How do I insert a new function into my R package? - r

I made a package in R using these instructions. I use RStudio and I'd like to add a new function to the package.
Do I just put the functions into an R script and drag it into the folder in the package called R? If I do that, do I need to change the contents of the folder named man?

Say you have written a new function called my_function
my_function <- function(){
print("New function!")
}
You need to document it in the same R file. So your complete R file would look something like this
#' my_function
#'
#' A function to print the words "New function!"
#'
#' #return A character vector
#' #export
#'
#' #examples
#' my_function()
my_function <- function(){
print("New function!")
}
Now save this file in your R/ directory in the package
Run devtools::document() and that will update your man/ directory.
You have now added a new function to your package
In my opinion, the book R Packages is the best guide. You can read it for free at that link

Related

R-package development: Documenting and exporting functions with non-syntactic names

I'm writing a package (called pac) where I have a function with a non-syntactic name (called +f). I'm unable to correctly document and export this function.
Here's a reproducible example:
library(devtools)
setwd("~/yourpath")
create("pac")
Save the following function definition along with its documentation in pac/R/+f.R
#' Add two objects
#'
#' #name `+f`
#'
#' #param x an object
#' #param y an object
#' #return A sum
#' #export
`+f`<- function(x, y) {x + y}
Then run
document()
load_all()
`+f`(2, 2)
Which produces the output
> document()
Updating pac documentation
Loading pac
Writing NAMESPACE
Writing tick-plus-f-tick.Rd
> load_all()
Loading pac
Warning message:
In setup_ns_exports(path, export_all, export_imports) :
Objects listed as exports, but not present in namespace: +f
> `+f`(2, 2)
Error in `+f`(2, 2) : could not find function "+f"
As you can see, the function `+f` is not exported correctly, even though the NAMESPACE-file does have the following line:
export(`+f`)
On the other hand, since the documentation file pac/man/tick-plus-f-tick.Rd exists, I am able to display it by calling ?"`+f`".
How can I define and document a function with a non-syntactic name in a package? What's going on in the above example? Why isn't the function available when pac is loaded, even though the NAMESPACE-file includes an export-statement?

R package creation function names and .R/.rd name

Does the name of the .R and .rd files (documentation) need to have the exact same name as the function it refers to?
For example, can I have a function called "b" and another one called "B" within the same R package and write the documentation into different .R and .rd files?
I'm a bit confused and I wasn't able to find someone encountering the same problem (I even looked it up on DataCamp's course), so thanks in advance.
Best regards!
As the .R file can contain many functions, it doesn't need to have the same exact name as the function(s) it refers to.
Regarding the .Rd files, it's much easier/efficient/practical to let Roxygen turn specially formatted comments into .Rd files.
On Windows (files not case sensitive) avoid to use Upper case / lower case to distinguish functions, because the .Rd file of one of the functions will be overwritten:
Updating package documentation
Loading package
Writing NAMESPACE
Writing FOO.Rd
Writing foo.Rd
#' foo
#'
#' A function to print bar
#'
#' #param bar
#'
#' #return prints input
#' #export
#'
#' #examples
#' foo(1)
#'
foo <- function(bar) { print(bar) }
#' FOO
#'
#' Another function to print bar
#'
#' #param bar
#'
#' #return prints input
#' #export
#'
#' #examples
#' foo(1)
#'
FOO <- function(bar) { print(bar) }
?foo

Include external R script in roxygen2 documentation

When developing packages, I often have R scripts stored in the inst directory that produce data objects then included in the package, i.e. stored as someObj.rda in the data directory.
These objects, in turn, have R scripts with roxygen2 headers for documentation (e.g. someObj.R).
Ideally, I would like to include a line in the roxygen2 header that sources and formats the script as code, OUTSIDE of examples. Yes, I could copy the lines in, but in the DRY principle, it would be nice to have the documentation include the code automatically.
I have tried the following with no success:
rdScript <- function(x) {
lns <- readLines(x)
lns <- sprintf("#' \\code{%s}", lns)
cat(lns, sep = "\n")
}
#' #name someObj
#' #title Some R Bbject
#' #description Some R Object
#' #details
#' Data created with the following script:
#' #eval rdScript("inst/createCrimeData.R")
#'
NULL
And this:
rdScript <- function(x) {
lns <- readLines(x)
lns <- sprintf("\\code{%s}", lns)
lns
}
#' #name someObj
#' #title Some R Bbject
#' #description Some R Object
#' #details
#' Data created with the following script:
#' #eval rdScript("inst/createCrimeData.R")
#'
NULL
Edit in response to arguments against placing these scripts in the inst
While this was not the intention of this question, I would like to make the argument for inst being the ideal place for these scripts. This situation comes up for me personally when producing not general-use R packages, but R packages to accompany manuscripts and reproduce analyses. R packages provide an ideal format for disseminating fully-reproducible analyses. However, often analyses include large datasets that are not needed in entirety. By including a script in inst, users can choose (easily) to reproduce the data included in the package BUT are not required recreate the input data for the analysis. It does not make sense to obscure the scripts away.
First, I would agree with Hong Ooi and say that in general you shouldn't put it in inst/; that is copied into the user's installation. I follow the advice in Hadley Wickham's R Packages and put them in a folder called data-raw/ (which you then add to .Rbuildignore). However, for the use case you further describe in the edits to your question, I can see why you would want to put the script in inst/ to distribute to your users.
But, on to the problem at hand. You can do this by instead using #evalRd and adding the \details{} part in rdScript(). I set up a dummy package foo with the file inst/bar.R with the following code in it:
a <- 5
b <- 8
Then I made R/baz.R with
rdScript <- function(filename, prepend = "") {
lns <- readLines(filename)
lns <- paste(sprintf("\\code{%s}", lns), collapse = "\n\n")
return(paste("\\details{", prepend, "\n", lns, "}", sep = "\n"))
}
#' #name someObj
#' #title Some R Object
#' #description Some R Object
#'
#' #evalRd rdScript("inst/bar.R", "Data was created with the following script:")
NULL
After document()ing, I get the following in man/someObj.Rd:
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/baz.R
\name{someObj}
\alias{someObj}
\title{Some R Object}
\description{
Some R Object
}
\details{
Data was created with the following script:
\code{a <- 5}
\code{b <- 8}
}
which renders in RStudio's help viewer as

Export error on overwriting primitives with S3 in R package

I'm trying to create a S3 method in my package called dimnames. This is a primitive in R, but there should be an S3 in my package with the same name.
I've got the following file dimnames.r
#' S3 overwriting primitive
#'
#' #param x object
#' #export
dimnames = function(x) {
UseMethod("dimnames")
}
#' title
#'
#' #export
dimnames.data.frame = function(x) {
dimnames.default(x)
}
#' title
#'
#' #export
dimnames.list = function(x) {
lapply(x, dimnames)
}
#' title
#'
#' #export
dimnames.default = function(x) {
message("in S3 method")
base::dimnames(x)
}
I then create a package from it (in R=3.3.2):
> package.skeleton("rpkg", code_files="dimnames.r")
> setwd("rpkg")
> devtools::document() # version 1.12.0
And then check the package
R CMD build rpkg
R CMD check rpkg_1.0.tar.gz
I get the following output (among other messages):
Warning: declared S3 method 'dimnames.default' not found
Warning: declared S3 method 'dimnames.list' not found
Loading the package and checking its contents, dimnames.data.frame is exported while dimnames.default and dimnames.list are not. This does not make sense to me. As far as I understand, I declared the exports correctly. Also, the NAMESPACE file looks good to me:
S3method(dimnames,data.frame)
S3method(dimnames,default)
S3method(dimnames,list)
export(dimnames)
Why does this not work, and how to fix it?
(Bonus points for: why do I need #' title in the S3 implementations when they should not be needed with roxygen=5.0.1?)
S3 methods are only exported if it is desired that the user be able to access them directly. If they are always to be invoked via the generic then there is no need to export them.
The problem with R CMD check is likely due to defining your own generic for dimnames. Normally one just defines methods and leverages off the primitive generic already in R. Remove the dimnames generic from dimnames.r.
There should be no problem in adding methods for new classes but you may have problems trying to override the functionality of dimnames for existing classes that R's dimnames handles itself.

devtools roxygen package creation and rd documentation

I am new to roxygen and am struggling to see how to be able to use it to quickly create a new/custom package.
I.e. I would like to know the minimum requirements are to make a package called package1 using devtools, roxygen2/3 so that I can run the commands
require(package1)
fun1(20)
fun2(20)
to generate 2000 and 4000 random normals respectively
So lets take the simplest example.
If I have two functions fun1 and fun2
fun1 <- function(x){
rnorm(100*x)
}
and
fun2 <- function(y){
rnorm(200*y)
}
the params are numeric, the return values are numeric. I'm pretty sure this isn't an S3 method, lets call the titles fun1 and fun2....im not too sure what other info i would need to provide. I can put fun1 and fun2 in separate .R files and add abit of #' but am unsure to include all relevant requirements for roxygen and also am unsure what to include as relevant requiremetns and how to use it to create the rd documentation to go with a package are. I presume the namespace would just have the names fun1 and fun2? and the package description would just be some generic information relating to me...and the function of the package?
any step by step guides would be gladly received.
EDIT: The below is how far I got to start with...
I can get as far as the following to create a pacakge...but cant use roxygen to make the documentation...
package.skeleton(list = c("fun1","fun2"), name = "package1")
and here is where I am not sure if I am missing a bunch of steps or not...
roxygenise("package1")
so when trying to install i get the following error message
system("R CMD INSTALL package1")
* installing to library ‘/Library/Frameworks/R.framework/Versions/2.15/Resources/library’
* installing *source* package ‘package1’ ...
** R
** preparing package for lazy loading
** help
Warning: /path.to.package/package1/man/package1-package.Rd:32: All text must be in a section
*** installing help indices
Error in Rd_info(db[[i]]) :
missing/empty \title field in '/path.to.package/package1/man/fun1.Rd'
Rd files must have a non-empty \title.
See chapter 'Writing R documentation' in manual 'Writing R Extensions'.
* removing ‘/Library/Frameworks/R.framework/Versions/2.15/Resources/library/package1’
I'm surprised #hadley says to not use package.skeleton in his comment. I would use package.skeleton, add roxygen comment blocks, then delete all the files in the "man" directory and run roxygenize. However, since Hadley says "Noooooooooo", here's the minimum you need to be able to build a package that passes R CMD check and exports your functions.
Create directory called "package1". Under that directory, create a file called DESCRIPTION and put this in it (edit it appropriately if you like):
DESCRIPTION
Package: package1
Type: Package
Title: What the package does (short line)
Version: 0.0.1
Date: 2012-11-12
Author: Who wrote it
Maintainer: Who to complain to <yourfault#somewhere.net>
Description: More about what it does (maybe more than one line)
License: GPL
Now create a directory called "R" and add a file for each function (or, you can put both of your functions in the same file if you want). I created 2 files: fun1.R and fun2.R
fun1.R
#' fun1
#' #param x numeric
#' #export
fun1 <- function(x){
rnorm(100*x)
}
fun2.R
#' fun2
#' #param y numeric
#' #export
fun2 <- function(y){
rnorm(200*y)
}
Now you can roxygenize your package
R> library(roxygen2)
Loading required package: digest
R> list.files()
[1] "package1"
R> roxygenize("package1")
Updating collate directive in /home/garrett/tmp/package1/DESCRIPTION
Updating namespace directives
Writing fun1.Rd
Writing fun2.Rd
Since you mentioned devtools in the title of your Q, you could use the build and install functions from devtools
build('package1')
install('package1')
Or you can exit R and use the tools that come with R to build/check/install.
$ R CMD build package1
$ R CMD check package1_0.0.1.tar.gz
$ R CMD INSTALL package1_0.0.1.tar.gz
Now, fire up R again to use your new package.
$ R --vanilla -q
library(package1)
fun1(20)
fun2(20)
But, figuring out the minimum requirements is unlikely to help you (or the users of your package) much. You'd be much better off studying one of the many, many packages that use roxgen2.
Here's a better version of the fun1.R file which still doesn't use all the roxygen tags that it could, but is much better than the bare minimum
Modified fun1.R
#' fun1
#'
#' This is the Description section
#'
#' This is the Details section
#'
#' #param x numeric. this is multiplied by 100 to determine the length of the returned vector
#' #return a numeric vector of random deviates of length \code{100 * x}
#' #author your name
#' #seealso \code{\link{fun2}}
#' #examples
#' fun1(2)
#' length(fun1(20))
#' #export
fun1 <- function(x){
rnorm(100*x)
}
Much later - You could let RoxygenReady prepare your functions with the minimal Roxygen annotation skeleton. It basically brings you from your 2 input functions to GSee's answer, which is the input of Roxygen2.

Resources