R package book: https://r-pkgs.org/

This is the best book to learn how to build R packages and it is free!

Useful packages to develop R package

if(!require("xfun")) install.packages("xfun")
xfun::pkg_attach2(c("devtools", "usethis", "roxygen2", "testthat"))

10 steps to develop an R package

1. Think about package name

A good package name should be relatively short, easy to pronounce, informative, and googlable (don’t use common word; but can change the word, e.g., knitr, rr2)

To check the availability of names, we can use the available package.

available::available("name_here")

2. Create package

Two ways to do this: use usethis::create_package() or create by hand with RStudio.

usethis::create_package("path/to/your/pkg")

RStudio –> New project –> New directory –> R package –> … (git repository?!) –> Create project

We have basic R package structure now!

  • .Rbuildignore lists files that we need to have around but that should not be included when building the R package from source
  • DESCRIPTION provides meta data of the package; we need to edit it
  • NAMESPACE declares the functions that will be exported and available to use after library()
  • R/ folder contains all the functions/code
  • man/ folder contains documentations of functions

Later, we may have folder such as data/, tests/, etc.

3. Write your functions (and documentations)!

Let’s just use the function (get_binomial_name()) we wrote.

#' To extract binomial scientific names
#' 
#' Some description about the function.
#'
#' @param v Input vector, must be a character vector.
#' @param patterns The Regex pattern to match, default will extract the first two words.
#' @param repl The values to replace the pattern matched that was specified by `patterns`.
#' @param ... Additional arguments to be passed to `[sub]` function.
#' @return A character vector, with the binomial scientific names
#' @examples get_binomial_name(c("Carex aquatilis Wahlenb.", "Boerhavia coulteri (Hook. f.) S. Watson"))
#'
get_binomial_name <- function(v, 
                              patterns = "^([^ ]+ [^ ]*) .*",
                              repl = "\\1",
                              ...
){
  if(!is.character(v)){ # in case non-character input
    stop("The input vector is not character.")
  }
  v2 = sub(pattern = patterns, replacement = repl, x = v, ...)
  return(v2)
} 

Copy and paste it into the existing R/hello.R or create a new R script file and paste there.

usethis::use_r("get_name")

To try the functions, use devtools::load_all() or click “Build –> load all”, which simulates the process of building, installing, and attaching the package.

4. Generate documentations.

To generate the documentations for functions, we can use devtools::document(). When running the code for the first time, if we see the warning below, simply just delete the NAMESPACE file and run devtools::document() again.

Warning: The existing ‘NAMESPACE’ file was not generated by roxygen2, and will not be overwritten.

Or if you prefer to click, “Build –> configure build tools –> check ‘Generate documentation with Roxygen’ –> OK”. Then click “Build –> Document” to generate the documentations.

NOTE: we need to add the following line if we want to actually export a function (so users can use it with library()).

#' @export

Now if we type ?get_binomial_name in R console, we should be able to read the documentation!!

5. Edit DESCRIPTION

You should add enough meta data here to tell more about your package.

If your function uses functions from other package(s), we need to declare that in the DESCRIPTION file:

usethis::use_package("stringr", type = "Imports")
# change types "Imports", "Depends", "Suggests", etc.

Then, use the format pkg::function() in your code.

6. Add a license

Read licensing a repository and links within it to learn more about how to choose a license.

Once decided, we can add it with the following examplary code in R:

usethis::use_agpl3_license()
usethis::use_mit_license() # or

You can read the generated LICENSE.md to have some idea about what it is.

7. Unit tests

We should test every function we put in the package.

usethis::use_test()

In the new tests/testthat folder, we can create R files to write unit tests. We won’t talk more about it here. To learn more, read the chapter 12 (testing) in the R packages book; or just look at the documentation of the testthat package.

context("Testing names")

test_that("Error returned when working with non-character input", {
  expect_error(get_binomial_name(1:5))
})

test_that("It should work with character input", {
  expect_equal(get_binomial_name(c("Carex aquatilis Wahlenb.", "Boerhavia coulteri (Hook. f.) S. Watson")),
               c("Carex aquatilis", "Boerhavia coulteri"))
})

Once having unit tests written, we can use devtools::test() or click “Build –> Test package” to test whether our function pass tests.

8. Check package for potential problems

We can use devtools::check() or click “Build –> Check package”. Hopefully no errors!

9. Build the package

We can try it with devtools::load_all() when we are developing it. Once done, we can click “Build –> Clean and Rebuild” to build and install it on our local computer. Once done, we can use the package in other projects!

10. Share your package

Now it is time to share your package with the world (or yourself). We can commit to Git and push to Github. Hopefully by now you are family with the process.

If you are serious about your package, submit it to CRAN! (then {rhub} package will be your friend; and devtools::release())

Sometimes we may even want to have a website for the package. For that, check out the {pkgdown} package.

That’s it!! Simple and easy, right??