Skip to contents
library(rpkgkit)
dir <- tempdir()
dir.create(dir)
usethis::create_package(dir)
usethis::local_project(dir)
usethis::use_readme_md(open = FALSE)

Import standalone helpers

rpkgkit includes utilities that can also be imported directly into another project with usethis::use_standalone().

usethis::use_standalone("WangLabCSU/rpkgkit", "args_to_func")

Match arguments to functions

The args_to_func.R standalone script provides helpers for matching a list of arguments to compatible functions.

f1 <- function(a, b) a + b
f2 <- function(x, y, ...) x * y
f3 <- function(p, q) p - q

args <- list(a = 1, b = 2)
match_func_to_args(args, f1, f2, f3)
args <- list(a = 1, b = 2, x = 3, y = 4)
foo <- function(x, y = 1) x + y
filter_args_for_func(args, foo)

Show the caller of a cli message

The caller_cli.R standalone script decorates a cli function so its output identifies the caller.

decorated <- add_caller_to_cli(cli::cli_alert_info)
foo1 <- \() {
  decorated("<- where is this called from?")
}
foo2 <- \() foo1()
bar <- function() foo2()
bar()

Use colored cli output

The colorful_cli.R standalone script creates a cli environment with convenient color classes.

color_cli <- create_colorful_cli_env()
color_cli$cli_alert_danger("{.red This is a red message}")
color_cli$cli_alert_info("{.blue This is a blue message}")
color_cli$cli_alert_info("{.orange This is an orange message}")

color_cli2 <- create_colorful_cli_env(cli_theme = generate_color_theme())
color_cli2$cli_alert_success(
  "{.violetred3 R}{.orange a}{.yellow i}{.green n}{.cyan b}{.blue o}{.purple w}"
)

The wrapped functions also take .envir, defaulting to parent.frame() and forwarded to the cli function, so {} interpolation is resolved in the caller’s environment instead of inside the wrapper:

name <- "world"
color_cli$cli_alert_info("Hello, {name}")

msg_env <- list2env(list(who = "Positron"), parent = emptyenv())
color_cli$cli_alert_info("Hello, {who}", .envir = msg_env)

Add timestamps to cli output

The ts_cli.R standalone script creates timestamped cli functions.

ts_cli <- create_ts_cli_env()
ts_cli$cli_alert_info("Hello, world!")

The cli_table.R standalone script prints frequency tables of a vector with cli styling. cli_table() uses two aligned lines (headers, then counts), while cli_table_oneline() collapses them into a single header: count line. Both return the underlying table object invisibly.

x <- c("apple", "pear", "apple", NA)

cli_table(x)
cli_table(x, head_format = ".strong", align = "center")

cli_table_oneline(x)
cli_table_oneline(mtcars$cyl, sep = " | ", count_format = NULL)

The cli_kable.R standalone script prints a data frame, a matrix or any object as.data.frame() accepts as the pipe table of knitr::kable(), the layout kableExtra::kable() shows, with cli inline classes instead of Markdown. The layout is the one of kable(): padded cells, padding extra spaces per column, a minimum column width of 3, rounded and right-aligned numbers, and the :---|---: alignment rule below the headers.

header_format (column headers), rownames_format (row names) and value_format (body values) style the table. Pass a single class to style everything, or a named vector or named list to style only the columns or rows it names: an unnamed element is the fallback style of everything that is not named, which is how a part of the table is highlighted. The printed lines are returned invisibly.

cli_kable(head(mtcars, 3))

# style the header of two columns only, with two different classes
cli_kable(head(mtcars, 3), header_format = c(cyl = ".val", wt = ".field"))

Named formats reach the rows too, and the elements of a value_format list can be named vectors of row names, so a block of rows and columns can be highlighted:

cli_kable(
  mtcars[1:6, c("mpg", "cyl", "disp", "wt")],
  header_format = c(disp = ".strong", wt = ".strong"),
  rownames_format = c("Hornet 4 Drive" = ".strong", "Valiant" = ".strong"),
  value_format = list(
    disp = c("Hornet 4 Drive" = ".field", "Valiant" = ".field"),
    wt = c("Hornet 4 Drive" = ".field", "Valiant" = ".field")
  )
)

Validate and transform arguments

The make_arg_validator.R standalone script builds reusable validators. Give it an unquoted block of checks and coercions written in terms of argument names; it returns a function that, called from inside your function, returns the validated arguments as a named list.

validate_add <- make_arg_validator({
  if (!type %in% c("sum", "product")) {
    rlang::abort("`type` must be \"sum\" or \"product\".", call = NULL)
  }
  n <- as.integer(max(n, 1L))
})

add <- function(type = c("sum", "product"), n = 1L) {
  args <- validate_add()
  switch(args$type, sum = sum(1:args$n), product = prod(1:args$n))
}

add("sum", 3)

Errors raised inside the block reach the caller unchanged, and an assignment to an existing argument is written back through the returned list:

try(list2env(validate_add(), envir = environment()))

Only names that already existed in the caller’s frame are returned, so a validator updates arguments but never adds new ones. The same validator can be shared by several functions, and env can be passed explicitly to validate a list of options instead of a function frame.

Manage standalone files in a package

Use inquire_standalone() to inspect standalone files in a GitHub repository and browse_standalone() to search supported repositories.

try(inquire_standalone("r-lib/rlang")) |> head()
#> Error in inquire_standalone("r-lib/rlang") : 
#>   could not find function "inquire_standalone"
#> [1] "Error in inquire_standalone(\"r-lib/rlang\") : \n  could not find function \"inquire_standalone\"\n"
try(browse_standalone()) |> head()
#> Error in browse_standalone() : 
#>   could not find function "browse_standalone"
#> [1] "Error in browse_standalone() : \n  could not find function \"browse_standalone\"\n"

Create a local standalone file with a standard metadata header:

library(rpkgkit)
#> ✔ rpkgkit v0.1.24 loaded [2 ms]
dir <- file.path(tempdir(), "R")
dir.create(dir, recursive = TRUE)
create_standalone("foo", path = dir, open = FALSE)
#> ✔ Created standalone file: /tmp/RtmpK00ZiL/R/standalone-foo.R

Validate the standalone file layout

check_standalone() verifies that a custom standalone file follows the layout consumed by usethis::use_standalone(). It checks the # --- header (the required repo, file, last-updated and license slots, the optional imports slot, and the format of each value), that every documented function carries @noRd, and that a # nocov start marker precedes all functions.

check_standalone(path = file.path(dir, "standalone-foo.R"))
#> ── standalone check results ──────────────────────────────── standalone-foo.R ──
#> ❯ The header slot `imports` is empty; remove it if there are no dependencies.
#> ... NOTE
#> ❯ The header has non-standard slots: `dependency`. ... NOTE
#> ❯ `repo` should look like `owner/repo`, got: R ... WARNING
#> ❯ No top-level function definitions found. ... NOTE
#> ✔ nocoverage start marker
#> 
#> Duration: 0.01s
#> 0 error ✔ | 1 warning ✖ | 3 notes ✖

Findings are printed in the style of devtools::check(), and the counts are returned invisibly as list(error = , warning = , note = ). An error in a check point skips the remaining ones, while warnings and notes never stop the run.

After editing standalone files, refresh their last-updated field:

update_time_in_standalone(path = file.path(dir, "standalone-foo.R"))
#> ✔ Updated last-updated to "2026-11-06" in 1 file.

Add a dated changelog entry to one or more standalone files:

add_changelog_in_standalone(
  path = file.path(dir, "standalone-foo.R"),
  "Added foo function"
)
#> ✔ Added changelog entry (2026-11-06) for /tmp/RtmpK00ZiL/R/standalone-foo.R.