Specify output directory for R package generation - r

I am trying to automize the procedure of package generation but seem to be unable to tell R where to save the newly generated package.
Here a more detailed explanation of my problem:
First I write a function (or multiple functions) and save it as a separate file in a source directory ("C:/Users/Raphael/Documents/Stats/R/Package_Forge/testpack_SourceFiles") that will be used to generate the package. For illustration purposes, I am using the following test function (file: testpack_test.R). As you can see I am using Hadley Wickham’s roxygen package.
#' #rdname f.test
#' #title Test function
#' #description This function squares a given number.
#' #param x Number
#' #return The function returns a number
#' #export
#'
f.test=function(x){
x=x^2
return(x)
}
Then I use the following script to generate the package, which in this example contains only one function (f.test):
#######################
#*** Load packages ***#
#######################
# Set library path
.libPaths("C:/Users/Raphael/Documents/Stats/R/Package_Use")
#install.packages("roxygen2")
library(digest)
library(roxygen2)
###################
#*** Set paths ***#
###################
# Define Path
pkForge="C:/Users/Raphael/Documents/Stats/R/Package_Forge"
pkUse="C:/Users/Raphael/Documents/Stats/R/Package_Use"
newPk=file.path(pkForge,"testpack")
newPkS=file.path(pkForge,"testpack_SourceFiles")
newPkR=file.path(newPk,"R") #"R" folder that will contain functions
newPkD=file.path(newPk,"DESCRIPTION") #Description file
############################################
#*** Generate directories and add files ***#
############################################
# Generate main directory of new package
if(file.exists(newPk)){
cat("\nExisting directory deleted!")
unlink(newPk,recursive=T) #deletes old directory
cat("\nNew directory generated!\n",newPk)
dir.create(newPk)
}else{
cat("\nNew directory generated!\n",newPk)
dir.create(newPk)
}
# Generate "R" sub directory of new package
dir.create(newPkR)
# Add all scripts in the source directory to "R" sub directory
# Note: roxygen code should be used for function annotation
allScripts=list.files(newPkS,"^testpack_.*?\\.R$", full.names=T, ignore.case=T) #uses regex to only select certain files; returns the entire path
file.copy(allScripts, newPkR)
# Generate a new description file in the package main directory
fileConn=file(newPkD,open="w")
writeLines(c("Package: testpack",
"Type: Package",
"Title: Test package",
"Version: 1.0",
"Date: 2013-08-04",
"Author: XYZ",
"Maintainer: XYZ <xyz#gmail.com>",
"Description: This package contains one test function",
"License:GPL-2"),fileConn)
close(fileConn)
# file.show(newPkD) #shows the content of new file
############################
#*** Roxygenize package ***#
############################
# list.files(MyPackages)
roxygenize(newPk)
#######################
#*** Build package ***#
#######################
cmd=paste("R CMD build ", shQuote(newPk)," --no-manual --no-resave-data", sep="")
system(cmd) #using a system call to build the package
This last system call builds the source package correctly. However, the problem is that for some reasons the “tarball” (testpack_1.0.tar.gz) is always saved to C:/Users/Raphael/Documents and I seem to be unable to specify an output directory. I would like to have the tarball saved directly to the pkUse directory ("C:/Users/Raphael/Documents/Stats/R/Package_Use"), which is the folder that I use for all my installed libraries. I tried to add the pkUse directory at various places in the “cmd” string ("R CMD build \"C:/Users/Raphael/Documents/Stats/R/Package_Forge/testpack\" --no-manual --no-resave-data") but it always gives an error. Does anyone have an idea of how to specify the output directory in the above system call? I know that the devtools package is able to do this but would like to be able to use the system call. Thanks so much for any suggestions!
Best,
Raphael

The tarball is being saved to the working directory, so you could setwd() before your system call, then set it back afterwards.

Can you use sink?
sink(x) will write the output to the directory and file format that you need.

Related

What's the most simple approach to name-spacing R files with `file::function`

Criteria for answer to this question
Given the following function (within its own script)
# something.R
hello <- function(x){
paste0("hello ", x)
}
What is the most minimal amount of setup which will enable the following
library(something)
x <- something::hello('Sue')
# x now has value: "hello Sue"
Context
In python it's very simple to have a directory containing some code, and utilise it as
# here foo is a directory
from foo import bar
bar( ... )
I'm not sure how to do something similar in R though.
I'm aware there's source(file.R), but this puts everything into the global namespace. I'm also aware that there's library(package) which provides package::function. What I'm not sure about is whether there's a simple approach to using this namespacing within R. The packaging tutorials that I've searched for seem to be quite involved (in comparison to Python).
I don't know if there is a real benefit in creating a namespace just for one quick function. It is just not the way it is supposed to be (I think).
But anyway here is a rather minimalistic solution:
First install once: install.packages("namespace")
The function you wanted to call in the namespace:
hello <- function(x){
paste0("hello ", x)
}
Creating your namespace, assigning the function and exporting
ns <- namespace::makeNamespace("newspace")
assign("hello",hello ,env = ns)
base::namespaceExport(ns, ls(ns))
Now you can call your function with your new namespace
newspace::hello("you")
Here's the quickest workflow I know to produce a package, using RStudio. The default package already contains a hello function, that I overwrote with your code.
Notice there was also a box "create package based on source files", which I didn't use but you might.
A package done this way will contain exported undocumented untested functions.
If you want to learn how to document, export or not, write tests and run checks, include other objects than functions, include compiled code, share on github, share on CRAN.. This book describes the workflow used by thousands of users, and is designed so you can usually read sections independently.
If you don't want to do it from GUI you can useutils::package.skeleton() to build a package folder, and remotes::install_local() to install it :
Reproducible setup
# create a file containing function definition
# where your current function is located
function_path <- tempfile(fileext = ".R")
cat('
hello <- function(x){
paste0("hello ", x)
}
', file = function_path)
# where you store your package code
package_path <- tempdir()
Solution :
# create package directory at given location
package.skeleton("something", code_file = file_path, path = package_path)
# remove sample doc to make remotes::install_local happy
unlink(file.path(package_path, "something", "man/"), TRUE)
# install package
remotes::install_local(file.path(package_path, "something"))

'data' is not an exported object from 'namespace:my_package'

I'm writing a function that uses an external data as follow:
First, it checks if the data is in the data/ folder, if it is not, it creates the data/ folder and then downloads the file from github;
If the data is already in the data/ folder, it reads it, and perform the calculations.
The question is, when I run:
devtools::check()
it returns:
Error: 'data' is not an exported object from 'namespace:my_package'
Should I manually put something on NAMESPACE?
An example:
my_function <- function(x){
if(file.exists("data/data.csv")){
my_function_calculation(x = x)
} else {
print("Downloading source data...")
require(RCurl)
url_base <-
getURL("https://raw.githubusercontent.com/my_repository/data.csv")
dir.create(paste0(getwd(),"/data"))
write.table(url_base,"data/data.csv", sep = ",", quote = FALSE)
my_function_calculation(x = x)
}
}
my_function_calculation <- function(x = x){
data <- NULL
data <- suppressMessages(fread("data/data.csv"))
#Here, I use data...
return(data)
}
It could not be the same in every case, but I've solved the problem by removing the data.R file on R/ folder.
data.R is a file describing all data presented in the package. I had it since the previous version of my code, that had the data built in, not remote (to be downloaded).
Removing the file solved my problem.
Example of data.R:
#' Name_of_the_data
#'
#' Description_of_the_Data
#'
#' #format A data frame with 10000 rows and 2 variables:
#' \describe{
#' \item{Col1}{description of Col1}
#' \item{Col2}{description of Col2}
#' }
"data_name"
No need to remove data.R in /R folder, you just need to decorate the documentation around the NULL keyword as follow:
#' Name_of_the_data
#'
#' Description_of_the_Data
#'
#' #format A data frame with 10000 rows and 2 variables:
#' \describe{
#' \item{Col1}{description of Col1}
#' \item{Col2}{description of Col2}
#' }
NULL
Generally, this happens when you have a mismatch between the names of one of the rda files in data folder and what is described in R/data.R.
In this case, the data reference in the error message is for data.csv, not the data folder. You need to have rda files in the data folder of a R package. If you want to download csv, you need to put them in inst/extdata.
This being said, you might want to consider using tempdir() to save those files in the temp folder of your session instead.
There's 3 things to check:
The documentation is appropriately named:
#' Name_of_the_data
#'
#' Description_of_the_Data
#'
#' #format A data frame with 10000 rows and 2 variables:
#' \describe{
#' \item{Col1}{description of Col1}
#' \item{Col2}{description of Col2}
#' }
data
That the RData file is appropriately named for export in the data/ folder.
That the RData file is loaded with the name data.
If documentation (1) is A, the Rdata file is A.RData (2), but the object (when loaded with load() ) is named B- you're going to get this error exactly.
The problem probably is because how your object was named when you save it.
Suppose I load a file a called it "d", then I save it (as is suggested) with save in the data/ directory as "data":
save(d, file = "data/data.rda")
Then you will run the clean and install package and you will get the following error:
Error: 'data' is not an exported object from 'namespace:YourPakage'
Looks like it does not matter how you declare your object in the roxygen documentation. I guess you must name your OBJECT with the same name you are going to save it and loaded it.
For example, load your dataset as "pib" object, then save as "pib.rda" and declare in roxygen "loadData.R" (for example) your "pib".
#' Datos del PIB
#'
#' #docType data
#'
#' #usage data(pib)
#'
#' #format An object of class ...
#'
#' #keywords datasets
#'
#' #references ----
#'
#' #source ----
#'
#' #examples
#' data(pib)
"pib"
I had this issue because I copied the .rda file into the R\data folder.
Issue was resolved by using usethis::use_data(DataObject) which automatically takes the raw-data (DataObject) file and adds it to the R\data folder within the R package directory.
When I was stumped by the error
Error: 'data' is not an exported object from 'namespace:my_package'
MrFlick's comment above saved me. I had simply changed the name of an .rda file in my data folder. I was unable to get devtools::document() to recreate the NAMESPACE file. The solution was to re-save the data into the .rda file. (Of course I should have remembered that when one loads from an .rda file the name of the R object(s) has nothing to do with the name of the .rda file so renaming the .rda file doesn't do much.)
I spent a few hours trying to fix this. Finally got it to work.
Notes:
Data files have to be of type "rda". "rds" won't work.
File names had to be lower case.
NULL in documentation name didn't work for me. Had to be a lower case string.
In general, it seems the same error message is caused by several things. Anything the checker doesn't like related to data files, it will issue the same error. Hard to debug under those circumstances.
I will add another trap. Working in RStudio
I have assigned a string to MyString and saved in the data folder of my package project:
save(MyString, file="./data/MyString.RData")
My ./R/data.R file contains documentation for this:
#' A character string
#'
"MyString"
This works. But you must use one file per object and not do save(X, Y, Z, file="BitsAndPieces.RData") and then document BitsAndPieces. If you do then you will get the error of this question. Which I did, needless to say.
I had the same error and I would be able to overcome the error as follows.
The data file located at: data/df.RData
The R documentation file located at: R/df.R
I have created the df.RData file by importing the df.txt file into R and using the save() function to create the .RData file. I used the following code block to create .RData file.
x=read.table("df.txt")
save(x,file="df.RData")
Then after running the RCMD check I get the same error as df is not an exported object from namespace "package name".
I have overcome the error by change the variable name of the df.RData file as
df=read.table("df.txt")
save(df,file="df.RData")
Restarting the session solved the problem for me. Somehow the environment was empty and after restart all objects were back, hence solving the diff.
I had the same issue with one of my packages, and I needed to add
LazyData: true
to my DESCRIPTION file.
I had this problem, even renaming the variables and uninstalling the probematic packages didn't work.
I did:
I was trying to carry out the process in a session (tab) of R that was already in use previously, where the terra package had already been requested. This session is not saved, but was being automatically saved to an image in ~/.RData every time Rstudio was closed. So every time I opened Rstudio it retrieved that section (image) and reloaded the previous state causing the conflict between packages.
I solved it by creating a new blank rmarkdown and closing all previously opened sessions, as well as clearing all saved data in the Rstudio "Global environment".
I encountered this "Error: 'weekly' is not an exported object from 'namespace:ISLR'' when I was trying the following:
library(ISLR)
w <- ISLR::weekly
The problem is somehow fixed by changing it to:
w = ISLR::weekly
The = sign made all the difference here.

RUnit: could not find function "checkEquals"

I am creating an R package with the standard directory hierarchy. Inside the R directory, I create a test subdirectory.
In the R directory, I create a uTest.R file containing:
uTest <- function() {
test.suite <- defineTestSuite('test',
dirs = file.path('R/test'))
test.result <- runTestSuite(test.suite)
printTextProtocol(test.result)
}
In the R/test directory, I create a runit.test.R file containing:
test.validDim <- function() {
testFile <- "test/mat.csv"
generateDummyData(testFile,
10,
10)
checkEquals(validDim(testFile), TRUE)
}
I build and install my package using R CMD INSTALL --no-multiarch --with-keep.source RMixtComp in Rstudio. When I try to launch the function uTest(), I get this error message:
1 Test Suite :
test - 1 test function, 1 error, 0 failures
ERROR in test.validDim: Error in func() : could not find function "checkEquals"
However, if I call library(RUnit) prior to calling uTest(), everything works fine. In the import field of the DESCRIPTION file, I added RUnit, and in the NAMESPACE file I added import(RUnit).
How can I call uTest() directly after loading my package, without manually loading RUnit ?
You should not add RUnit to the Depends (or Imports) field in the DESCRIPTION file (despite the comment to the contrary). Doing so implies that the RUnit package is necessary in order to use your package, which is likely not the case. In other words, putting RUnit in Depends or Imports implies RUnit needs to be installed (Imports) and on the users' search path (Depends) in order for them to use your package.
You should add RUnit to the Suggests field in the DESCRIPTION file, then modify your uTest function as below:
uTest <- function() {
stopifnot(requireNamespace("RUnit"))
test.suite <- RUnit::defineTestSuite('test', dirs = file.path('R/test'))
test.result <- RUnit::runTestSuite(test.suite)
RUnit::printTextProtocol(test.result)
}
Doing this allows you to use RUnit for your tests, but does not require users to have RUnit installed (and possibly on their search path) in order to use your package. Obviously, they'll need RUnit if they wish to run your tests.

Include example using data in documentation of that data (when developing R package)

In documentation of data within an R package (using Roxygen via Rstudio), is it possible to include an example that uses that data?
E.g. TestPackage.R in the R directory
#' My New Colour
#'
#' Enables use of my new colour \emph{aNewColour} in plots.
#' #name aNewColour
#' #docType data
#' #format A colour defined by rgb(red=232,green=81,blue=0,maxColorValue=255)
#' #usage data(allNewColours)
#' #examples
#' curve(dnorm,from=-4,to=4,col=aNewColour,lwd=2)
NULL
In the same R directory, I have a file: allNewColours.rda, which consists only of the variable aNewColour with value #E85100.
When I press Check on the Build menu of R studio (equivalent to the command R CMD Check I believe), I get the following error message:
** Examples
curve(dnorm,from=-4,to=4,col=aNewColour,lwd=2) Error in plot.xy(xy, type, ...) : object 'aNewColour' not found Calls: curve -> plot ->
plot.default -> plot.xy Execution halted Error: Command failed (1)
Execution halted
Exited with status 1.
Is it possible to use the data "aNewColour" in the example of the documentation of "aNewColour" ?
Edit: Okay I found my problem - If I move the .rda file to a data folder (at the same level as the R folder, all works)... Had been struggling with this for ages only to determine the solution within seconds of posting this question ...
move the .rda file to a data folder - and enter LazyData: yes in the DESCRIPTION file

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