R Package Development
Use this skill when working with R packages to ensure proper development workflows, testing patterns, and documentation standards.
Development Workflow
R Environment
-
Use radian with R as an alias so call R scripts using Rscript
-
Do not run devtools::test with grep; read the whole output
Package Building and Management
Load package for interactive development
devtools::load_all()
Update documentation (REQUIRED before committing R changes)
devtools::document()
Run all tests
devtools::test()
Run specific test file
testthat::test_file("tests/testthat/test-filename.R")
Run tests matching a pattern
devtools::test(filter = "pattern") testthat::test_local(filter = "pattern")
Check package (R CMD check)
devtools::check()
Build package
devtools::build()
Install package locally
devtools::install()
Check with vignettes built
devtools::check(build_args = c("--compact-vignettes=both"))
Code Quality and Style
Lint package (configuration in .lintr)
lintr::lint_package()
Lint specific file
lintr::lint("R/filename.R")
Style code (pre-commit hook typically uses tidyverse style)
styler::style_pkg()
Check test coverage
covr::package_coverage()
Documentation Building
Build vignettes
devtools::build_vignettes()
Build specific vignette
rmarkdown::render("vignettes/name.Rmd")
Build pkgdown site locally
pkgdown::build_site()
Testing Best Practices
testthat Patterns
Preferred expectations:
- expect_identical()
expect_equal() (when exact match expected)
-
Multiple expect_true() calls > stacking conditions with &&
-
expect_s3_class()
expect_true(inherits(...))
-
Use specific expect_* functions:
-
expect_lt() , expect_gt() , expect_lte() , expect_gte()
-
expect_length()
-
expect_named()
-
expect_type()
Examples:
Good
expect_identical(result, expected) expect_s3_class(obj, "data.frame") expect_lt(value, 10) expect_true(condition1) expect_true(condition2)
Avoid
expect_equal(result, expected) # when identical match is needed expect_true(inherits(obj, "data.frame")) expect_true(value < 10) expect_true(condition1 && condition2)
Test Organisation
-
Use testthat edition 3
-
Test files named test-{component}.R
-
Helper files in tests/testthat/helper-{name}.R
-
Setup files in tests/testthat/setup.R for shared fixtures
-
Custom expectations in tests/testthat/helper-expectations.R
Conditional Testing
Skip tests on CRAN
testthat::skip_on_cran()
Skip if not on CI
testthat::skip_if_not(on_ci())
Skip if package not available
testthat::skip_if_not_installed("package")
Documentation Standards
roxygen2 Best Practices
Avoid duplication with @inheritParams :
#' @param x Input data #' @param ... Additional arguments my_function <- function(x, ...) {}
#' @inheritParams my_function #' @param y Another parameter wrapper_function <- function(x, y, ...) {}
Documentation structure:
-
One sentence per line in descriptions
-
Max 80 characters per line
-
Use @family tags for related functions
-
Use @examples or @examplesIf for examples
-
UK English spelling
Example documentation:
#' Process input data #' #' This function processes the input data according to specified parameters. #' It returns a processed data frame with additional columns. #' #' @param data A data.frame containing the input data #' @param method Character string specifying the processing method #' #' @return A data.frame with processed results #' #' @family preprocessing #' #' @examples #' \dontrun{ #' result <- process_data(my_data, method = "standard") #' } #' #' @export process_data <- function(data, method = "standard") {
implementation
}
Code Style Guidelines
Naming Conventions
Internal functions: Prefix with .
.internal_helper <- function() {}
Exported functions: Use snake_case
public_function <- function() {}
Formatting
-
Max 80 characters per line
-
No trailing whitespace
-
No spurious blank lines
-
Use tidyverse style guide
-
Set up pre-commit hooks for automatic formatting
Pre-commit Hooks
Typical .pre-commit-config.yaml includes:
-
style-files : Auto-format R code
-
lintr : Lint R code
-
readme-rmd-rendered : Ensure README.md is up-to-date
-
parsable-R : Check R syntax
-
deps-in-desc : Check dependencies are in DESCRIPTION
Install pre-commit
pip install pre-commit
Install hooks
pre-commit install
Run manually
pre-commit run --all-files
Common Data Structures
data.table Usage
Many R packages use data.table for performance:
-
Functions often expect/return data.table objects
-
Use data.table::setDT() or custom coerce_dt() to ensure input is data.table
-
Set keys for efficient joins: data.table::setkey(dt, col)
-
Use := for in-place modification
S3 Classes
-
Check class with inherits() or expect_s3_class()
-
Document S3 methods properly
-
Export constructors, not internal class definitions
Package Dependencies
Managing Dependencies
Use specific package functions with ::
package::function()
Add to DESCRIPTION Imports or Suggests
usethis::use_package("package_name") usethis::use_package("package_name", type = "Suggests")
Common R Package Ecosystem Tools
-
devtools: Development workflow
-
testthat: Testing framework
-
roxygen2: Documentation generation
-
usethis: Package setup automation
-
lintr: Code linting
-
styler: Code formatting
-
covr: Test coverage
-
pkgdown: Website generation
When to Use This Skill
Activate this skill when:
-
Developing R packages
-
Writing R tests
-
Documenting R functions
-
Setting up R package infrastructure
-
Running R package checks
-
Working with devtools, testthat, or roxygen2
This skill provides R-specific development patterns. Project-specific architecture and domain knowledge should remain in project CLAUDE.md files.