| Title: | Advice on R Package Building |
|---|---|
| Description: | Give advice about good practices when building R packages. Advice includes functions and syntax to avoid, package structure, code complexity, code formatting, etc. |
| Authors: | Mark Padgham [aut, cre] (ORCID: <https://orcid.org/0000-0003-2172-5265>), Ascent Digital Services UK Limited [cph] (GitHub: MangoTheCat), Karina Marks [aut] (GitHub: KarinaMarks), Daniel de Bortoli [aut] (GitHub: ddbortoli), Gabor Csardi [aut], Hannah Frick [aut], Owen Jones [aut] (GitHub: owenjonesuob), Hannah Alexander [aut], Ana Simmons [ctb] (GitHub: anasimmons), Fabian Scheipl [ctb] (GitHub: fabian-s), Athanasia Mo Mowinckel [aut] (GitHub: drmowinckels, ORCID: <https://orcid.org/0000-0002-5756-0223>) |
| Maintainer: | Mark Padgham <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.0.5.9000 |
| Built: | 2026-04-17 14:56:21 UTC |
| Source: | https://github.com/ropensci-review-tools/goodpractice |
Give advice about good practices when building R packages. Advice includes functions and syntax to avoid, package structure, code complexity, code formatting, etc.
Maintainer: Mark Padgham [email protected] (ORCID)
Authors:
Karina Marks [email protected] (KarinaMarks)
Daniel de Bortoli (ddbortoli)
Gabor Csardi [email protected]
Hannah Frick [email protected]
Owen Jones [email protected] (owenjonesuob)
Hannah Alexander [email protected]
Athanasia Mo Mowinckel [email protected] (ORCID) (drmowinckels)
Other contributors:
Ascent Digital Services UK Limited (MangoTheCat) [copyright holder]
Ana Simmons [email protected] (anasimmons) [contributor]
Fabian Scheipl (fabian-s) [contributor]
Useful links:
Report bugs at https://github.com/ropensci-review-tools/goodpractice/issues
Returns the names of all registered check groups.
Use these names with checks_by_group() to select checks by group,
or with options(goodpractice.exclude_check_groups = ...) to skip
groups.
all_check_groups()all_check_groups()
Character vector of check group names
all_check_groups() # See all checks by group lapply(all_check_groups(), checks_by_group)all_check_groups() # See all checks by group lapply(all_check_groups(), checks_by_group)
List the names of all checks
all_checks()all_checks()
Character vector of checks
all_checks()all_checks()
List all checks performed
checks(gp)checks(gp)
gp |
|
Character vector of check names.
Other API:
failed_checks(),
results()
path <- system.file("bad1", package = "goodpractice") # run a subset of all checks available g <- gp(path, checks = all_checks()[3:16]) checks(g)path <- system.file("bad1", package = "goodpractice") # run a subset of all checks available g <- gp(path, checks = all_checks()[3:16]) checks(g)
Returns the names of all checks that belong to the given group(s). This makes it easy to run or inspect a specific category of checks without knowing individual check names.
checks_by_group(...)checks_by_group(...)
... |
Group names as character strings. Use |
Character vector of check names
# run only DESCRIPTION and namespace checks checks_by_group("description", "namespace") # see what the lintr group covers checks_by_group("lintr") # See all checks by group: lapply(all_check_groups(), checks_by_group) # use directly in gp() ## Not run: gp(".", checks = checks_by_group("description", "lintr")) ## End(Not run)# run only DESCRIPTION and namespace checks checks_by_group("description", "namespace") # see what the lintr group covers checks_by_group("lintr") # See all checks by group: lapply(all_check_groups(), checks_by_group) # use directly in gp() ## Not run: gp(".", checks = checks_by_group("description", "lintr")) ## End(Not run)
Defining custom preparations and checks
make_prep(name, func) make_check(description, check, gp, ...)make_prep(name, func) make_check(description, check, gp, ...)
name |
Name of the preparation function. |
func |
A function that takes two arguments:
The |
description |
A description of the check. |
check |
A function that takes the |
gp |
A short description of what is good practice. |
... |
Further arguments. Most important: A |
For make_prep: a preparation function. For
make_check: a check object of class "check".
make_prep(): Create a preparation function
make_check(): Create a check function
# make a preparation function url_prep <- make_prep( name = "desc", func = function(path, quiet) desc::description$new(path) ) # and the corresponding check function url_chk <- make_check( description = "URL field in DESCRIPTION", tags = character(), preps = "desc", gp = "have a URL field in DESCRIPTION", check = function(state) state$desc$has_fields("URL") ) # use together in gp(): # (note that you have to list the name of your custom check in # the checks-argument as well....) bad1 <- system.file("bad1", package = "goodpractice") res <- gp(bad1, checks = c("url", "no_description_depends"), extra_preps = list("desc" = url_prep), extra_checks = list("url" = url_chk))# make a preparation function url_prep <- make_prep( name = "desc", func = function(path, quiet) desc::description$new(path) ) # and the corresponding check function url_chk <- make_check( description = "URL field in DESCRIPTION", tags = character(), preps = "desc", gp = "have a URL field in DESCRIPTION", check = function(state) state$desc$has_fields("URL") ) # use together in gp(): # (note that you have to list the name of your custom check in # the checks-argument as well....) bad1 <- system.file("bad1", package = "goodpractice") res <- gp(bad1, checks = c("url", "no_description_depends"), extra_preps = list("desc" = url_prep), extra_checks = list("url" = url_chk))
List the names of default checks (excludes optional check sets)
default_checks()default_checks()
Character vector of default check names
default_checks()default_checks()
Describe one or more checks
describe_check(check_name = NULL)describe_check(check_name = NULL)
check_name |
Names of checks to be described. |
List of character descriptions for each check_name
describe_check("rcmdcheck_non_portable_makevars") check_name <- c("no_description_depends", "lintr_assignment_linter", "no_import_package_as_a_whole", "rcmdcheck_missing_docs") describe_check(check_name) # Or to see all checks: ## Not run: describe_check(all_checks()) ## End(Not run)describe_check("rcmdcheck_non_portable_makevars") check_name <- c("no_description_depends", "lintr_assignment_linter", "no_import_package_as_a_whole", "rcmdcheck_missing_docs") describe_check(check_name) # Or to see all checks: ## Not run: describe_check(all_checks()) ## End(Not run)
Export failed checks to JSON
export_json(gp, file, pretty = FALSE)export_json(gp, file, pretty = FALSE)
gp |
|
file |
Output connection or file. |
pretty |
Whether to pretty-print the JSON. |
Invisibly returns the path to the output file.
path <- system.file("bad1", package = "goodpractice") g <- gp(path, checks = "description_url") tmp <- tempfile(fileext = ".json") export_json(g, tmp) unlink(tmp)path <- system.file("bad1", package = "goodpractice") g <- gp(path, checks = "description_url") tmp <- tempfile(fileext = ".json") export_json(g, tmp) unlink(tmp)
Names of the failed checks
failed_checks(gp)failed_checks(gp)
gp |
|
Names of the failed checks.
Other API:
checks(),
results()
path <- system.file("bad1", package = "goodpractice") # run a subset of all checks available g <- gp(path, checks = all_checks()[3:16]) failed_checks(g)path <- system.file("bad1", package = "goodpractice") # run a subset of all checks available g <- gp(path, checks = all_checks()[3:16]) failed_checks(g)
Note that not all checks refer to the source code.
For these the result will be NULL.
failed_positions(gp)failed_positions(gp)
gp |
|
For the ones that do, the results is a list, one for each failure.
Since the same check can fail multiple times. A single failure
is a list with entries: filename, line_number,
column_number, ranges. ranges is a list of
pairs of start and end positions for each line involved in the
check.
A list of lists of positions. See details below.
path <- system.file("bad1", package = "goodpractice") g <- gp(path, checks = "description_url") failed_positions(g)path <- system.file("bad1", package = "goodpractice") g <- gp(path, checks = "description_url") failed_positions(g)
To see the results, just print it to the screen.
gp( path = ".", checks = default_checks(), extra_preps = NULL, extra_checks = NULL, quiet = TRUE )gp( path = ".", checks = default_checks(), extra_preps = NULL, extra_checks = NULL, quiet = TRUE )
path |
Path to a package root. |
checks |
Character vector, the checks to run. Defaults to
|
extra_preps |
Custom preparation functions. See
|
extra_checks |
Custom checks. See |
quiet |
Whether to suppress output from the preparation
functions. Note that not all preparation functions produce output,
even if this option is set to |
A goodpractice object that you can query
with a simple API. See results to start.
When using the default checks = all_checks(), entire groups of
checks can be excluded by group name via the
goodpractice.exclude_check_groups option or the
GP_EXCLUDE_CHECK_GROUPS environment variable (comma-separated).
The option takes precedence.
# Skip URL and coverage checks:
options(goodpractice.exclude_check_groups = c("urlchecker", "covr"))
# Or via environment variable:
Sys.setenv(GP_EXCLUDE_CHECK_GROUPS = "urlchecker,covr")
Exclusion only applies when checks = NULL (the default).
Explicit checks arguments are never filtered.
Specific files can be excluded from checks via the
goodpractice.exclude_path option or the GP_EXCLUDE_PATH
environment variable (comma-separated). Paths are relative to the
package root.
options(goodpractice.exclude_path = c("R/RcppExports.R", "R/generated.R"))
# Or via environment variable:
Sys.setenv(GP_EXCLUDE_PATH = "R/RcppExports.R,R/generated.R")
Excluded files are skipped by lintr, treesitter, expression, and roxygen2 checks.
Preparation steps run sequentially by default. To run them in
parallel, install future.apply and set a
plan:
future::plan("multisession")
gp(".")
Preps run in parallel only when a non-sequential plan is active. Prep functions must be independent: in parallel mode each prep receives the initial state snapshot, so a prep cannot read another prep's output. Only new state fields are merged back; if two preps write the same field, the second is dropped with a warning.
path <- system.file("bad1", package = "goodpractice") # run a subset of all checks available g <- gp(path, checks = all_checks()[3:16]) gpath <- system.file("bad1", package = "goodpractice") # run a subset of all checks available g <- gp(path, checks = all_checks()[3:16]) g
Print goodpractice results
## S3 method for class 'goodPractice' print(x, positions_limit = 5, ...)## S3 method for class 'goodPractice' print(x, positions_limit = 5, ...)
x |
Object of class |
positions_limit |
How many positions to print at most. |
... |
Unused, for compatibility with |
Return all check results in a data frame
results(gp)results(gp)
gp |
|
Data frame, with columns:
check |
The name of the check. |
passed |
Logical, whether the check passed. |
Other API:
checks(),
failed_checks()
path <- system.file("bad1", package = "goodpractice") # run a subset of all checks available g <- gp(path, checks = all_checks()[3:16]) results(g)path <- system.file("bad1", package = "goodpractice") # run a subset of all checks available g <- gp(path, checks = all_checks()[3:16]) results(g)
These checks are optional and not included in the default set.
They are powered by lint_package using lintr's
default linter set and respect any .lintr configuration file
in the package root (e.g. to disable specific linters or add exclusions).
Add them via checks = c(default_checks(), tidyverse_checks()).
tidyverse_checks()tidyverse_checks()
Character vector of tidyverse check names
tidyverse_checks()tidyverse_checks()