Home » Uncategorized » Developing R packages using roxygen and devtools

Developing R packages using roxygen and devtools

I feel like I’ve arrived late to a party. Idly googling, I discovered roxygen2, a “Doxygen-like in-source documentation system for Rd, collation, and NAMESPACE”. With roxygen2, you can use the functions in devtools to automate lots of the painful parts of writing/updating/testing packages. To convert existing packages to roxygen format, there’s Rd2roxygen .

A common denominator to all these is Hadley Wickham, who is quickly becoming my R hero.

So, how does this work? I decided to take an existing package of mine that needed a little update, and have a go.

After backing up my package directory, I begain by roxygenize-ing an existing package

library(devtools)
library(Rd2roxygen)
options(roxygen.comment = "##' ") ## allow ESS style comments
Rd2roxygen("snpStatsWriter")
##------ Mon Jan 28 13:59:25 2013 ------##
parsed: snpStatsWriter-package.Rd
unmatched object 'snpStatsWriter-package' written into snpStatsWriter/R/snpStatsWriter-package.R


##------ Mon Jan 28 13:59:25 2013 ------##
parsed: write.simple.Rd
looking for the object 'write.simple' in:
  snpStatsWriter-package.R: not found
  write.R: line 21
snpStatsWriter/R/write.R updated

Then I checked around in the files, played with my documentation a little (easy to do with it being right next to the functions). One function now looks like

##' Write a snpStats object in PHASE/FastPHASE format
##'
##' see \code{\link{write.simple}} for general information
##' 
##' @inheritParams write.simple
##' @param pedfile Output file name. 
##'@param trait disease trait (0=missing, 1=control, 2=case)
##'@param gfile,mfile \code{gfile}=genotype file, \code{pedfile}=pedigree file
##' 
##' @return No return value, but has the side effect of writing specified output
##' files.
##' @author Chris Wallace
##'@keywords manip
##'@examples
##'
##'data(testdata,package="snpStats")
##'A.small <- Autosomes[1:6,1:10]
##'f <- tempfile()
##'
##'## write in suitable format for PHASE
##'nsnps <- ncol(A.small)
##'write.phase(A.small, file=f)
##'unlink(f)
##'
write.phase <- function(X,a1=rep(1,ncol(X)),a2=rep(2,ncol(X)),bp=NULL,file) {
  check.args(X,a1,a2)
  if(!is.null(bp) && length(bp)!=ncol(X))
    stop("require ncol(X) == length(bp)")
  res <- .C("write_phase", X@.Data, as.character(a1), as.character(a2),
            as.character(file), as.integer(nrow(X)),
            as.integer(ncol(X)), rownames(X), colnames(X),
            as.integer(!is.null(bp)), as.integer(bp), get.eol())
  return(c(nrow(X), ncol(X)))
}

The @inheritParams flag is great, because it means I only need document common arguments once (in write.simple) and devtools will know to copy it as appropriate. I had documented everything before in a single file with aliases, because I was too lazy to write multiple .Rd files. Now, I’ve used cut and paste and the @inheritParams flag to document each function individually.

Now, to use devtools to build, document and test the package. First, load from the .R files:

> load_all("snpStatsWriter")
Loading snpStatsWriter
Re-compiling snpStatsWriter
'/usr/lib/R/bin/R' --vanilla CMD INSTALL  \
  '/home/chrisw/local/R/packages/snpStatsWriter' --library='/tmp/RtmpWxyxLf'  \
  --no-R --no-data --no-help --no-demo --no-inst --no-docs --no-multiarch  \
  --no-test-load 

* installing *source* package 'snpStatsWriter' ...
** libs
gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG      -fpic  -O3 -pipe  -g  -c writers.c -o writers.o
gcc -std=gnu99 -shared -o snpStatsWriter.so writers.o -L/usr/lib/R/lib -lR
installing to /tmp/RtmpWxyxLf/snpStatsWriter/libs

* DONE (snpStatsWriter)
Loading required namespace: snpStats
Loading required package: snpStats
Loading required package: survival
Loading required package: splines
Loading required package: Matrix
Loading required package: lattice

Then, write .Rd files

> document("snpStatsWriter")
Loading required package: roxygen2
Loading required package: digest
Updating snpStatsWriter documentation
Loading snpStatsWriter
Updating collate directive in  /home/chrisw/local/R/packages/snpStatsWriter/DESCRIPTION 
Updating namespace directives
Writing snpStatsWriter-package.Rd
Writing write.simple.Rd
Writing write.mach.Rd
Writing write.impute.Rd
Writing write.beagle.Rd
Writing write.phase.Rd

and check

> check_doc("snpStatsWriter")
prepare_Rd: write.simple.Rd:75: unknown macro '\n'
prepare_Rd: write.simple.Rd:77: unknown macro '\r'
prepare_Rd: write.simple.Rd:77: unknown macro '\n'
NULL
Documented arguments not in \usage in documentation object 'write.beagle':
  ‘pedfile’

Documented arguments not in \usage in documentation object 'write.phase':
  ‘pedfile’ ‘trait’ ‘gfile’ ‘mfile’

Documented arguments not in \usage in documentation object 'write.simple':
  ‘snp.id’

OK… a little editting and rerunning of the last two steps needed till I got

> check_doc("snpStatsWriter")
NULL

Then do the full check

> check("snpStatsWriter")
Updating snpStatsWriter documentation
Loading snpStatsWriter
'/usr/lib/R/bin/R' --vanilla CMD build  \
  '/home/chrisw/local/R/packages/snpStatsWriter' --no-manual --no-resave-data 

* checking for file '/home/chrisw/local/R/packages/snpStatsWriter/DESCRIPTION' ... OK

...

There were two errors. First, my functions, even though they were exported in the old NAMESPACE file, did not carry the @export tag after Rd2roxygen(), so I had to manually add the line

#' @export

above each function I wanted exported. Second, after doing this, the useDynLib() from NAMESPACE disappeared, and I had to add the line

#' @useDynLib snpStatsWriter

to R/snpStatsWriter-package.R

To reload, I had to do

> load_all("snpStatsWriter",TRUE)
> document("snpStatsWriter")
> check("snpStatsWriter")

till I got the all clear. Finally I built and submitted my package to CRAN using

build("snpStatsWriter")
release("snpStatsWriter")

and this function even wrote the email!

So, that took less than an hour to learn (ish) three new packages, and release a package. I still want to learn testthat though, so I can feel virtuous for doing more testing than simply running example code.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s