覚え書き:私が考えた最強のRパッケージ作成方法 (2022年12月版)

 仕事の都合でRパッケージを作ることがあるんだけど、そのたびに作り方を忘れていることに気づき右往左往する羽目になる。自分のための覚え書きとして、Rパッケージをつくるための手順をメモしておく。
 あくまでの私のためのメモなので、レベルの低さに驚愕したとしても、内緒にしておいてください。

第一夜
 まずは、Rパッケージのひな型を作成しよう。
 なお、以下の手順では次のように想定している。そうでない場合は適宜修正すること。

  • 関係者にアーカイブを配るだけ、CRANやGithubで公開することはない
  • パッケージのライセンスはプロプライエタリ
  • Gitは使うがリポジトリはローカル
  • NAMESPACEはRoxygenで生成
  • Markdown記法を使う
  • NEWSとVignetteはつけるがREADMEはつけない
  • testthatパッケージを使う

 手順は以下の通り。

  1. RStudioを立ち上げ、[New Project]-[New Directory]-[R Package]を選ぶ。パッケージ名と親ディレクトリを指定。親ディレクトリのフルパスに日本語がはいっているとたぶん駄目(R CMD checkがエラーになると思う)。”Create a git repository”をチェック。
  2. [Build]-[Configure Build Tool]を選ぶ。”Generate documention with Roxygen”をチェック。
  3. コンソールから以下を実行する:
    1. usethis::use_namespace()。「お前は気が確かか」というようなことを聞いてくるので「いいからやれ」と答える。
    2. usethis::use_proprietary_license(copyright_holder = “社名”)
    3. usethis::use_testthat()
    4. usethis::use_test(“dummy”)
    5. usethis::use_vignette(“vitnetteのタイトル”)
    6. usethis::use_news_md()。いまcommitするかどうか聞いてくるので、”Not now”のような選択肢を選ぶ。
  4. DESCRIPTIONの編集。Title, Author, Maintainer, Descriptionを書く。
  5. R/hello.R, man/hello.Rdを消す
  6. 以下でエラーが出ないことを確認する。
    1. パッケージをインストール(Ctrl+Shift+B)
    2. パッケージをテスト(Ctrl+Shift+T)
    3. パッケージをチェック(Ctrl+Shift+E)
  7. Gitペインで、すべてを選択して[commit]。commit messageにはなにか適当に書く。”first commit”とか。
  8. [Build]-[Build Source Package]を選択し、パッケージファイルを作成する。以後、開発の進捗を問われた際には、パッケージファイルの存在を示し、あたかも謙遜しているような口調で「これが作成中のRパッケージです。このバージョンではまだなにも実装できていませんが…」というとよい。
  9. ひと仕事済ませたという充足感を感じつつ、プロジェクトを閉じる。

第二夜
 これから作成するRパッケージが提供すべき機能を実装する。
 以下の説明では次のように想定している。そうでない場合は適宜修正すること。

  • Rパッケージが提供すべき関数・データはせいぜい両手両足で数えられるくらいの数しかない
  • すべて自分一人で開発する
  • 開発は一晩で終わるはずである

 手順は以下の通り。

  1. Rパッケージを作ろうという気持ちを一切捨てる。前夜につくったRパッケージのプロジェクトは開かず、別のプロジェクトを開け。おまえがいつもそうしているように、必要なすべての関数を書き、必要なすべてのデータを生成しろ。ドキュメントを書き、テストし、デバッグしろ。
  2. 開発が一晩で終わるわけがない。いくつもの夜がおまえを過ぎ去るだろう。おまえはふと、ここまでにできたところだけもちょっとパッケージにしてみようかな? などと思うかもしれない。やめろ。おまえは仕事に飽きていて、そこから逃げ出し、ちょっと目先の異なる作業をしたいだけなのだ。顔を洗え。茶をいれろ。そしてコーディングを続けろ。必要なすべての関数を書きあげ、必要なすべてのデータを生成するのだ。
  3. 繰り返す。Rパッケージを作ろうという気持ちを捨てろ。 いまここで余計なことを考えるな。

第n夜
 ほんとうにRパッケージをつくる。
 以下の説明では次のように想定している。そうでない場合は適宜修正すること。

  • 依存性については深く考えず、使いたいパッケージをどんどん使う
  • テストのこともあとで考える

 手順は以下の通り。

  1. Rパッケージのプロジェクトと、開発中のプロジェクトの両方を開く。前夜までに書いた関数を、Rパッケージのフォルダ R/ の下にひとつづつ移していき、各関数のドキュメントをroxygen2フォーマットに書き換える。library()やrequire()を @import か @importFrom に書き換える。インポートした関数は bar()ではなく foo::bar()と書く。
  2. tidyverseは使わないに越したことはないが、もし使うんなら、tidyverseではなく個別のパッケージをインポートする。%>% を使うなら usethis::use_pipe()。@importFrom rlang .data としておき、裸の変数名の前には.data$と書く。(話はちがうが、tidyr::complete()とかをパッケージ内で使うときの書き方がわからない… 裸の変数名を書くとチェック時に怒られるし、.data$変数名 では通らないし…)
  3. ライブラリを新しくインポートするたびにドキュメントを生成する(CTRL+SHIFT+D)。たびたびドキュメント生成が必要になるのというのは変な気分なんだけど、NAMESPACEをdevtools::document()で生成してるんだから当然のことである。
  4. 初めて使うパッケージはDESCRIPTIONSに追加する。これもなんだか奇妙な気分になるのだが、devtools::document()はNAMESPACEの面倒はみるがDESCRIPTIONSの面倒はみてくれない。usethis::use_package()を使えばいいのだろうか?
  5. 関数をひとつ移植するたびにロードし(CTRL+SHIFT+L)、動作をチェックする。チェック用に書き散らすコードは /tools の下に置く。ここはどうやら治外法権で、適当にファイルを作っても文句を言われない。
  6. ときどきインストールし(Ctrl+Shift+B)、さらにときどきチェックする(Ctrl+Shift+E)。チェックにはそれなりの時間がかかるので面倒なのだが、かといってあまりに間が空くと、それはそれで山のように文句を言われる羽目になる。
  7. データ・オブジェクトを作る手順は以下の通り。(1) usethis::use_data_raw()。(2) /data-raw にRファイルをつくり、そのなかでオブジェクトを生成する。元になるcsvファイルだのなんだのを置いてもよい。(3) usethis::use_data(オブジェクト名)。(4)/Rの下に (オブジェクト名).Rをつくり、ドキュメントを書く。(あれ? use_data()でテンプレートが生成されたっけ?)
  8. 外部データを含める場合は inst/extdata/ に置く。ファイルの場所はsystem.file(“extdata”, (ファイル名), package = (パッケージ名))でわかるのだが、ついでにそのファイルのパスを返す関数を実装してしまうのがよいかもしれない。
  9. コードを改善しようという気持ちを捨てる。Rパッケージへの移植はそれなりに面倒な作業なので、そこに集中したほうが良い。自分は昨夜までの自分に雇われた人だと自分に言い聞かせ、なにか音楽でも聴きながら作業すると良い。「このコードを書いた奴は~、あほだ~、あほだ~」といった歌を即興で唄いながら作業するのもよいだろう。

最終夜
 ドキュメントを整備する。
 以下の説明では次のように想定している。そうでない場合は適宜修正すること。

  • この辺になるともう精神的に煮詰まっている
  • 疲れた
  • 眠い
  1. vignetteを書く。ここも自分のベスト・プラクティスが定まらず困惑しているくだりなんだけど… latexでなにかを書いているときには、ほとんど段落ごとにコンパイルしてしまう私だが(昔のlatexはコンパイルが速かったんです…)、knitrで毎回knitするのは時間がかかって仕方ない。とりあえず全体を書き終えるまでは我慢したほうがよさそうだ。
  2. vignetteを書きながらRコードを修正するのはよくない。ロードしただけでは反映されず、いちいちインストールしなければならないからだ。とはいえ、他人様向けの説明を書いていると、あれこれと反省点が出てくるんですよね…。上述の歌でも唄ったほうがいいのかもしれない。
  3. knitrのキャッシュについて考えるのは時間の無駄である。あれは黒魔術であり、人間の思い通りには決して動かないものなのだ。処理に時間のかかるチャンクは、一度だけ走らせ、その結果をどこかにrdsで保存し、そのチャンクはeval=FALSEにし、その下にそのrdsをこっそり読み込むチャンクを書いてecho=FALSEにする。以後のknitには処理中のコンソール出力は含まれなくなるし、そもそもこのvignetteは他のコンピュータではビルドできなくなってしまうけど、人生に完璧というものはない。
  4. なんでもいいからいったん区切りをつけよう。/tools の下を片付け、DESCRIPTIONSのバージョン番号をちょっぴり上げ、newsを書き、ソースパッケージをビルドする。おめでとう、最初のバージョンの完成だ。
  5. RStudioを閉じ、パソコンを落とし、風呂に入り歯を磨き電気を消して寝る。俺たちの戦いは明日以降からだ!