Site icon R-bloggers

RStudio:addins part 2 – roxygen documentation formatting made easy

[This article was first published on Jozef's Rblog, 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.

Introduction

Code documentation is extremely important if you want to share the code with anyone else, future you included. In this second post in the RStudio:addins series we will pay a part of our technical debt from the previous article and document our R functions conveniently using a new addin we will build for this purpose.

The addin we will create in this article will let us create well formatted roxygen documentation easily by using keyboard shortcuts to add useful tags such as \code{} or \link{} around selected text in RStudio.

Contents

  1. Quick intro to documentation with roxygen2
    1. Documenting your first function
    2. Generating and viewing the documentation
    3. Real-life example
  2. Our addins to make documenting a breeze
    1. Add a selected tag around a character string
    2. Apply the tag on a selection in an active document in RStudio
    3. Wrappers around addRoxytag to be used as addin for some useful tags
    4. Add the addin bindings into addins.dcf and assign keyboard shortcuts
  3. The addins in action
  4. What is next – even more automated documentation
  5. TL;DR – Just give me the package
  6. References

Quick intro to documentation with roxygen2

1. Documenting your first function

To help us generate documentation easily we will be using the roxygen2 package. You can install it using install.packages("roxygen2"). Roxygen2 works with in-code tags and will generate R’s documentation format .Rd files, create a NAMESPACE, and manage the Collate field in DESCRIPTION (not relevant to us at this point) automatically for our package.

Documenting a function works in 2 simple steps:

Documenting a function

  1. Inserting a skeleton – Do this by placing your cursor anywhere in the function you want to document and click Code Tools -> Insert Roxygen Skeleton (default keyboard shortcut Ctrl+Shift+Alt+R).
  2. Populating the skeleton with relevant information. A few important tags are:
  • #' @params – describing the arguments of the function
  • #' @return – describing what the function returns
  • #' @importFrom package function – in case your function uses a function from a different package Roxygen will automatically add it to the NAMESPACE
  • #' @export – if case you want the function to be exported (mainly for use by other packages)
  • #' @examples – showing how to use the function in practice

2. Generating and viewing the documentation

Generating and viewing the documentation

  1. We generate the documentation files using roxygen2::roxygenise() or devtools::document() (default keyboard shortcut Ctrl+Shift+D)
  2. Re-installing the package (default keyboard shortcut Ctrl+Shift+B)
  3. Viewing the documentation for a function using ?functioname e.g. ?mean, or placing cursor on a function name and pressing F1 in RStudio – this will open the Viewer pane with the help for that function

3. A real-life example

Let us now document runCurrentRscript a little bit:

#' runCurrentRscript
#' @description Wrapper around executeCmd with default arguments for easy use as an RStudio addin
#' @param path character(1) string, specifying the path of the file to be used as Rscript argument (ideally a path to an R script)
#' @param outputFile character(1) string, specifying the name of the file, into which the output produced by running the Rscript will be written
#' @param suffix character(1) string, specifying additional suffix to pass to the command
#' @importFrom rstudioapi getActiveDocumentContext
#' @importFrom rstudioapi navigateToFile
#' @seealso executeCmd
#' @return side-effects
runCurrentRscript <- function(
  path = replaceTilde(rstudioapi::getActiveDocumentContext()[["path"]])
, outputFile = "output.txt"
, suffix = "2>&1") {
  cmd <- makeCmd(path, outputFile = outputFile, suffix = suffix)
  executeCmd(cmd)
  if (!is.null(outputFile) && file.exists(outputFile)) {
    rstudioapi::navigateToFile(outputFile)
  }
}

As we can see by looking at ?runCurrentRscript versus ?mean, our documentation does not quite look up to par with documentation for other functions:

What is missing if we abstract from the richness of the content is the usage of markup commands (tags) for formatting and linking our documentation. Some of the very useful such tags are for example:

  • \code{}, \strong{}, \emph{} for style
  • \link{}, \href{}, \url{} for linking to other parts of the documentation or external resources
  • \enumerate{}, \itemize{}, \tabular{} for using lists and tables
  • \eqn{}, \deqn{} for mathematical expressions such as equations etc.

For the full list of options regarding text formatting, linking and more see Writing R Extensions’ Rd format chapter

Our addins to make documenting a breeze

As you can imagine, typing the markup commands in full all the time is quite tedious. The goal of our new addin will therefore be to make this process efficient using keyboard shortcuts – just select a text and our addin will place the desired tags around it. For this time, we will be satisfied with simple 1 line tags.

1. Add a selected tag around a character string

roxyfy <- function(str, tag = NULL, splitLines = TRUE) {
  if (is.null(tag)) {
    return(str)
  }
  if (!isTRUE(splitLines)) {
    return(paste0("\\", tag, "{", str, "}"))
  }
  str <- unlist(strsplit(str, "\n"))
  str <- paste0("\\", tag, "{", str, "}")
  paste(str, collapse = "\n")
}

2. Apply the tag on a selection in an active document in RStudio

We will make the functionality available for multi-selections as well by lapply-ing over the selection elements retrieved from the active document in RStudio.

addRoxytag <- function(tag = NULL) {
  context <- rstudioapi::getActiveDocumentContext()
  lapply(X = context[["selection"]]
       , FUN = function(thisSel, contextid) {
           rstudioapi::modifyRange(location = thisSel[["range"]]
                                 , roxyfy(thisSel[["text"]], tag)
                                 , id = contextid)
         }
       , contextid = context[["id"]]
       )
  return(invisible(NULL))
}

3. Wrappers around addRoxytag to be used as addin for some useful tags

addRoxytagCode <- function() {
  addRoxytag(tag = "code")
}

addRoxytagLink <- function() {
  addRoxytag(tag = "link")
}

addRoxytagEqn <- function() {
  addRoxytag(tag = "eqn")
}

4. Add the addin bindings into addins.dcf and assign keyboard shortcuts

As the final step, we need to add the bindings for our new addins to the inst/rstudio/addins.dcf file and re-install the package.

Name: addRoxytagCode
Description: Adds roxgen tag code to current selections in the active RStudio document
Binding: addRoxytagCode
Interactive: false

Name: addRoxytagLink
Description: Adds roxgen tag link to current selections in the active RStudio document
Binding: addRoxytagLink
Interactive: false

Name: addRoxytagEqn
Description: Adds roxgen tag eqn to current selections in the active RStudio document
Binding: addRoxytagEqn
Interactive: false

assigning keyboard shortcuts to addins

The addins in action

And now, let’s just select the text we want to format and watch our addins do the work for us! Then document the package, re-install it and view the improved help for our functions:

The addins in action

What is next – even more automated documentation

Next time we will try to enrich our addins for generating documentation by adding the following functionalities

  • automatic generation of @importFrom tags by inspecting the function code
  • allowing for more complex tags such as itemize

TL;DR – Just give me the package

References

To leave a comment for the author, please follow the link and comment on their blog: Jozef's Rblog.

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.