Skip to contents

Overview

The litr R package lets you write a complete R package in a single R markdown document. This enables a workflow for writing R packages that is probably very different from what you are used to.

With litr, knitting creates an R package in addition to the .html file.

Why write R packages in this way?

Using litr brings all the benefits of R markdown to package development:

  • Record and explain every step of making your R package so that you and others can understand every detail years later.
  • Present the functions in your package in a logical order that maximizes human readability.
  • Include all the derivations in latex right next to the code that ends up in your package.
  • Include figures alongside code to help in the explanation.
  • Define unit tests in the relevant context, i.e. directly after defining the function to be tested.

Furthermore, writing your R package is actually easier with litr than without it. Just choose one of the R package templates below and press “Knit” – and you’ll have a working R package that you can then modify.

Installation

You can install the latest release of litr on github with the following:

remotes::install_github("jacobbien/litr-project@*release", subdir = "litr")

Or for the latest development version, remove the @*release in the above.

Getting started

Using a template is the best way to get started:

rmarkdown::draft("create-rhello.Rmd", template = "make-an-r-package", package = "litr")

This creates an R markdown file called create-rhello.Rmd that demonstrates the literate programming workflow for writing an R package. In particular, when you knit create-rhello.Rmd, it creates a tiny example R package called rhello with one function and one test function. To knit, you can either press “Knit” in RStudio or use the following command:

litr::render("create-rhello.Rmd")

This creates an R package! Now you can modify the template to design your own package.

To explore other kinds of R packages, such as those using Rcpp, see the templates page. Also, see the section on packages in the wild that use litr.

More background

When you try to understand the code in an R package, the logic of how the functions relate to each other is often not obvious. While including function documentation, vignettes, and unit tests are all best practices, they do not convey the chain of logic in the mind of the programmer that went into writing the different functions. It can be difficult to know how to look through all the functions within even a well-documented R package. The fact that the functions appear in different files and that functions within files can be defined in arbitrary order makes it unclear how to approach reading the code. Furthermore, tests are stored in a different place from the functions themselves, making the tests harder to read. This would all be resolved if we could have a single document that goes through all code and tests in a linear, logical fashion. Rather than try to construct such a document after the fact, the idea of litr is to make this document the actual source code for the package. The R package is created through the act of knitting this document. If we want to modify anything in the package, then we do so by modifying this document and re-knitting.

The above motivation is that of literate programming, introduced by Donald Knuth, and the direct inspiration is fast.ai’s nbdev, which is available in Python. The litr package relies heavily on a number of great tools in R, especially knitr, rmarkdown, usethis, devtools, and testthat. I should also note that Yihui Xie has a post where he demonstrates a similar idea, although his approach appears to be more of a proof of concept.

You can hear Jeremy Howard and Hugo Bowne-Anderson talk about literate programming and nbdev on the Vanishing Gradients podcast. This discussion is what inspired litr!