Heavy Watal

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

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

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

Rパッケージ

http://r-pkgs.had.co.nz/

最低限の作成手順

  1. Rを起動して devtools をインストールする

    install.packages('devtools')
    library(devtools)
  2. devtools::create() で骨組みを作る

    setwd('~/tmp/')
    pkgname = 'namaespace'
    title_desc = 'Utility to create dummy R packages for namespace'
    github_repo = sprintf('https://github.com/heavywatal/%s', pkgname)
    devtools::create(pkgname, description=list(
        Package=pkgname,
        Title=title_desc,
        Description=paste0(title_desc, '.'),
        `Authors@R`="person('Watal M.', 'Iwasaki', email='user@example.com', role=c('aut', 'cre'))",
        License='MIT',
        Suggests='tidyverse',
        Imports='devtools, stringr',
        URL=github_repo,
        BugReports=paste0(github_repo, '/issues'))
  3. devtools::check(pkgname) で様子を見てみる

    LaTeX 関連で怒られたら足りないパッケージを入れる: sudo tlmgr install inconsolata helvetic

  4. GitHubに空のリポジトリを作る

    • パッケージと同名でなくてもよい
    • READMELICENSE は後から作る
  5. コミットしてプッシュ

    % git init
    % git add --all
    % git commit -m "first commit"
    % git remote add origin git@github.com:heavywatal/namaespace.git
    % git push -u origin master
  6. とりあえず誰でもインストール可能なパッケージができたはず

    install_github('heavywatal/namaespace')
  7. あとは R/ にソースコードを置いたり README.md を書いたり

構造

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で表示できるので表現力豊か。

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

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

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

https://github.com/hadley/devtools

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

関数

create(path, description=getOption('devtools.desc'), check=FALSE, rstudio=TRUE)
まっさらな状態から骨組みを作る。 path が既に存在している場合は先に進めないので、 やり直すときは system('rm -rf path') などとして一旦消す必要がある。
document(pkg='.', ...)
roxygen2 を呼び出してソースコードから NAMESPACEman/*.Rd を自動生成する
check(pkg='.', document=TRUE, cleanup=TRUE, cran=TRUE, check_version=FALSE, ...)
パッケージとしての整合性を確認。 document()も呼ばれる。
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
#' @export
#' @param x A numeric vector
#' @return A numeric vector
#' @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引数の記述を別の関数から継承する。 継承の連鎖はしないので、親関数で@param定義されてないものはダメ。
@return description
関数の返り値。
@examples code...
例となるコードを記述する。 exportしないやつには書いてはいけない。 単数形の @example は外部ファイルのパスを受け取る
@rdname basename
man/に書き出すRdファイルの名前。 複数の関数で同じものを指定すればひとつのヘルプにまとめられる。 このとき@paramなどは共有されるので、 同じ名前のものはどこかで1度だけ記述する。 逆に言えば、中身が違うものに同じ名前をつけてはいけないし、 引数や機能がほとんど重ならない関数をまとめると分かりにくくなる。
@docType
関数やクラスには不要だが datapackage の場合はここで指定。
@name name
パッケージやデータはこのタグで明示的に設定する必要がある。

関連書籍