備忘ログ

チラシの裏的備忘録&メモ

RのパッケージのREADMEを読む方法を考える(READMEをvignetteにするなど)

Rでパッケージを使っていると、関数の使い方やパッケージの目的などを調べたくなる時がある。そんな時に関数のヘルプドキュメントは重要な情報源となるが、パッケージのREAEMEも大いに役に立つ。

READMEとはパッケージの概要や簡単な使い方などを説明したドキュメントのことで、GitHubで公開されているパッケージならリポジトリのトップに表示されている。CRANでもREAME.mdがあるパッケージではパッケージのページにREADMEの項目があり、参照することができる。

大いに役に立つREADMEながら、READMEを参照するためにはパッケージのウェブページ(CRANやGitHubなどの)にアクセスする必要があり、通常はウェブ検索等でパッケージ名検索しREADMEの項目にアクセスする必要がある。

しかし、ブラウザを立ち上げて検索かけるという手間があり、やや不便である。また、"パッケージ名 R package"と検索しても上位に当該パッケージのウェブページが表示されないため、少し探すのに手間取ることがある。

そこで、パッケージのREADMEを簡便に読みたいと思い、方法を考えた。

方法としては

  • READMEがある(ありそうな)ウェブページにアクセスする関数を作ってREADMEにウェブブラウザをつかってアクセスする。

  • パッケージをインストールする時にREAME.mdの内容をvignetteにコピーする処理を行い、vignette()関数を用いてREAMEを参照できるようにする。

というものを考えた。後者のパッケージをインストール中にREAEME.mdをvignetteにする処理を行う方は現在のところGitHubで公開されているパッケージでしか実行できない(が、CRANからソースからのインストールであれば似たような処理で仕組み上は工夫すればできそうだと思う)。

(追記)CRANリポジトリに公開されているパッケージでもパッケージをインストールする時にREAME.mdの内容をvignetteにコピーする処理を行い、vignette()関数を用いてREAMEを参照できるようにする処理をする関数を追加した。後述。(追記終了)

READMEがある(ありそうな)ウェブページにアクセスする関数を作ってREADMEにウェブブラウザをつかってアクセスする

CRANからインストールされたパッケージであれば、CRANのパッケージのウェブページ上にREADMEがあるはず(なければない)。GitHubからインストールされたパッケージであれば、パッケージをインストールしたリポジトリのページにREADMEがあるはず(なければない)。

ということで、パッケージ名を入力するとインストールされているパッケージのDESCRIPTIONを参照し、CRANからインストールされたのかGitHubからインストールされたのかを判別して、それぞれのページにブラウザでアクセスする関数を作った。

readme <- function(package){
  if(length(package) != 1) stop("Only one package name can be specified.")
  if(!is.character(package)) stop("The package name must be specified as a string.")
  repository_info <- utils::packageDescription(package)[c("Repository", "GithubRepo", "GithubUsername")]
  if(!is.null(repository_info$Repository) && repository_info$Repository == "CRAN")
    utils::browseURL(paste0("https://cran.r-project.org/web/packages/",
                     package,
                     "/readme/README.html"))
  else if(!is.null(repository_info$GithubRepo))
    utils::browseURL(paste0("https://github.com/",
                     repository_info$GithubUsername,
                     "/",
                     repository_info$GithubRepo))
  else stop("Only packages installed from CRAN or GitHub are supported.")
}

この関数はGitHubで公開している{infun}パッケージに追加した。

github.com

これで、例えば{zipangu}パッケージをインストールしている場合、

readme("zipangu")

{zipangu}をCRANからインストールしている場合はCRAN上のREADMEのウェブページ、開発版等をGitHubからインストールしている場合はGitHubリポジトリのウェブページがブラウザで開かれる。

もしREADMEがない場合は表示できない。

パッケージをインストールする時にREAME.mdの内容をvignetteにコピーする処理を行い、vignette()関数を用いてREAMEを参照できるようにする

パッケージをインストールする時に、REAME.mdの内容をvignetteにREADMEとしてコピーする処理を行って、パッケージをインストールするようにする方法を考えた。

この方法はGitHub上で公開している{readme2vignette}install_github_with_readme()を使ってGitHub上で公開されているパッケージをインストールすると実現できる。

(追記)CRANリポジトリにあるパッケージも同様の処理でREAMEをvignetteにコピーするinstall_cran_with_readme(){readme2vignette}に追加した。(追記終了)

github.com

この方法では、README.mdの内容がvignetteとなるので、vignette("README", "パッケージ名")でREADMEをローカル環境で参照することができる。

install.packages("remotes")
remotes::install_github("indenkun/readme2vignette")
# 例えば、MissMechをインストールしてみる
readme2vignette::install_github_with_readme("indenkun/MissMech")

これで、

vignette("README", package = "MissMech")

でREADMEを参照することができる。

{readme2vignette}install_github_with_readme(){remotes}install_github()の処理の途中にREADME.mdの内容をvignette化する処理を挟んでいるだけ。

(追記){readme2vignette}install_cran_with_readme(){remotes}install_cran()の処理の途中にREADME.mdの内容をvignette化する処理を挟んでいる。インストールするパッケージは、途中で処理を挟むために、必ずソースパッケージからインストールする必要があり、バイナリパッケージからのインストールはできない。依存関係でインストールされるパッケージはその限りではない。(追記終了)

ただ、この方法だとパッケージのバージョンアップなどでinstall_github_with_readme()以外でパッケージの再インストールを行うと元々のパッケージがインストールされるのでREADMEのvignetteは消えてしまう。

{readme2vignette}install_github_with_readme()について

{remotes}install_github()は、GitHub上のパッケージをダウンロードしてインストールする関数で、その際にREADME.mdをvignetteにコピーしてくれるようにしたのが{readme2vignette}install_github_with_readme()である。

具体的な処理の流れは以下の通り。

  • README.mdがあるかどうか、vignetteディレクトリがないかどうかを確認する
  • DESCRIPTIONファイルに{knitr}{rmarkdown}パッケージをSuggestsに追加する
  • DESCRIPTIONファイルに{knitr}をVignetteBuilderとして追加する
  • vignetteディレクトリを作成し、README.Rmdを作成する
  • README.Rmdの中身はchild = "../README.md"とする
  • README.Rmd内で、man/figuresディレクトリがあれば、その中身をコピーする
  • install_github()build_vignettes = TRUEとしてvignetteをBuildする

これで、README.mdがない場合やvignetteがすでにある場合は、README.mdのvignette化をスキップし、それ以外のときにはREADME.mdの内容をそのままvignetteにREADMEとして反映させることができる。

ただし、この方法ではman/figuresディレクトリ以外にあるイメージファイルは参照されないので、イメージが欠落してしまう。

また、REAMDE.RmdではなくREADME.mdを参照しているためvignette中のRのコードはsourceで確認できないというデメリットがある。しかし、README.RmdではときどきパッケージのDESCRIPTIONに依存関係として記述されていないパッケージを用いているコードが用いられていたり、環境依存情報を用いている例があり、README.Rmdをレンダリングする時にパッケージ不足でうまく行かない可能性やもともとのREADME.mdとやや異なる結果になる可能性があることから、README.mdを参照することとしている。

雑記

Rのパッケージには、パッケージの目的や使い方を説明するドキュメントとしてREADMEとvignetteの二種類がある。READMEは、パッケージの概要や使い方などを説明したドキュメントで、ウェブページで見ることができる。vignetteは、パッケージの詳細な解説や実例などを含んだHTMLファイルまたはpdfファイルで、ローカル環境で見ることができます。

READMEとvignetteの関係については、パッケージ開発者やユーザーの間で意見が分かれており、READMEとvignetteの違いや役割について、概観しただけでも以下のような議論がある*1*2*3

  • READMEとvignetteのどちらが重要か
  • READMEとvignetteのどちらが優先されるべきか
  • READMEとvignetteのどちらが更新されやすいか
  • READMEとvignetteのどちらが読みやすいか
  • READMEとvignetteのどちらが分かりやすいか
  • READMEとvignetteのどちらが効率的か

これらの議論には一概に正解があるとは言えず、パッケージの目的や内容、開発者のスタイルや意図、ユーザーのニーズや環境などによると思う。

ところで実際のパッケージとしては、vignetteを備えずにREADMEしかないパッケージが多くあるように思っている。README.mdはソースパッケージに含まれて入るので、インストールするときもそのまま取り込んでくれればR本体でローカル環境でもREADMEを読めそうだと思うのだが……。

また、古いISSUEながら{usethis}にパッケージ開発時にREADMEの内容をvignetteにする関数が提案されたこともあったが、採用あいならずという感じのこともあった。

github.com

READMEの内容をヘルプドキュメントに入れている例もある({callr}パッケージなど)。

callr/R/callr-package.R at main · r-lib/callr · GitHub

もちろんちゃんとvignetteを書くべきという議論はありえるが、現状としてREADMEはあるがvignetteはないパッケージが多くあると思うので、なんとかしてREADMEが参照できるといいのではないかと思っている。