How to Make a R package in Rstudio

A learning note from reading “the whole game” chapter in R packages by Hadley Wickham and Jenny Bryan.

Install and load package development dependencies

install.packages("devtools") # a set of tools (functions) for R package development
install.packages("roxygen2") # documentation for individual functions
install.pacakges("usethis") # a package like "devtools" and complementary to it
install.packages("testthat") # make unittest simple
install.pacakges("tidyverse") # for data wrangling

library(devtools)
library(roxygen2)
library(usethis)
library(testthat)
library(tidyverse)
packageVersion("devtools")
packageVersion("roxygen2")
packageVersion("tidyverse")
packageVersion("testthat")
packageVersion("usethis")
[1] ‘2.4.0’
[1] ‘7.1.1’
[1] ‘1.3.0’
[1] ‘3.0.2’
[1] ‘2.0.1’

All functions used in this post comply to the versions from the section above, double check if your loaded dependencies are the same version. The actual function call might change slightly depends on which version you use.

Initialize a package in a desired location

Option 1: click on “File” tab -> “new project” -> choose from menu

Option 2: use devtools

devtools::create("path_to_package/myfirstRpackage")

Initialize a git repo, this is highly recommended, as you can track changes and link this repo to github. Read more about it in Happy Git and GitHub for the useR by Jenny Bryan and Jim Hester.

usethis::use_git() #initialises a Git repository and adds important files to .gitignore

Write functions and test files

We want to save R related functions in R/. One can refer to Hadley Wickham’s function chapter from Advanced R for writing functions in R. It is also important to generate tests for each function that was written. usethis::use_r() command lets user switch between .R files and associated tests. Below is an example.

usethis::use_r("concat_two_vec") # it would generate a script called concat_two_vec.R under R/

# paste concat_two_vec inside concat_two_vec.R
concat_two_vec <- function(vec1, vec2){c(vec1,vec2)} # click save

# initializes the unit test, it adds testthat to DESCRIPTION, creates the directory tests/testthat/, and adds the script tests/testthat.R
use_testthat() 

# in concat_two_vec.R view, type the following to the console
use_test() # this will generate tests/testthat/test-concat_two_vec.R with a default template, so that you can update your test case accordingly 

use_test() only generates a generic template for you to write test. It is the package creator’s responsibility to fill in the test case.

All tests can be run with test() command or whenever you check() the package (see ‘Build and check source by running check()’ section).

What if your function requires calling a function from another package, such as dplyr package?

use_package("dplyr") #adds "dplyr" to Imports field in DESCRIPTION

use_r("my_func_with_ dplyr") #creates 'R/my_func_with_dplyr.R'

#edit R/my_func_with_dplyr.R
#' Subset a column from a data.frame
#'
#' @param df data.frame
#' @param col_name: a column name of df
#'
#' @return A list
#' @export
#' @examples
#' my_func_with_dplyr(iris,Species)
my_func_with_dplyr <- function(df, col_name){dplyr::select(df, col_name)}

use_test() # create unit test template, you can add some test cases

Write documentation for functions

Here we want to use roxygen2 package to generate markdown page for each function, the markdown files will be saved in man and can be accessed by ?function_name. To do this, we would need to write docstrings in a specific way for each function before defining it. Checkout an exmaple made by roxygen2.

Most functions’ docstring have @param (follows by the description of input, one input variable per line), @return (follow by the description of what the function returns), @example (follows by an example usage of the function). There are many more types of tags one can use, see roxygen quick reference.

document()

After docstring of the function of interest is generated, run document() to generate documentation for the functions you have in R/. The documentation will be saved in man/ and can be looked up by ?function_name.In addition, it adds function names in R/ to NAMESPACE. Each time you add a new function to R/, you will need to run document() again.

Use git to commit small and meaningful changes, you can use git window built in Rstudio to do that.

Install package functions in dev mode and do some tests

After you’ve written a function and would like to test if it works, there are two ways to make a function available. Calling source("R/concat_two_vec.R") in package root directory will install it in the global workplace, whereas load_all() installs this package in development mode (also installs unexported internal ones, read more in devtools). Do not use both methods mentioned above in the same time, this will create concat_two_vec() in the global space and mask myfirstRpackage::concat_two_vec(). If you accidentially did both, remove the global version using rm(concat_two_vec).

Build and check source by running check()

check()

This updates your package’s documentation, loads it, updates NAMESPACE, checks environment variables and others necessary settings, it returns a report indicating the number of errors, warnings and notes. Read the report carefully and resolve errors while they are in the early stage.

Run check() as frequently as possible.

Fill in other generic parts with your stamp

DESCRIPTION provides metadata about this package, you can find information such as author and the purpose for this package. Ctrl + . in RStudio then type “DESCRIPTION” to load a template, start editing from there.

Use a license, such as MIT license by running use_mit_license("your first and last name here"), this generates a LICENSE and a LICENSE.md file.

Install package via install()

Run check() one more time, confirm everything works as expected.

install()

Now you can load functions like any other packages.

library(myfirstRpackage)