Heavy Watal

devtools — Rパッケージ作成支援

自分で書いた関数が多くなってきたら、まとめてパッケージを作るとよい。 少しだけ面倒だが、以下のようなメリットがある。

CRANに上げる程ではないとしても、 GitHubに公開しておけば誰でも使えるようになるので、 共同研究者と解析環境を共有したり、 ひとつの論文のワークフローを置いておいたり、いろいろ使い道はある。

Rパッケージ

最低限の作成手順

  1. 開発支援パッケージをインストールする: install.packages(c("devtools", "usethis"))

  2. usethis の関数をいくつか使って骨組みを作る:

    usethis::create_package("hello")
    usethis::use_mit_license()
    usethis::use_roxygen_md()
    usethis::use_package_doc()
  3. devtools::check() で様子を見てみる。 LaTeX 関連で怒られたら足りないパッケージを入れる: sudo tlmgr install inconsolata helvetic

  4. ローカルgitリポジトリを作って最初のコミットをする: usethis::use_git()

  5. GitHubかどこかに空のリポジトリを作る。 パッケージと同名でなくてもよい。

  6. そのリモートリポジトリにプッシュ:

    git remote add origin https::/github.com/heavywatal/rhello.git
    git push -u origin master
  7. とりあえず誰でもインストール可能なパッケージができたはず:

    devtools::install_github('heavywatal/rhello')

構造

DESCRIPTION  # 一番大事
NAMESPACE    # 見せるオブジェクトを列挙
README.md    # 全体の説明を簡単に
R/           # Rソースコード
data/        # サンプルデータなど
exec/        # 実行ファイル
inst/        # CITATION
man/         # ヘルプファイル.Rd
src/         # C++ソースコード
tests/
vignettes/

DESCRIPTION

NAMESPACE

R/ ソースコード

src/ C++ソースコード

その他の注意点

vignettes/

個々の関数の使用例はRソースファイルの @examples に書くとして、 複数の関数を組み合わせてどう使うかとか、 パッケージ全体の使い方とかを説明するのがvignettes/の役割。 Rmarkdown形式で書いてHTMLやPDFで表示できるので表現力豊か。

usethis::use_vignette('hello') で雛形を作ってもらうのが楽。

pandocpandoc-citeproc が必要なので Homebrew とかでインストールしておく。

check()がデフォルトでvignette=TRUEかつ処理がやや重いので、 毎回その重さを受け入れるか、わざわざFALSE指定するかというのは悩みどころ。

inst/

ここに入ってるものはインストール先でトップディレクトリに移される謎仕様。

論文で引用されることを想定している場合は inst/CITATION を作る。 citation('ggplot2') のように参照できるようになる。

demo/

vignettesに取って代わられた古い機能。 ソースコード*.Rを置いておくとdemo()関数で呼び出せるというだけ。

check()でソースコードの中身は実行されないが、 demo/00Index というファイルの整合性が取れてないと警告される。 「デモの名前 + スペース3つ以上かタブ + 適当な説明」という形式。 ファイル名から拡張子を取り除いたものがデモの名前になる。

mydemo1    Description of demo 1
mydemo2    Description of demo 2

人に見せたりtests/に入れたりするほどのもんでもないし、 毎回check()されなくてもいいけど、 試しに書いたコードを一応取っとく、くらいの用途にはいいかな?

devtools

骨組みを作るとこからCRANにデプロイするとこまでお世話してくれる。

主な関数

document(pkg='.', ...)
roxygen2 を呼び出してソースコードから NAMESPACEman/*.Rd を自動生成する。
check(pkg='.', document=TRUE, cleanup=TRUE, cran=TRUE, check_version=FALSE, ...)
パッケージとしての整合性を確認。 ついでにdocument()は実行できるけどspell_check()はできないので手動で。
test(pkg='.', filter=NULL, ...)
testthat を呼び出して test/ 以下のテストコードを実行する
install(pkg='.', reload=TRUE, quick=FALSE, local=TRUE, ...)
ローカルにあるディレクトリからインストール
install_github(repo, username=NULL, ref='master', subdir=NULL, ...)
GitHubリポジトリからインストール
unload(pkg='.')
datach('package:XXX') とか unloadNamespace(XXX) よりもちゃんとまっさらにパッケージを外す。
load_all(pkg='.', reset=TRUE, recompile=FALSE, export_all=TRUE, quiet=FALSE)
install() せずファイルから直接 library() する。 ロード済みでもまず unload() が呼ばれるので安心。
clean_dll(pkg='.')
src/ 以下に生成される .o, .so を消す。 普段は触る必要ないが、たまにこれが必要な不具合に出くわす。

設定

項目の説明を読む

?devtools

例えば .Rprofile

options(devtools.desc.author='Watal M. Iwasaki <user@example.com> [aut, cre]')
options(devtools.desc.license='MIT')

roxygen2

RソースコードのコメントからNAMESPACEとヘルプ(man/*.Rd)を自動生成する。

roxygen2::roxygenise(package.dir='.', ..., clean=FALSE) を直接呼んでもよいが、 基本的には devtools::document() を使って間接的に利用する。

使い方

#' A simple function to add 1
#' @param x A numeric vector
#' @export
#' @examples
#' increment(42)
increment = function(x) {x + 1}

タグ

@import pkg1, pkg2, ...
NAMESPACEimport() するパッケージを指定。 名前の衝突が怖いので基本的に使わない。
@importFrom pkg func
NAMESPACEimportFrom() するパッケージと関数を指定。 e.g., @importFrom magrittr %>%
@export
NAMESPACEexport() する関数を指定。
@param arg1 description...
関数の引数。型や役割の説明を書く。
@inheritParams package::function
@param引数の記述を別の関数から継承する。
@return description
関数の返り値。
@examples code...
例となるコードを記述する。 exportしないやつには書いてはいけない。 \dontrun{} に入れるとチェックから除外される。 単数形の @example は外部ファイルのパスを受け取る
@rdname basename
man/に書き出すRdファイルの名前。 複数の関数で同じものを指定すればひとつのヘルプにまとめられる。 このとき@paramなどは共有されるので、 同じ名前のものはどこかで1度だけ記述する。 逆に言えば、中身が違うものに同じ名前をつけてはいけないし、 引数や機能がほとんど重ならない関数をまとめると分かりにくくなる。
@docType, @name
パッケージやデータを記述するのに必要だったが今では不要っぽい。

関連書籍