Building R Packages
Prerequisites: Testing with testthat, Object-oriented R: S3
A package is the standard way to share R code — with colleagues, on GitHub, or on CRAN. Even for private work, packaging functions you reuse across projects gives you documentation, tests, and easy installation.
The usethis and devtools packages automate almost every step.
Creating a package
usethis::create_package("~/code/cleanr")
cleanr/
├── DESCRIPTION # name, version, authors, dependencies
├── NAMESPACE # generated: what the package exports
├── R/ # your functions
├── man/ # generated documentation
└── tests/testthat/ # tests
Writing a documented function
# R/clean_names.R
#' Standardize column names
#'
#' Converts names to lowercase snake_case and removes symbols.
#'
#' @param x A character vector of names.
#' @return A character vector of cleaned names.
#' @export
#' @examples
#' clean_names(c("First Name", "Total $"))
clean_names <- function(x) {
x <- tolower(trimws(x))
x <- gsub("[^a-z0-9]+", "_", x)
gsub("^_|_$", "", x)
}
#'comments are roxygen2 documentation: runningdevtools::document()turns them into help pages (?clean_names) and updatesNAMESPACE.@exportmakes the function available to users; unexported functions are internal helpers.
The development loop
devtools::load_all() # load the package as if installed (Ctrl+Shift+L)
devtools::document() # rebuild documentation
usethis::use_test("clean_names") # create tests/testthat/test-clean_names.R
devtools::test() # run the tests
devtools::check() # R CMD check: the full quality check
devtools::install() # install it locally
Dependencies
Declare packages you use with usethis::use_package("dplyr"), which adds
them to DESCRIPTION. Inside package code, call functions as
dplyr::filter() — never use library() in a package.
Sharing
- GitHub —
usethis::use_github(); others install withpak::pak("you/cleanr").usethis::use_github_action("check-standard")adds CI that runsR CMD checkon every push. - CRAN — requires
devtools::check()to pass with no errors, warnings, or notes, plus CRAN's policies; its reviewers check every submission. - pkgdown builds a documentation website from your help pages and vignettes.
Common mistakes
- Using
library()orsetwd()inside package functions. - Relying on global variables. Package functions should get everything they need through their arguments.