|
| 1 | +# --- |
| 2 | +# repo: r-lib/rlang |
| 3 | +# file: standalone-lifecycle.R |
| 4 | +# last-updated: 2023-02-23 |
| 5 | +# license: https://unlicense.org |
| 6 | +# imports: rlang (>= 1.0.0) |
| 7 | +# --- |
| 8 | +# |
| 9 | +# This file serves as a reference for currently unexported rlang |
| 10 | +# lifecycle functions. These functions require rlang in your `Imports` |
| 11 | +# DESCRIPTION field but you don't need to import rlang in your |
| 12 | +# namespace. |
| 13 | +# |
| 14 | +# ## Changelog |
| 15 | +# |
| 16 | +# 2023-02-23 |
| 17 | +# |
| 18 | +# - Updated the API and internals to match modern lifecycle tools. |
| 19 | +# |
| 20 | +# |
| 21 | +# 2021-04-19 |
| 22 | +# |
| 23 | +# - Removed `lifecycle()` function. You can now use the following in |
| 24 | +# your roxygen documentation to inline a badge: |
| 25 | +# |
| 26 | +# ``` |
| 27 | +# `r lifecycle::badge()` |
| 28 | +# ``` |
| 29 | +# |
| 30 | +# This is a build-time dependency on lifecycle so there is no need |
| 31 | +# to add lifecycle to Imports just to use badges. See also |
| 32 | +# `?usethis::use_lifecycle()` for importing or updating the badge |
| 33 | +# images in your package. |
| 34 | +# |
| 35 | +# - Soft-namespaced private objects. |
| 36 | +# |
| 37 | +# nocov start |
| 38 | + |
| 39 | + |
| 40 | +#' Signal deprecation |
| 41 | +#' |
| 42 | +#' @description |
| 43 | +#' These functions provide two levels of verbosity for deprecation |
| 44 | +#' warnings. |
| 45 | +#' |
| 46 | +#' * `deprecate_soft()` warns only if called directly: from the global |
| 47 | +#' environment (so the user can change their script) or from the |
| 48 | +#' package currently being tested (so the package developer can fix |
| 49 | +#' the package). |
| 50 | +#' |
| 51 | +#' * `deprecate_warn()` warns unconditionally. |
| 52 | +#' |
| 53 | +#' * `deprecate_stop()` fails unconditionally. |
| 54 | +#' |
| 55 | +#' Both functions warn only once per session by default to avoid |
| 56 | +#' overwhelming the user with repeated warnings. |
| 57 | +#' |
| 58 | +#' @param msg The deprecation message. |
| 59 | +#' @param id The id of the deprecation. A warning is issued only once |
| 60 | +#' for each `id`. Defaults to `msg`, but you should give a unique ID |
| 61 | +#' when the message is built programmatically and depends on inputs. |
| 62 | +#' @param user_env The environment in which the deprecated function |
| 63 | +#' was called. The verbosity depends on whether the deprecated |
| 64 | +#' feature was called directly, see [rlang::env_is_user_facing()] and the |
| 65 | +#' documentation in the lifecycle package. |
| 66 | +#' |
| 67 | +#' @section Controlling verbosity: |
| 68 | +#' |
| 69 | +#' The verbosity of retirement warnings can be controlled with global |
| 70 | +#' options. You'll generally want to set these options locally with |
| 71 | +#' one of these helpers: |
| 72 | +#' |
| 73 | +#' * `with_lifecycle_silence()` disables all soft-deprecation and |
| 74 | +#' deprecation warnings. |
| 75 | +#' |
| 76 | +#' * `with_lifecycle_warnings()` enforces warnings for both |
| 77 | +#' soft-deprecated and deprecated functions. The warnings are |
| 78 | +#' repeated rather than signalled once per session. |
| 79 | +#' |
| 80 | +#' * `with_lifecycle_errors()` enforces errors for both |
| 81 | +#' soft-deprecated and deprecated functions. |
| 82 | +#' |
| 83 | +#' All the `with_` helpers have `scoped_` variants that are |
| 84 | +#' particularly useful in testthat blocks. |
| 85 | +#' |
| 86 | +#' @noRd |
| 87 | +NULL |
| 88 | + |
| 89 | +deprecate_soft <- function(msg, |
| 90 | + id = msg, |
| 91 | + user_env = rlang::caller_env(2)) { |
| 92 | + .rlang_lifecycle_signal_stage(msg, "deprecated") |
| 93 | + |
| 94 | + id <- paste(id, collapse = "\n") |
| 95 | + verbosity <- .rlang_lifecycle_verbosity() |
| 96 | + |
| 97 | + invisible(switch( |
| 98 | + verbosity, |
| 99 | + quiet = NULL, |
| 100 | + warning = , |
| 101 | + default = |
| 102 | + if (rlang::env_is_user_facing(user_env)) { |
| 103 | + always <- verbosity == "warning" |
| 104 | + trace <- rlang::trace_back(bottom = caller_env()) |
| 105 | + .rlang_lifecycle_deprecate_warn0( |
| 106 | + msg, |
| 107 | + id = id, |
| 108 | + trace = trace, |
| 109 | + always = always |
| 110 | + ) |
| 111 | + }, |
| 112 | + error = deprecate_stop(msg) |
| 113 | + )) |
| 114 | +} |
| 115 | + |
| 116 | +deprecate_warn <- function(msg, |
| 117 | + id = msg, |
| 118 | + always = FALSE, |
| 119 | + user_env = rlang::caller_env(2)) { |
| 120 | + .rlang_lifecycle_signal_stage(msg, "deprecated") |
| 121 | + |
| 122 | + id <- paste(id, collapse = "\n") |
| 123 | + verbosity <- .rlang_lifecycle_verbosity() |
| 124 | + |
| 125 | + invisible(switch( |
| 126 | + verbosity, |
| 127 | + quiet = NULL, |
| 128 | + warning = , |
| 129 | + default = { |
| 130 | + direct <- rlang::env_is_user_facing(user_env) |
| 131 | + always <- direct && (always || verbosity == "warning") |
| 132 | + |
| 133 | + trace <- tryCatch( |
| 134 | + rlang::trace_back(bottom = rlang::caller_env()), |
| 135 | + error = function(...) NULL |
| 136 | + ) |
| 137 | + |
| 138 | + .rlang_lifecycle_deprecate_warn0( |
| 139 | + msg, |
| 140 | + id = id, |
| 141 | + trace = trace, |
| 142 | + always = always |
| 143 | + ) |
| 144 | + }, |
| 145 | + error = deprecate_stop(msg), |
| 146 | + )) |
| 147 | +} |
| 148 | + |
| 149 | +.rlang_lifecycle_deprecate_warn0 <- function(msg, |
| 150 | + id = msg, |
| 151 | + trace = NULL, |
| 152 | + always = FALSE, |
| 153 | + call = rlang::caller_env()) { |
| 154 | + if (always) { |
| 155 | + freq <- "always" |
| 156 | + } else { |
| 157 | + freq <- "regularly" |
| 158 | + } |
| 159 | + |
| 160 | + rlang::warn( |
| 161 | + msg, |
| 162 | + class = "lifecycle_warning_deprecated", |
| 163 | + .frequency = freq, |
| 164 | + .frequency_id = id |
| 165 | + ) |
| 166 | +} |
| 167 | + |
| 168 | +deprecate_stop <- function(msg) { |
| 169 | + msg <- cli::format_error(msg) |
| 170 | + .rlang_lifecycle_signal_stage(msg, "deprecated") |
| 171 | + |
| 172 | + stop(rlang::cnd( |
| 173 | + c("defunctError", "error", "condition"), |
| 174 | + old = NULL, |
| 175 | + new = NULL, |
| 176 | + package = NULL, |
| 177 | + message = msg |
| 178 | + )) |
| 179 | +} |
| 180 | + |
| 181 | +.rlang_lifecycle_signal_stage <- function(msg, stage) { |
| 182 | + rlang::signal(msg, "lifecycle_stage", stage = stage) |
| 183 | +} |
| 184 | + |
| 185 | +expect_deprecated <- function(expr, regexp = NULL, ...) { |
| 186 | + rlang::local_options(lifecycle_verbosity = "warning") |
| 187 | + |
| 188 | + if (!is.null(regexp) && rlang::is_na(regexp)) { |
| 189 | + rlang::abort("`regexp` can't be `NA`.") |
| 190 | + } |
| 191 | + |
| 192 | + testthat::expect_warning( |
| 193 | + {{ expr }}, |
| 194 | + regexp = regexp, |
| 195 | + class = "lifecycle_warning_deprecated", |
| 196 | + ... |
| 197 | + ) |
| 198 | +} |
| 199 | + |
| 200 | +local_lifecycle_silence <- function(frame = rlang::caller_env()) { |
| 201 | + rlang::local_options( |
| 202 | + .frame = frame, |
| 203 | + lifecycle_verbosity = "quiet" |
| 204 | + ) |
| 205 | +} |
| 206 | +with_lifecycle_silence <- function(expr) { |
| 207 | + local_lifecycle_silence() |
| 208 | + expr |
| 209 | +} |
| 210 | + |
| 211 | +local_lifecycle_warnings <- function(frame = rlang::caller_env()) { |
| 212 | + rlang::local_options( |
| 213 | + .frame = frame, |
| 214 | + lifecycle_verbosity = "warning" |
| 215 | + ) |
| 216 | +} |
| 217 | +with_lifecycle_warnings <- function(expr) { |
| 218 | + local_lifecycle_warnings() |
| 219 | + expr |
| 220 | +} |
| 221 | + |
| 222 | +local_lifecycle_errors <- function(frame = rlang::caller_env()) { |
| 223 | + rlang::local_options( |
| 224 | + .frame = frame, |
| 225 | + lifecycle_verbosity = "error" |
| 226 | + ) |
| 227 | +} |
| 228 | +with_lifecycle_errors <- function(expr) { |
| 229 | + local_lifecycle_errors() |
| 230 | + expr |
| 231 | +} |
| 232 | + |
| 233 | +.rlang_lifecycle_verbosity <- function() { |
| 234 | + opt <- getOption("lifecycle_verbosity", "default") |
| 235 | + |
| 236 | + if (!rlang::is_string(opt, c("quiet", "default", "warning", "error"))) { |
| 237 | + options(lifecycle_verbosity = "default") |
| 238 | + rlang::warn(glue::glue( |
| 239 | + " |
| 240 | + The `lifecycle_verbosity` option must be set to one of: |
| 241 | + \"quiet\", \"default\", \"warning\", or \"error\". |
| 242 | + Resetting to \"default\". |
| 243 | + " |
| 244 | + )) |
| 245 | + } |
| 246 | + |
| 247 | + opt |
| 248 | +} |
| 249 | + |
| 250 | +# nocov end |
0 commit comments