Usage of the lifecycle package

library(lifecycle)

lifecycle は、エクスポートされた関数や引数の状態を記録するために使用します。ドキュメントに lifecycle ステージを記述するための標準的な方法と、非推奨の関数からユーザーを引き離すためのツールを提供します。

Stages

関数1 の lifecycle ステージを下図にまとめました。

デフォルトの開発ステージは、Stable です。関数は、作者がそのインタフェースや動作に十分満足し、多くのユーザと共有できる場合に安定したとみなされます。安定した機能には保証があります。もし破壊的な変更が必要な場合は、以下に説明する非推奨のプロセスを通じて、徐々に行われるでしょう。

エクスポートされた関数の安定性は、エクスポート元のパッケージのバージョン番号に基づいて、さらに細かく設定することができます。>1.0.0パッケージでは、主要な機能は作者によって「完成」されたとみなされます。ブレークチェンジや非推奨はあり得ません。1.0.0 以下のパッケージでは、パッケージのいくつかの部分 (内部バックエンド、外部 UI など) はまだ作業が必要であり、変更が可能です。安定した >=1.0.0 パッケージは、依存し、頼るのに最も安全なパッケージです。

パッケージと関数の中には、 Experimental ステージで公開されるものもあります。実験的な機能は、人々がそれを試してフィードバックを提供できるように公開されていますが、作者は変更を壊さないようにすることを約束するものではありません。壊れるような変更に対する非推奨のプロセスは保証されていません(ただし、十分に多くのユーザーがその機能に依存している場合には、起こるかもしれません)。

End of life

ある関数が寿命を迎えるには、2つの方法があります。

特に重要な機能については、非推奨のサイクルを2段階追加することができます。

関数の作者は、ある関数が最適なアプローチであることを確信できなくなることがありますが、より良い方法をまだ知らないのです。このような関数は、 Questioning としてマークすることで、作者がその関数に疑問を抱いていることをユーザーに警告することができます。

Documentation

実験的、疑問的、上書きのある、非推奨(ソフト非推奨、廃止された機能を含む)は、文書中にバッジで明確に表示されるべきです。

Signals

非推奨の関数は、その非推奨の状態を明確に示す必要があります。メッセージの多さ (verbosity) には3つのレベルがあります。

以下の項では、関数や引数を非推奨とする場合の詳細を説明します。

Functions

最初の2つの引数は、非推奨が発生したバージョン3と、何が非推奨であるかの説明を与えます。

deprecate_warn("1.0.0", "mypkg::foo()")
#> Warning: `foo()` is deprecated as of mypkg 1.0.0.
#> This warning is displayed once every 8 hours.
#> `lifecycle::last_warnings()` をコールして、この警告がどこで発生したかを確認します。

可能であれば、第3引数に置換を記述します。

deprecate_warn("1.0.0", "mypkg::foo()", "new()")
#> Warning: `foo()` is deprecated as of mypkg 1.0.0.
#> Please use `new()` instead.
#> This warning is displayed once every 8 hours.
#> `lifecycle::last_warnings()` をコールして、この警告がどこで発生したかを確認します。

これらの例では、明示的に名前空間に言及していますが、ライフサイクルが呼び出し環境から推論するため、通常は名前空間を省略することができます。名前空間を指定することは、その置換が別のパッケージで実装されている場合にほとんど有効です。

# The new replacement
foobar_adder <- function(foo, bar) {
  foo + bar
}

# The old function still exported for compatibility
foobaz_adder <- function(foo, bar) {
  deprecate_warn("1.0.0", "foobaz_adder()", "foobar_adder()")
  foobar_adder(foo, bar)
}

Arguments

非推奨の引数の構文も同様です。

deprecate_warn("1.0.0", "mypkg::foo(arg = )")
#> Warning: The `arg` argument of `foo()` is deprecated as of mypkg 1.0.0.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_warnings()` to see where this warning was generated.

deprecate_warn("1.0.0", "mypkg::foo(arg = )", "mypkg::foo(new = )")
#> Warning: The `arg` argument of `foo()` is deprecated as of mypkg 1.0.0.
#> Please use the `new` argument instead.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_warnings()` to see where this warning was generated.

引数は、特定の入力タイプを禁止することで、部分的に非推奨とすることができます。

deprecate_warn("1.0.0", "mypkg::foo(arg = 'must be a scalar integer')")
#> Warning: The `arg` argument of `foo()` must be a scalar integer as of mypkg 1.0.0.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_warnings()` to see where this warning was generated.

lifecycle はまた、デフォルトの引数として使用する deprecated() センチネルを提供します。これはユーザに対してセルフ・ドキュメンテーションを提供し、外部ツールはどの引数が廃止されたかを判断することが可能になります。lifecycle::is_present() で、呼び出し元から引数が与えられたかどうかテストします。

foobar_adder <- function(foo, bar, baz = deprecated()) {
  # Check if user has supplied `baz` instead of `bar`
  if (lifecycle::is_present(baz)) {

    # Signal the deprecation to the user
    deprecate_warn("1.0.0", "foobar_adder(baz = )", "foobar_adder(bar = )")

    # Deal with the deprecated argument for compatibility
    bar <- baz
  }

  foo + bar
}

Workflow

これらの非推奨の警告はどこから来るのでしょうか?

lifecycle::last_warnings() を呼び出すと、最後のトップレベルコマンドで発行されたすべての非推奨 警告のバックトラックを見ることができます。

非推奨ステージの変更

非推奨の機能のステータスを上げるには、手動での検索と置換が必要です。廃止された機能から始めて、順次対応することをお勧めします。

  1. deprecate_stop() を検索して、パッケージから機能を削除してください。これでその機能はアーカイブされます。

  2. deprecate_warn() を検索して deprecate_stop() に置き換えてください。

  3. deprecate_soft()を検索して、deprecate_warn()に置き換えてください。

  4. 新たに非推奨となった関数からdeprecate_soft()を呼び出します。

ドキュメントトピックのバッジを更新することを忘れないでください。

依存する非推奨の機能を確認する

test_check() が呼ばれる直前に tests/testthat.R ファイルで verbosity オプションを設定することにより、あなたのパッケージが非推奨の機能に直接または間接的に依存しているかどうかをテストすることができます。

library(testthat)
library(mypackage)

options(lifecycle_verbosity = "error")
test_check("mypackage")

これにより、非推奨の機能はすべて強制的に失敗するようになります。また、関連するオプションを手動で設定して、セッションで警告やエラーを強制的に発生させることもできます。

# Force silence
options(lifecycle_verbosity = "quiet")

# Force warnings
options(lifecycle_verbosity = "warning")

# Force errors
options(lifecycle_verbosity = "error")

警告の強制は last_warnings() との組み合わせで有用であり、最後のトップレベルコマンドで発行されたすべての非推奨 警告のバックトラックを表示します。

非推奨機能のテスト

lifecycle_verbosity"quiet" に設定することによって、非推奨の機能がまだ動作するかどうかをテストします。

test_that("`baz` argument of `foobar_adder()` still works", {
  withr::local_options(list(lifecycle_verbosity = "quiet"))
  foobar_adder(1, baz = 2)
})

setup()teardown() ブロックの中で testthat ファイル全体に対してメッセージの多さを設定することも可能です。

setup(options(lifecycle_verbosity = "quiet"))
teardown(options(lifecycle_verbosity = NULL))

expect_deprecated() または expect_defunct() を用いて、機能が正しく非推奨であることをテストしてください。

test_that("`baz` argument of `foobar_adder()` is deprecated", {
  expect_deprecated(foobar_adder(1, baz = 2))
})

test_that("`foo()` is defunct", {
  expect_defunct(foo())
})

lifecycle_verbosity オプションを使用すると、メッセージの多さをさらに制御することができます。 ?verbosity をご覧ください。


  1. また、個々の引数や、引数の値の組み合わせに適用することもできます。↩︎

  2. このステージを以前はリタイアと呼んでいました。↩︎

  3. 関数が複数の非推奨段階を経ている場合でも、これは変わりません。↩︎