RStudio:addins part 1 - code reproducibility testing

Introduction

This is the first post in the RStudio:addins series. The aim of the series is to walk the readers through creating an R package that will contain functionality for integrating useful addins into the RStudio IDE. At the end of this first article, your RStudio will be 1 useful addin richer.

The addin we will create in this article will let us run a script open in RStudio in R vanilla mode via a keyboard shortcut and open a file with the script’s output in RStudio.

This is useful for testing whether your script is reproducible by users that do not have the same start-up options as you (e.g. preloaded environment, site file, etc.), making it a good tool to test your scripts before sharing them.

If you want to get straight to the code, you can find it at https://gitlab.com/jozefhajnala/jhaddins.git

Prerequisites and recommendations

To make the most use of the series, you will need the following:

  1. R, ideally version 3.4.3 or more recent, 64bit
  2. RStudio IDE, ideally version 1.1.383 or more recent
  3. Also recommended
  • git, for version control
  • TortoiseGit, convenient shell interface to git for those using Windows, with pretty icons and all
  1. Recommended R packages (install with install.packages("packagename"), or via RStudio’s Packages tab):
  • devtools - makes your development life easier
  • testthat - provides a framework for unit testing integrated into RStudio
  • roxygen2 - makes code documentation easy

Step 1 - Creating a package

  1. Use devtools::create to create a package (note that we will update more DESCRIPTION fields later and you can also choose any path you like and it will be reflected in the name of the package)
devtools::create(
  path = "jhaddins"
, description = list("License" = "GPL-3")
)
  1. In RStudio or elsewhere navigate to the jhaddins folder and open the project jhaddins.Rproj (or the name of your project if you chose a different path)

  2. Run the first check and install the package

devtools::check()   # Ctrl+Shift+E or Check button on RStudio's build tab
devtools::install() # Ctrl+Shift+B or Install button on RStudio's build tab
  1. Optionally, initialize git for version control
devtools::use_git()

Step 2 - Writing the first functions

We will now write some functions into a file called makeCmd.R that will let us run the desired functionality:

  1. makeCmd to create a command executable via system or shell, with defaults set up for executing an R file specified by path
makeCmd <- function(path
                  , command = "Rscript"
                  , opts = "--vanilla"
                  , outputFile = NULL
                  , suffix = NULL
                  , addRhome = TRUE) {
  if (Sys.info()["sysname"] == "Windows") {
    qType <- "cmd2"
  } else {
    qType <- "sh"
  }
  if (isTRUE(addRhome)) {
    command <- file.path(R.home("bin"), command)
  }
  cmd <- paste(
    shQuote(command, type = qType)
  , shQuote(opts, type = qType)
  , shQuote(path, type = qType)
  )
  if (!is.null(outputFile)) {
    cmd <- paste(cmd, ">", shQuote(outputFile))
  }
  if (!is.null(suffix)) {
    cmd <- paste(cmd, suffix)
  }
  cmd
}
  1. executeCmd to execute a command
executeCmd <- function(cmd, intern = FALSE) {
  sysName <- Sys.info()["sysname"]
  stopifnot(
    is.character(cmd)
  , length(cmd) == 1
  , sysName %in% c("Windows", "Linux")
  )

  if (sysName == "Windows") {
    shell(cmd, intern = intern)
  } else {
    system(cmd, intern = intern)
  }
}
  1. replaceTilde for Linux purposes
replaceTilde <- function(path) {
  if (substr(path, 1, 1) == "~") {
    path <- sub("~", Sys.getenv("HOME"), path, fixed = TRUE)
  }
  file.path(path)
}
  1. And finally the function which will be used for the addin execution - runCurrentRscript to retrieve the path to the currently active file in RStudio, run it, write the output to a file output.txt and open the file with output.
runCurrentRscript <- function(
  path = replaceTilde(rstudioapi::getActiveDocumentContext()[["path"]])
, outputFile = "output.txt") {
  cmd <- makeCmd(path, outputFile = outputFile)
  executeCmd(cmd)
  if (!is.null(outputFile) && file.exists(outputFile)) {
    rstudioapi::navigateToFile(outputFile)
  }
}

Step 3 - Setting up an addin

Now that we have all our functions ready, all we have to do is create a file addins.dcf under the \inst\rstudio folder of our package. We specify the Name of the addin, write a nice Description of what it does and most importantly specify the Binding to the function we want to call:

creating addins.dcf under inst/rstudio

creating addins.dcf under inst/rstudio

Name: runCurrentRscript
Description: Executes the currently open R script file via Rscript with --vanilla option
Binding: runCurrentRscript
Interactive: false

Now we can rebuild and install our package and in RStudio’s menu navigate to Tools -> Addins -> Browse Addins..., and there it is - our first addin. For the best experience, we can click the Keyboard Shortcuts... button and assign a keyboard shortcut to our addin for easy use.

setting an RStudio addin keyboard shortcut

setting an RStudio addin keyboard shortcut

Now just open an R script, hit our shortcut and voilà, our script gets execute via RScript in vanilla mode.

Step 4 - Updating our DESCRIPTION and NAMESPACE

As our last steps, we should

  1. Update our DESCRIPTION file with rstudioapi as Imports, as we will be needing it before using our package:
Package: jhaddins
Title: JH's RStudio Addins
Version: 0.0.0.9000
Authors@R: person("Jozef", "Hajnala", email = "jozef.hajnala@gmail.com", role = c("aut", "cre"))
Description: Useful addins to make RStudio even better.
Depends: R (>= 3.0.1)
Imports: rstudioapi (>= 0.7)
License: GPL-3
Encoding: UTF-8
LazyData: true
RoxygenNote: 6.0.1
  1. Update our NAMESPACE by importing the functions from other packages that we are using, namely:
importFrom(rstudioapi, navigateToFile)
importFrom(rstudioapi, getActiveDocumentContext)

Now we can finally rebuild and install our package again and run a CHECK to see that we have no errors, warnings and notes telling us something is wrong. Make sure to use the document = FALSE for now.

devtools::install() # Ctrl+Shift+B or Install button on RStudio's build tab
devtools::check(document = FALSE)   # Ctrl+Shift+E or Check button on RStudio's build tab

What is next - Always paying our (technical) debts

In the next post of the series, we will pay our debt of

  • missing documentation for our functions, that will help us to generate updates to our NAMESPACE automatically and help us get a nice documentation so that we can read about our functions using ?
  • and unit tests to help us sleep better knowing that our functions get tested!

Wrapping up

We can quickly create an RStudio addin by:

  1. Creating an R package
  2. Writing a function in that package
  3. Creating a addins.dcf in \inst\rstudio folder of our package

TL;DR - Just give me the package

References