How to start writing an R package

This is not a complete exhaustive resource for writing R packages. Think of this more as a “quick start” guide.

I’m writing this using R version 4.4.1 through ESS in Emacs on Manjaro Linux, but most of this is pretty platform-agnostic, and could probably work anywhere else. I’m assuming you keep your git repos in a folder called Projects in your home folder (~/Projects).

I will use “>” to indicate a new line in the R console and “$” to indicate a new line in a command line terminal.

1. Install R packages

Install the following R packages:

  • devtools
  • usethis
  • available

2. Choose a name for your package

> library(available)

## You can use the suggest function to generate possible names
## or you can come up with one yourself
> available::suggest("A tool to categorize clinical trials by measures of feasibility from their clinicaltrials.gov record")

categorizeR

## Check that the name is available on Github and CRAN
> available::available("categorizeR", browse=FALSE)

Name valid: ✔
Available on CRAN: ✔ 
Available on Bioconductor: ✔
Available on GitHub:  ✔ 
Abbreviations: http://www.abbreviations.com/categorize
Wikipedia: https://en.wikipedia.org/wiki/categorize
Wiktionary: https://en.wiktionary.org/wiki/categorize
Sentiment:???
Abbreviations: http://www.abbreviations.com/categorizeR
Wikipedia: https://en.wikipedia.org/wiki/categorizeR
Wiktionary: https://en.wiktionary.org/wiki/categorizeR
Sentiment:???

## You don't have to go through this, but it's a decent way to
## choose a name

For the following, we’re gonna assume you went with testpack for the name of your project.

3. Make a git repo

Go to Github and click the “New” button.

Enter the name for your package that you chose above (for the following we will use testpack) and click “Create repository.”

Now copy the ssh link, it will look something like this: git@github.com:bgcarlisle/testpack.git

In a terminal window do the following:

$ cd ~/Projects

$ git clone git@github.com:bgcarlisle/testpack.git

Cloning into 'testpack'...
warning: You appear to have cloned an empty repository

$ cd testpack

$ git config --local user.email "my-email@users.noreply.github.com"

Now you have your repo (testpack) and it’s cloned to your local machine (it’s in ~/Projects/testpack) so you can work on it.

4. Fill the empty repo folder with the skeleton of an R package

Do the following in R:

## Go to the folder that is one level up from the git repo
## folder
> setwd("~/Projects")

## Load the devtools library
> library(devtools)

## Create the basic R package structure in the git repo
## folder
> create("testpack")

✔ Setting active project to "/home/researchfairy/Projects/testpack".
✔ Creating R/.
✔ Writing DESCRIPTION.
Package: testpack
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R (parsed):
    * First Last <first.last@example.com> [aut, cre] (YOUR-ORCID-ID)
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to
    pick a license
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2
✔ Writing NAMESPACE.
✔ Setting active project to "<no active project>".

> setwd("testpack/")

Now you have two files and a folder inside your R package folder: DESCRIPTION, NAMESPACE and R/.

Edit DESCRIPTION with metadata that matches your project (title, version, your author details, description).

To choose the GPL license: use_gpl3_license()

(You can choose another license, but you’ll have to look up the function call yourself.)

Commit changes to your git repo and push to the server, so you have a baseline to work from.

5. Add a function to your package

Create a file with a .R extension in the R/ folder that is inside your package root folder and give it a descriptive name. If I were adding a function called testmath() to my package, I’d call the file R/testmath.R.

Use the following format for your function:

#' @title Function title
#'
#' @description A full paragraph describing the function
#'
#' @param varname A description of the argument 'varname' that will be
#'     passed to the function
#'
#' @return A description of what the function will return on
#'     completion
#'
#' @export
#'
#' @importFrom magrittr %>%
#'
#' @examples
#'
#' testmath(4)

testmath <- function(varname) {
    return(0)
}

Most of this is self-explanatory, except for a couple notes:

The @export line tells R that the function in question should be made available to the end-user of the package. If you leave it out, the function will be usable by other functions in the package, but not by the end user.

The @importFrom magrittr %>% line tells R to import the pipe operator as implemented by the magrittr package, which I use pretty much everywhere. If you don’t use it, you can leave this out.

Now that we have another package as a dependency, I’ll tell you how to tell your package to include other packages:

> use_package("magrittr")
✔ Adding magrittr to Imports field in DESCRIPTION.
☐ Refer to functions with magrittr::fun()

This will add magrittr to the DESCRIPTION file using the correct syntax. As the message says, be sure to always use the double-colon notation to refer to functions implemented by other packages.

You’ll also want to write some unit tests for any functions you write. To start a unit test for the testmath() function that you just wrote up, type: use_test("testmath")

This will create a file, tests/testthat/test-testmath.R, along with all the structure that R needs to run all the tests you will do on your package at once.

Inside the unit test file, write something like this:

test_that(
    "testmath works", {
    expect_equal(
        testmath(10),
        0
    )
})

6. Add some data to your package

Imagine you have some data frame in R, call it testdata. You want anyone who loads your package to have access to these data. This is how I would do it:

I would make a file called data-raw/generate-testdata.R in the project folder that contains a well-commented R script I used to generate the testdata data frame.

Then at the of this file, I’d put:

## Write data set to a CSV in the inst/extdata/ folder
if (! file.exists("inst/")) {
    dir.create("inst/")
}
if (! file.exists("inst/extdata/")) {
    dir.create("inst/extdata/")
}
comparator %>%
    write_csv("inst/extdata/testdata.csv")

## Write data set to a .dba file in the data/ folder
usethis::use_data(testdata, overwrite = TRUE)

Now all the data is saved as both a .dba file and a .csv in the package.

To document your data, create R/testdata.R with the following inside it:

#' Test data
#' 
#' @format Info about the formatting
#'
#' @usage
#'
#' data(testdata)

"testdata"

Details on best practices for documenting data in R packages here: https://r-pkgs.org/data.html

7. Test and document your package

Generate a file for package documentation using the following command:

> devtools::use_package_doc()

Now edit the file that was just created at R/testpack-package.R:

#' @details This package provides 1 function for doing miscellaneous
#'     math stuff
#'
#' @details testmath() always returns the number 0 regardless of what
#'     you give it
#'
#' @references Carlisle, BG. The grey literature, 2024.
#' 
#' @keywords internal
"_PACKAGE"

## usethis namespace: start
## usethis namespace: end
NULL

To run all your package’s unit tests, use the following command:

> devtools::test()

ℹ Testing testpack
✔ | F W  S  OK | Context
✔ |          1 | testmath

══ Results ══
[ FAIL 0 | WARN 0 | SKIP 0 | PASS 1 ]

To document your package, use the following command:

> devtools::document()

You can also use devtools::check() to check that all the formatting has been done correctly.

If that runs properly, install your package with devtools::install() to test it locally. When you’ve made changes, you can remove the package with remove.packages("testpack") and reinstall. (Pro-tip, quit R after every time you remove the package, or it gets confused sometimes.)

Commit your changes in git and push to Github. The package can now be installed by anyone using devtools::install_github("bgcarlisle/testpack").

This is probably enough to get you started, next time I’ll try to cover rhub and submitting to CRAN.

Published by

The Grey Literature

This is the personal blog of Benjamin Gregory Carlisle PhD. Queer; Academic; Queer academic. "I'm the research fairy, here to make your academic problems disappear!"

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.