| name | lifecycle |
| description | Manage R package lifecycle using tidyverse principles. |
| user-invocable | true |
| allowed-tools | ["Read","Edit","Write","Bash"] |
| metadata | {"author":"Garrick Aden-Buie (@gadenbuie)","version":"1.1"} |
| license | MIT |
R Package Lifecycle Management
Manage function and argument lifecycle using tidyverse conventions and the lifecycle package.
Setup
Check if lifecycle is configured by looking for lifecycle-*.svg files in man/figures/.
If not configured, run:
usethis::use_lifecycle()
This:
- Adds lifecycle to
Imports in DESCRIPTION
- Adds
@importFrom lifecycle deprecated to the package documentation file
- Copies badge SVGs to
man/figures/
Lifecycle Badges
Insert badges in roxygen2 documentation:
For arguments:
Only badge functions/arguments whose stage differs from the package's overall stage.
Deprecating a Function
- Add badge and explanation to
@description:
- Add
deprecate_warn() as first line of function body:
old_fun <- function(x) {
lifecycle::deprecate_warn("1.0.0", "old_fun()", "new_fun()")
new_fun(x)
}
- Show migration in examples:
Deprecation Functions
| Function | When to Use |
|---|
deprecate_soft() | First stage; warns only direct users and during tests |
deprecate_warn() | Standard deprecation; warns once per 8 hours |
deprecate_stop() | Final stage before removal; errors with helpful message |
Deprecation workflow for major releases:
- Search
deprecate_stop() - consider removing function entirely
- Replace
deprecate_warn() with deprecate_stop()
- Replace
deprecate_soft() with deprecate_warn()
Renaming a Function
Move implementation to new name, call from old name with deprecation:
add_two <- function(x, y) {
lifecycle::deprecate_warn("1.0.0", "add_two()", "number_add()")
number_add(x, y)
}
number_add <- function(x, y) {
x + y
}
Deprecating an Argument
Use deprecated() as default value with is_present() check:
write_file <- function(x, file, path = deprecated()) {
if (lifecycle::is_present(path)) {
lifecycle::deprecate_warn("1.4.0", "write_file(path)", "write_file(file)")
file <- path
}
}
Renaming an Argument
add_two <- function(x, y, na_rm = TRUE, na.rm = deprecated()) {
if (lifecycle::is_present(na.rm)) {
lifecycle::deprecate_warn("1.0.0", "add_two(na.rm)", "add_two(na_rm)")
na_rm <- na.rm
}
sum(x, y, na.rm = na_rm)
}
Superseding a Function
For functions with better alternatives that shouldn't be removed:
No warning needed - just document the preferred alternative.
Marking as Experimental
cool_function <- function() {
lifecycle::signal_stage("experimental", "cool_function()")
}
Testing Deprecations
Test that deprecated functions work and warn appropriately:
test_that("old_fun is deprecated", {
expect_snapshot({
x <- old_fun(1)
expect_equal(x, expected_value)
})
})
Suppress warnings in existing tests:
test_that("old_fun returns correct value", {
withr::local_options(lifecycle_verbosity = "quiet")
expect_equal(old_fun(1), expected_value)
})
Deprecation Helpers
For deprecations affecting many functions (e.g., removing a common argument), create an internal helper:
warn_for_verbose <- function(
verbose = TRUE,
env = rlang::caller_env(),
user_env = rlang::caller_env(2)
) {
if (!lifecycle::is_present(verbose) || isTRUE(verbose)) {
return(invisible())
}
lifecycle::deprecate_warn(
when = "2.0.0",
what = I("The `verbose` argument"),
details = c(
"Set `options(mypkg_quiet = TRUE)` to suppress messages.",
"The `verbose` argument will be removed in a future release."
),
user_env = user_env
Then use in affected functions:
my_function <- function(..., verbose = deprecated()) {
warn_for_verbose(verbose)
}
Custom Deprecation Messages
For non-standard deprecations, use I() to wrap custom text:
lifecycle::deprecate_warn(
when = "1.0.0",
what = I('Setting option "pkg.opt" to "foo"'),
with = I('"pkg.new_opt"')
)
The what fragment must work with "was deprecated in..." appended.
Reference
See references/lifecycle-stages.md for detailed stage definitions and transitions.