Site icon R-bloggers

Automating roxygen2 package documentation

[This article was first published on Jonathan Sidi's R Blog, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Take the mystery out of CRAN level package maintenance –

Thinking of creating a new package? Dread the task of function documentation? Afraid to run devtools::check(build_args = '--as-cran') and get bombarded by Errors, Warnings, and Notes (oh my!) ? Wait…. breathe!

After feeling all that anxiety and following all of Hadley’s directions online, I felt I was doing a lot of manual labour, and that a package should be doing all lot of this for me. So we wrote one – sinew (sin-yu).

tl;dr: sinew is an automatic roxygen2 documentation creator

Quick example, run it in R:

 install.packages("sinew") # or devtools::install_github('metrumresearchgroup/sinew')
 
 # simple function
 
 myFun <- function(h=1){
   utils::head(rnorm(10),h)
 }
 
 library(sinew)
 makeOxygen(myFun)

This will produce the following output (which you can then append above your definition of myFun):

makeOxygen(myFun)

#' @title FUNCTION_TITLE
#' @description FUNCTION_DESCRIPTION
#' @param h PARAM_DESCRIPTION, Default: 1
#' @return OUTPUT_DESCRIPTION
#' @details DETAILS
#' @examples 
#' \dontrun{
#' if(interactive()){
#'  #EXAMPLE1
#'  }
#' }
#' @seealso 
#'  \code{\link[utils]{head}}
#' @rdname myFun
#' @export 
#' @importFrom utils head
myFun <- function(h=1){
  utils::head(h)
}

or document functions interactively with the shiny gadget:

For more details read the rest of the post, or skip straight to the gitbook: https://metrumresearchgroup.github.io/sinew/.

Why sinew?

Let me explain by example…

The current way to start down the documentation path is to create a function, I’ll use myFun defined above. Next I would use the skeleton provided by RStudio (In the toolbar Code=>Insert Roxygen Skeleton).

#' Title
#'
#' @param h 
#'
#' @return
#' @export
#'
#' @examples
myFun <- function(h=1){
  utils::head(h)
}

This gets me on my way, but there is information nested within the function itself that can be useful to document and manage the namespace

I could just add that manually but this is just a toy example, actual functions have many parameters and you can import many functions from a number of different packages.

Trying to do the documentation bookkeeping as you develop the function will make you lose your train of thought, and make you forget that great idea you just had. Or you could write the full function and then at the end try to figure out what functions you need to import what packages they are from, should they get a seealso field, what parameters you used and so on…

Sinew will do this for you. It will parse your full function for relevant information that can fill in the blanks in the roxygen2 documentation and manage your import fields for you. Think of it as connecting the meat of your function to the Roxygen2 skeleton – or just the definition of the term sinew (again sin-yu). Added bonus it will help keep your package CRAN ready as you develop.

So how would that skeleton look after running it with sinew?

The workhorse of sinew is makeOxygen, it takes functions and returns Roxygen2 headers.

makeOxygen(myFun)

#' @title FUNCTION_TITLE
#' @description FUNCTION_DESCRIPTION
#' @param h PARAM_DESCRIPTION, Default: 1
#' @return OUTPUT_DESCRIPTION
#' @details DETAILS
#' @examples 
#' \dontrun{
#' if(interactive()){
#'  #EXAMPLE1
#'  }
#' }
#' @seealso 
#'  \code{\link[utils]{head}}
#' @rdname myFun
#' @export 
#' @importFrom utils head
myFun <- function(h=1){
  utils::head(h)
}

That little function had a lot of information embbeded in it to make your documentation well rounded.

Now lets take a real function – lm

makeOxygen(lm)

#' @title FUNCTION_TITLE
#' @description FUNCTION_DESCRIPTION
#' @param formula PARAM_DESCRIPTION
#' @param data PARAM_DESCRIPTION
#' @param subset PARAM_DESCRIPTION
#' @param weights PARAM_DESCRIPTION
#' @param na.action PARAM_DESCRIPTION
#' @param method PARAM_DESCRIPTION, Default: 'qr'
#' @param model PARAM_DESCRIPTION, Default: TRUE
#' @param x PARAM_DESCRIPTION, Default: FALSE
#' @param y PARAM_DESCRIPTION, Default: FALSE
#' @param qr PARAM_DESCRIPTION, Default: TRUE
#' @param singular.ok PARAM_DESCRIPTION, Default: TRUE
#' @param contrasts PARAM_DESCRIPTION, Default: NULL
#' @param offset PARAM_DESCRIPTION
#' @param ... PARAM_DESCRIPTION
#' @return OUTPUT_DESCRIPTION
#' @details DETAILS
#' @examples 
#' \dontrun{
#' if(interactive()){
#'  #EXAMPLE1
#'  }
#' }
#' @seealso 
#'  \code{\link[stats]{model.frame}}
#' @rdname lm
#' @export 
#' @importFrom stats model.frame
lm

That would of been a pain to do by hand, all that is left to do is replace the placeholders with relevant information and you’re done. Also notice the layout is consistent so other people (and you) can easily navigate the help across the package functions.

A few features and use cases:

Interactive Documentation

A Shiny gadget was built to combine all this into an easy to use interface. Highlight text (preferably a function) in source editor of RStudio and then deploy the addin from the addins menu.

The gadget can read in almost any source you have the function in: unsourced functions, functions in the global environment, in a loaded package, in an installed package that you didn’t load yet.

The gadget will allow you to preview the roxygen header, add and remove roxygen2 fields with checkboxes and control the level of cut. When you’re ready insert what you see in the preview pane into the editor. When you’re done with one function highlight another one and continue to work, if you need to move to another file tab… that’s ok too!

If there is already documentation move into update mode, and touch up any changes that need to be made through moga.

To leave a comment for the author, please follow the link and comment on their blog: Jonathan Sidi's R Blog.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.