niszetの日記

細かい情報を載せていくブログ

(R) RStudio IDE 上の View() がどこから来ているか調べる (1回目) あるいは RStudio IDEによって置き換えられた関数の一覧など

調べられるところまでは頑張る。

さて、View()で色々見れますよ~という話をしてきましたが、結局このView()はRStudio IDEによって上書きされた関数ということでした(オリジナルはutilsにいる)
さて、こうなってくるとこの関数が一体どこで作られて出てきているのか気になります。ということで調べられるだけ調べていきます。

が、この話は長くなりそうなので何回かに分けて書いていきます。

RStudio IDE上で置き換えられている関数の一覧

現時点で把握している、RStudio IDE上で置き換えられている関数の一覧は下記のとおりです。おそらくこれで全部。 なお、これはGitHub版のソースから判断しています。バイナリ版は少し違います(後述)

grDevices::quartz
utils::history 
utils::loadhistory
utils::savehistory
utils::timestamp
utils::file.edit
utils::View
utils::edit
utils::install.packages
utils::remove.packages

結構あるような、そうでもないような。RStuio IDEのPaneとかに表示されるようなものはまぁ大体上書きされているということですね(考えてみれば当たり前か)

バイナリ版はこれら関数のうちedit()はオリジナルのままです。他は上書きされていることをコンソール上で実行して確認しました。
ということは、次のバージョンあたりで挙動が変わるということですね。

また、grDevices::quartzは使用できないようにしているようです。古いバージョンのRに含まれるのでしょうか、ソースを確認すると、

.rs.addFunction( "disableQuartz", function()
{
  .rs.registerReplaceHook("quartz", "grDevices", function(...) {
    stop(paste("RStudio does not support the quartz device in R <= 2.11.1.",
               "Please upgrade to a newer version of R to use quartz."))
  })
})

ということが書かれています。

なお、View()は下記のリンクの先にある。更新とともにずれていきそうだが…。

github.com

.rs.registerReplaceHook("View", "utils", .rs.viewHook)

Viewはどこにいるのか。

ソースコード上の所在は上に書いた通りです。では実際に実行時にはどこにいるのでしょうか?パッケージ?グローバル環境??

実際にコンソール上で関数名だけで呼べば、environmentが表示されるのでどこにいるのかわかります。

View
#> function (...) 
#> .rs.callAs(name, hook, original, ...)
#> <environment: 0x000000000c62fc40>

…となりますが、environmentはnew.env()で与えられたような値ですね。

親環境を追う

ということでこんどはこの親環境を追っていきます。親環境についてはrlang::env_parents()で見ていくことが出来ます。
この結果はlistで返ってくるので、例によってView()で表示させるとこんな感じになります。

View(rlang::env_parents(environment(View)))

f:id:niszet:20180305224720p:plain

このとき、View()の親の親環境についてAttributesを表示させて該当する行を選択する形で生成された、下のコードを実行して結果を見てみると…

attributes(rlang::env_parents(environment(View))[[2]])[["name"]]
#> [1] "tools:rstudio"

となります。検索するとView()の中にあった.rs.callAs()もここにいることがわかります。RStudioがなんらかの方法で差し込んだ環境であろうといことがわかりますね。

そして、View()自身の環境を見てみると、

View(environment(View))

f:id:niszet:20180305225058p:plain

この環境にはoriginalという変数があり、これは

identical(utils::View, environment(View)[["original"]])
#> [1] TRUE

という結果になるように、本当にオリジナルであるutils::View()であることがわかります。

なんだか少しずつ見えてきました。というか、ソースコード読んだのでもう大体対応関係分かりますよね。OSSのメリットですね。

そんなわけでもう少し見ていきます。長くなってきたので複数回に分けてみます。

Enjoy!!