lifecycle は、関数や引数の lifecycle
ステージを文書化する標準的な方法と、非推奨の関数からユーザーを誘導するためのツールを提供します。
詳細な説明に入る前に、 vignette("stages")
で説明されている
lifecycle ステージに精通していることを確認してください。
lifecycle バッジは、ユーザーがドキュメントを読むときに、lifecycle
ステージを簡単に確認できるようにします。 バッジを使うには、まず
usethis::use_lifecycle()
を呼んでバッジの画像をパッケージに埋め込みます
(これは一度だけ行う必要があります)。次に lifecycle::badge()
を使ってバッジを挿入します。
#' `r lifecycle::badge("experimental")`
#' `r lifecycle::badge("deprecated")`
#' `r lifecycle::badge("superseded")`
また、非推奨の関数は、実行時にその状態を告知する必要があります。
lifecycle は、3つの主要な引数を取る deprecate_warn()
を提供します。
最初の引数 when
は、非推奨が発生したときのバージョン番号を与えます。
2 番目の引数、 what
は、非推奨になったものを正確に記述します。
3番目の引数 with
は、推奨される代替案を提供します。
詳細は後ほど説明しますが、ここではいくつかの使用例を紹介します。
::deprecate_warn("1.0.0", "old_fun()", "new_fun()")
lifecycle#> Warning: `old_fun()` was deprecated in lifecycle 1.0.0.
#> Please use `new_fun()` instead.
::deprecate_warn("1.0.0", "fun()", "testthat::fun()")
lifecycle#> Warning: `fun()` was deprecated in lifecycle 1.0.0.
#> Please use `testthat::fun()` instead.
::deprecate_warn("1.0.0", "fun(old_arg)", "fun(new_arg)")
lifecycle#> Warning: The `old_arg` argument of `fun()` is deprecated as of lifecycle 1.0.0.
#> Please use the `new_arg` argument instead.
(メッセージにパッケージ名が含まれていることに注意してください。これは、関数を呼び出した環境から自動的に検出されるため、パッケージの名前空間から関数が呼び出されない限り機能しません)。
次のセクションでは、lifecycle バッジと関数を一緒に使用して、さまざまな一般的な開発タスクを処理する方法について説明します。
まず、@description
ブロックにバッジを追加します1。
なぜ非推奨になったのか、そして代わりに何を使えばいいのかを簡単に説明します。
#' Add two numbers
#'
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' This function was deprecated because we realised that it's
#' a special case of the [sum()] function.
次に、古い使い方から新しい使い方への変換方法を示す例を更新します。
#' @examples
#' add_two(1, 2)
#' # ->
#' sum(1, 2)
そして、@keywords internal
を追加して、ドキュメントのインデックスからその関数を削除してください。
pkgdown を使用している場合は、 _pkgdown.yml
に記載されなくなったことも確認してください。
これらの変更により、新しいユーザが非推奨の関数に出会う可能性は低くなりますが、すでにその関数を知っているユーザがドキュメントを参照することは防げません。
#' @keywords internal
これで
docsの作成は終わりです。次は、ユーザーが関数を呼び出したときに警告を表示するようにしましょう。
関数の最初の行に deprecate_warn()
の呼び出しを追加して、これを行います。
<- function(x, y) {
add_two ::deprecate_warn("1.0.0", "add_two()", "base::sum()")
lifecycle+ y
x
}
add_two(1, 2)
#> Warning: `add_two()` was deprecated in lifecycle 1.0.0.
#> Please use `base::sum()` instead.
#> [1] 3
deprecate_warn()
は、2つの一般的な非推奨の選択肢について、ユーザーフレンドリーなメッセージを生成します。
同じパッケージ内の関数:
lifecycle::deprecate_warn("1.0.0", "fun_old()", "fun_new()")
別のパッケージの関数:
lifecycle::deprecate_warn("1.0.0", "old()", "package::new()")
その他のケースでは、 details
引数を使用して、ユーザーへの独自のメッセージを提供します。
<- function(x, y) {
add_two ::deprecate_warn(
lifecycle"1.0.0",
"add_two()",
details = "This function is a special case of sum(); use it instead."
)+ y
x
}
add_two(1, 2)
#> Warning: `add_two()` was deprecated in lifecycle 1.0.0.
#> This function is a special case of sum(); use it instead.
#> [1] 3
非推奨の関数がまだ動作し、有用な警告を生成することをテストし、非推奨を正しく実装したことをテストすることは良い習慣です。
testthat::expect_snapshot()
2
の中で期待値を使うのは、これを行うための便利な方法です。
test_that("add_two is deprecated", {
expect_snapshot({
<- add_two(1, 1)
x expect_equal(x, 2)
}) })
If you have existing tests for the deprecated function you can
suppress the warning in those tests with the
lifecycle_verbosity
option:
非推奨の関数に対するテストが既にある場合は、
lifecycle_verbosity
オプションでテストでの警告を抑制することができます。
test_that("add_two returns the sum of its inputs", {
::local_options(lifecycle_verbosity = "quiet")
withrexpect_equal(add_two(1, 1), 2)
})
そして、非推奨に特化した別のテストを追加してください。
test_that("add_two is deprecated", {
expect_snapshot(add_two(1, 1))
})
特に重要な関数については、非推奨化処理にもう2つの段階を追加することができます。
deprecate_soft()
は deprecate_warn()
の前に使用されます。 この関数は、(a)
グローバル環境からその機能を試したユーザーと、(b)
その機能を直接利用した開発者 (testthat テスト実行時)
にのみ警告を発します。
非推奨の機能が他のパッケージから間接的に呼び出されている場合には警告を発しない
—
その目的は、非推奨の機能の使用を止める力を持つ人にだけ警告することを保証するためである。
deprecate_stop()
は deprecate_warn()
の後に来て、警告の代わりにエラーを発生させます。
単に機能を削除するよりも大きな利点は、ユーザーに代替機能を知らせることができることです。
これらのステージを使用する場合、メジャーリリースとマイナーリリースの非推奨ステージをバンプするためのプロセスも必要になるでしょう。 私たちは次のようなものを推奨します。
deprecate_stop()
を検索し、その関数を完全に削除する準備ができたかどうか検討します。
deprecate_warn()
を検索して、deprecate_stop()
に置き換えます。
残りの関数本体とテストを削除します。
deprecate_soft()
を検索して、
deprecate_warn()
に置き換えます。
既存のコードを壊さずに関数名を変更するには、実装を新しい関数に移動し、非推奨のメッセージを添えて古い関数から新しい関数を呼び出します。
#' Add two numbers
#'
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `add_two()` was renamed to `number_add()` to create a more
#' consistent API.
#' @keywords internal
#' @export
<- function(foo, bar) {
add_two ::deprecate_warn("1.0.0", "add_two()", "number_add()")
lifecyclenumber_add(foo, bar)
}
# documentation goes here...
#' @export
<- function(x, y) {
number_add + y
x }
もし、APIのオーバーホールの一環として多くの関数の名前を変更するのであれば、このように1つのファイルにすべての変更を記録するのも良いでしょう。 https://rvest.tidyverse.org/reference/rename.html
警告を発してユーザーを誘導する必要がないため、関数を廃止するよりも簡単です。 そのため、必要なことは、旧式 (supersed) バッジを追加することだけです。
#' Gather columns into key-value pairs
#'
#' @description
#' `r lifecycle::badge("superseded")`
そして、なぜその機能が廃止されたのか、推奨される代替案は何なのかを説明します。
#'
#' Development on `gather()` is complete, and for new code we recommend
#' switching to `pivot_longer()`, which is easier to use, more featureful,
#' and still under active development.
#'
#' In brief,
#' `df %>% gather("key", "value", x, y, z)` is equivalent to
#' `df %>% pivot_longer(c(x, y, z), names_to = "key", values_to = "value")`.
#' See more details in `vignette("pivot")`.
残りのドキュメントはそのままで大丈夫です。
もし、lifecycle の最先端を生きたいのであれば、実験的な
signal_stage()
の呼び出しを追加してください。
<- function(data, key = "key", value = "value", ...) {
gather ::signal_stage("superseded", "gather()")
lifecycle }
このシグナルは現在どのような挙動にもフックされていませんが、将来のリリースではロギングと解析のツールを提供する予定です。
ある関数が実験的であり、将来的にインターフェースが変更される可能性があることを宣伝するために、まず説明に実験的 (experimental) バッジを追加してください。
#' @description
#' `r lifecycle::badge("experimental")`
もしその関数が非常に実験的なものであれば、@keywords internal
も追加した方がよいかもしれません。
もし、実験的なlifecycle 機能を試したいのであれば、
signal_stage()
の呼び出しを本文に追加してください。
<- function() {
cool_function ::signal_stage("experimental", "cool_function()")
lifecycle }
このシグナルは現在、どのような挙動にもフックされていませんが、将来のリリースではロギングや分析ツールを提供する予定です。
この例では、na.rm
を非推奨とし、常に TRUE
とすることにします。
<- function(x, y, na.rm = TRUE) {
add_two sum(x, y, na.rm = na.rm)
}
まず、引数の説明文にバッジを追加します。
#' @param na.rm `r lifecycle::badge("deprecated")` `na.rm = FALSE` is no
#' longer supported; this function will always remove missing values
また、na.rm
がFALSEの場合、非推奨の警告を追加します。
この場合、動作に代わるものはないので、代わりに details
を使ってカスタムメッセージを提供します。
<- function(x, y, na.rm = TRUE) {
add_two if (!isTRUE(na.rm)) {
::deprecate_warn(
lifecyclewhen = "1.0.0",
what = "add_two(na.rm)",
details = "Ability to retain missing values will be dropped in next release."
)
}
sum(x, y, na.rm = na.rm)
}
add_two(1, NA, na.rm = TRUE)
#> [1] 1
add_two(1, NA, na.rm = FALSE)
#> Warning: The `na.rm` argument of `add_two()` is deprecated as of lifecycle 1.0.0.
#> Ability to retain missing values will be dropped in next release.
#> [1] NA
また、デフォルト値を lifecycle::deprecated()
に変更して、外から見ても非推奨であることがわかるようにし、
lifecycle::is_present()
を使って引数が提供されたかどうかをテストすることもできます。 missing()`
とは異なり、これは直接的な呼び出しと間接的な呼び出しの両方で機能します。
#' @importFrom lifecycle deprecated
<- function(x, y, na.rm = deprecated()) {
add_two if (lifecycle::is_present(na.rm)) {
::deprecate_warn(
lifecyclewhen = "1.0.0",
what = "add_two(na.rm)",
details = "Ability to retain missing values will be dropped in next release."
)
}
sum(x, y, na.rm = na.rm)
}
この手法の最大の利点は、ユーザが na.rm
のどの値を使っても警告が表示されることです。
add_two(1, NA, na.rm = TRUE)
#> Warning: The `na.rm` argument of `add_two()` is deprecated as of lifecycle 1.0.0.
#> Ability to retain missing values will be dropped in next release.
#> [1] 1
add_two(1, NA, na.rm = FALSE)
#> Warning: The `na.rm` argument of `add_two()` is deprecated as of lifecycle 1.0.0.
#> Ability to retain missing values will be dropped in next release.
#> [1] NA
引数の名前を間違えたことに気づいたとき、引数の名前を変更することがあります。
例えば、引数の複合名を区切るのに、誤って _
ではなく
.
を使っていることに気づいたとします。
一時的に両方の引数を許可して、ユーザーが古い引数を入力したときに非推奨の警告を表示する必要があります。
<- function(x, y, na_rm = TRUE, na.rm = deprecated()) {
add_two if (lifecycle::is_present(na.rm)) {
::deprecate_warn("1.0.0", "add_two(na.rm)", "add_two(na_rm)")
lifecycle<- na.rm
na_rm
}
add_two(x, y, na.rm = na_rm)
}
許可される入力のセットを狭めるには、ユーザーが以前にサポートされていた入力を供給するときだけ
deprecate_warn()
を呼び出します。
以前の挙動を保持することを確認してください。
<- function(x, y) {
add_two if (length(y) != 1) {
::deprecate_warn("1.0.0", "foo(y = 'must be a scalar')")
lifecycle<- sum(y)
y
}+ y
x
}
add_two(1, 2)
#> [1] 3
add_two(1, 1:5)
#> Warning: The `y` argument of `foo()` must be a scalar as of lifecycle 1.0.0.
#> [1] 16