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.
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
!