lifecycle

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

R Package Lifecycle Management

R包生命周期管理

Manage function and argument lifecycle using tidyverse conventions and the lifecycle package.
使用tidyverse规范和lifecycle包管理函数与参数的生命周期。

Setup

配置

Check if lifecycle is configured by looking for
lifecycle-*.svg
files in
man/figures/
.
If not configured, run:
r
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/
通过检查
man/figures/
目录下是否存在
lifecycle-*.svg
文件,确认lifecycle是否已配置。
若未配置,运行:
r
usethis::use_lifecycle()
该命令会:
  • 在DESCRIPTION文件的
    Imports
    中添加lifecycle
  • 在包文档文件中添加
    @importFrom lifecycle deprecated
  • 将徽章SVG文件复制到
    man/figures/
    目录

Lifecycle Badges

生命周期徽章

Insert badges in roxygen2 documentation:
r
#' @description
#' `r lifecycle::badge("experimental")`
#' `r lifecycle::badge("deprecated")`
#' `r lifecycle::badge("superseded")`
For arguments:
r
#' @param old_arg `r lifecycle::badge("deprecated")` Use `new_arg` instead.
Only badge functions/arguments whose stage differs from the package's overall stage.
在roxygen2文档中插入徽章:
r
#' @description
#' `r lifecycle::badge("experimental")`
#' `r lifecycle::badge("deprecated")`
#' `r lifecycle::badge("superseded")`
针对参数:
r
#' @param old_arg `r lifecycle::badge("deprecated")` Use `new_arg` instead.
仅为与包整体生命周期阶段不同的函数/参数添加徽章。

Deprecating a Function

弃用函数

  1. Add badge and explanation to
    @description
    :
r
#' Do something
#'
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `old_fun()` was deprecated in mypkg 1.0.0. Use [new_fun()] instead.
#' @keywords internal
  1. Add
    deprecate_warn()
    as first line of function body:
r
old_fun <- function(x) {

lifecycle::deprecate_warn("1.0.0", "old_fun()", "new_fun()")
new_fun(x)
}
  1. Show migration in examples:
r
#' @examples
#' old_fun(x)
#' # ->
#' new_fun(x)
  1. @description
    中添加徽章和说明:
r
#' Do something
#'
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `old_fun()` was deprecated in mypkg 1.0.0. Use [new_fun()] instead.
#' @keywords internal
  1. 在函数体第一行添加
    deprecate_warn()
r
old_fun <- function(x) {

lifecycle::deprecate_warn("1.0.0", "old_fun()", "new_fun()")
new_fun(x)
}
  1. 在示例中展示迁移方法:
r
#' @examples
#' old_fun(x)
#' # ->
#' new_fun(x)

Deprecation Functions

弃用函数说明

FunctionWhen 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:
  1. Search
    deprecate_stop()
    - consider removing function entirely
  2. Replace
    deprecate_warn()
    with
    deprecate_stop()
  3. Replace
    deprecate_soft()
    with
    deprecate_warn()
函数使用场景
deprecate_soft()
第一阶段:仅对直接用户和测试过程发出警告
deprecate_warn()
标准弃用:每8小时仅发出一次警告
deprecate_stop()
移除前的最终阶段:抛出错误并显示提示信息
大版本发布时的弃用工作流:
  1. 搜索
    deprecate_stop()
    - 考虑完全移除该函数
  2. deprecate_warn()
    替换为
    deprecate_stop()
  3. deprecate_soft()
    替换为
    deprecate_warn()

Renaming a Function

重命名函数

Move implementation to new name, call from old name with deprecation:
r
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `add_two()` was renamed to `number_add()` for API consistency.
#' @keywords internal
#' @export
add_two <- function(x, y) {
lifecycle::deprecate_warn("1.0.0", "add_two()", "number_add()")
number_add(x, y)
}

#' Add two numbers
#' @export
number_add <- function(x, y) {
x + y
}
将实现逻辑迁移到新函数名,在旧函数中调用新函数并添加弃用提示:
r
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `add_two()` was renamed to `number_add()` for API consistency.
#' @keywords internal
#' @export
add_two <- function(x, y) {
lifecycle::deprecate_warn("1.0.0", "add_two()", "number_add()")
number_add(x, y)
}

#' Add two numbers
#' @export
number_add <- function(x, y) {
x + y
}

Deprecating an Argument

弃用参数

Use
deprecated()
as default value with
is_present()
check:
r
#' @param path `r lifecycle::badge("deprecated")` Use `file` instead.
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
  }
  # ... rest of function
}
使用
deprecated()
作为默认值,并通过
is_present()
检查:
r
#' @param path `r lifecycle::badge("deprecated")` Use `file` instead.
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

重命名参数

r
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)
}
r
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:
r
#' Gather columns into key-value pairs
#'
#' @description
#' `r lifecycle::badge("superseded")`
#'
#' Development on `gather()` is complete. For new code, use [pivot_longer()].
#'
#' `df %>% gather("key", "value", x, y, z)` is equivalent to
#' `df %>% pivot_longer(c(x, y, z), names_to = "key", values_to = "value")`.
No warning needed - just document the preferred alternative.
针对有更好替代方案但不应被移除的函数:
r
#' Gather columns into key-value pairs
#'
#' @description
#' `r lifecycle::badge("superseded")`
#'
#' Development on `gather()` is complete. For new code, use [pivot_longer()].
#'
#' `df %>% gather("key", "value", x, y, z)` is equivalent to
#' `df %>% pivot_longer(c(x, y, z), names_to = "key", values_to = "value")`.
无需添加警告,仅需在文档中说明推荐的替代方案即可。

Marking as Experimental

标记为实验性

r
#' @description
#' `r lifecycle::badge("experimental")`
cool_function <- function() {
  lifecycle::signal_stage("experimental", "cool_function()")
  # ...
}
r
#' @description
#' `r lifecycle::badge("experimental")`
cool_function <- function() {
  lifecycle::signal_stage("experimental", "cool_function()")
  # ...
}

Testing Deprecations

测试弃用逻辑

Test that deprecated functions work and warn appropriately:
r
test_that("old_fun is deprecated", {
  expect_snapshot({
    x <- old_fun(1)
    expect_equal(x, expected_value)
  })
})
Suppress warnings in existing tests:
r
test_that("old_fun returns correct value", {
  withr::local_options(lifecycle_verbosity = "quiet")
  expect_equal(old_fun(1), expected_value)
})
测试已弃用函数是否正常工作并正确发出警告:
r
test_that("old_fun is deprecated", {
  expect_snapshot({
    x <- old_fun(1)
    expect_equal(x, expected_value)
  })
})
在现有测试中抑制警告:
r
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:
r
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
  )

  invisible()
}
Then use in affected functions:
r
my_function <- function(..., verbose = deprecated()) {
  warn_for_verbose(verbose)
  # ...
}
针对影响多个函数的弃用操作(例如移除一个通用参数),可创建内部辅助函数:
r
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
  )

  invisible()
}
随后在受影响的函数中使用该辅助函数:
r
my_function <- function(..., verbose = deprecated()) {
  warn_for_verbose(verbose)
  # ...
}

Custom Deprecation Messages

自定义弃用消息

For non-standard deprecations, use
I()
to wrap custom text:
r
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.
针对非标准弃用场景,使用
I()
包裹自定义文本:
r
lifecycle::deprecate_warn(
  when = "1.0.0",
  what = I('Setting option "pkg.opt" to "foo"'),
  with = I('"pkg.new_opt"')
)
what
部分的文本需要能与“was deprecated in...”衔接自然。

Reference

参考资料

See
references/lifecycle-stages.md
for detailed stage definitions and transitions.
查看
references/lifecycle-stages.md
获取详细的阶段定义与过渡说明。