2012-01-06 15 views
19

私は、パッケージとそのパッケージを利用し、外部依存関係を識別するスクリプトを調べています。目的は、スクリプトを変更してlibrary(pkgName)を指定し、パッケージ内の関数をrequire(pkgName)に変更して、後でこれらの依存関係を明らかにすることです。R関数とスクリプトの依存関係を確認する

私は、コードを外部依存の各パッケージを考慮して改訂しています。一例として、決定的なものではありませんが、私は現在、data.tableに依存するコードを特定するのが難しいと判断しています。 data.tableMatrix,ggplot2,bigmemory,plyrなど多くのパッケージに置き換えることができますので、他のパッケージに基づいて例を挙げてお答えください。

この検索は特に簡単ではありません。私がこれまで試してみましたアプローチは、次のとおりです

  • は、検索がdata.tableの言及libraryrequire
  • のコードを検索する(例えばlibrary(data.table)
  • は、いくつかの問題があるかもしれない場所を決定するcodetools::checkUsageを実行してみてください。スクリプトの場合、私のプログラムはスクリプトをローカル関数に挿入し、その関数にcheckUsageを適用します。それ以外の場合は、パッケージにcheckUsagePackageを使用します。
  • :=のように、data.tableにいくぶんユニークな文を探します。オブジェクトのクラスはハンガリアン記法を介して識別することができるため
  • 見、
私の検索の本質を見つけることです

などDT:名前の

  • ロード、data.table
  • オブジェクトをそれらがdata.tableオブジェクトであることを示し、
  • data.table特有の方法

これの唯一の簡単な部分は、パッケージがロードされている場所を見つけているようです。残念ながら、すべての関数が明示的に外部パッケージをロードしたり、必要とするわけではありません。これは悪い習慣であり、私はそれを修正しようとしています。しかし、オブジェクトやメソッドの検索は難しいようです。

この(data.table)は1つのパッケージであり、1つは制限されていると思われ、ややユニークな使い方です。オプションがより広範で、構文のテキストが特有のものではない(すなわち、+の頻繁な使用は特有のものではなく、:=のように見える)ggplot関数の使用を探したいとします。

私は静的解析が完全な答えを与えるとは考えていません。関数に引数を渡すことができます。この引数は、ロードされるパッケージを指定します。それにもかかわらず、静的解析や動的解析のいずれかによって、このブルートフォース手法で改善できるコアツールやパッケージはありますか?

tools::pkgDependsは、機能レベルやスクリプトレベル(私が作業しているレベル)ではなく、パッケージレベルの依存関係のみを扱います。


更新1:動作するはずの動的解析ツールの例は、コード実行中に読み込まれるパッケージを報告するものです。しかし、そのような機能がRに存在するかどうかはわかりません。Rprofはコードスタックの代わりにsearch()の出力を報告するようなものになります。

+3

'mvbutils'パッケージで' foodweb'を試してみませんか?私はそれ自身で経験がありませんが、それは私には有望なようです(私はそれがどれだけ深く検索しているかは分かりません)。 'foodweb(where = 'package:data.table'、prune = 'function_youre_examining')のようなもの? –

+0

@ mathematical.coffeeそれは非常に興味深いです。それは非常に有用なインパッケージと思われる。私はパッケージ間で何ができるのかはっきりしていませんが、私はそれに渦を立てます。ありがとう! – Iterator

+0

@ mathematical.coffeeこれは非常に興味深いです。私はそれをもう少し遠ざけています。あなたは答えとしてコメントを投稿できますか?私は、それを動作させることができると仮定して、それをソリューションに編集する手助けをするかもしれません。以前はパッケージ全体で動作していないようですが、それは正しくありません。 'where'引数は検索スペースを管理するためのトリックをするようです。 Btw、changed.funsのヘルプは、私の最近の経験のいくつかを書いているように、ほぼ読んでいます。 :) – Iterator

答えて

13

まず、Mark Bravingtonのmvbutilsパッケージを使用する道を私に任せてくれた@ mathematical.coffeeに感謝します。 foodwebの機能はそれ以上のものです。要約すると

、私は1つのパッケージをチェックについてについて知りたいと思った、別の対myPackageを言う、externalPackageは、とexternalPackageに対してスクリプトをチェックについて言います。それぞれを行う方法を実演します。この場合、外部パッケージはdata.tableです。

1:data.tablemyPackageについては、次のコマンドで十分:

library(mvbutils) 
library(myPackage) 
library(data.table) 
ixWhere <- match(c("myPackage","data.table"), search()) 
foodweb(where = ixWhere, prune = ls("package:data.table"), descendents = FALSE) 

これは機能がdata.tableの関数に依存優れ示すグラフを生成します。グラフにはdata.tableの依存関係が含まれていますが、あまりにも負担はありません。に依存する関数と、それらが使用する関数、例えば,、data.table、、keyなどを簡単に見ることができます。この時点で、パッケージの依存関係の問題は解決されたと言えるかもしれませんが、foodwebにはこれ以上のものがありますので、それを見てみましょう。クールな部分は依存関係行列です。

depMat <- foodweb(where = ixWhere, prune = ls("package:data.table"), descendents = FALSE, plotting = FALSE) 
ix_sel <- grep("^myPackage.",rownames(depMat)) 
depMat <- depMat[ix_sel,] 
depMat <- depMat[,-ix_sel] 
ix_drop <- which(colSums(depMat) == 0) 
depMat <- depMat[,-ix_drop] 
ix_drop <- which(rowSums(depMat) == 0) 
depMat <- depMat[-ix_drop,] 

これはクールです:それは今私は、例えば、冗長な名前を使用しています私のパッケージに機能の依存関係を示しmyPackage.cleanData、on functionは 、つまりdata.tableの関数ではなく、依存関係のない行と列を削除します。これは簡潔であり、依存関係を素早く調べることができ、rownames(depMat)を処理することで、自分の関数の補集合も簡単に見つけることができます。

NB:plotting = FALSE少なくとも最初にfoodwebが一連の呼び出しで呼び出されたときは、プロットデバイスが作成されないようには見えません。それは面倒ですが、ひどいことではありません。たぶん私は間違ったことをしているのかもしれない

2:スクリプトの場合、data.tableに対して、これはもう少し面白いです。スクリプトごとに、一時的な関数を作成し、依存関係をチェックする必要があります。私はちょうどそれを行う以下の少し機能があります。

listFiles <- dir(pattern = "myScript*.r") 
checkScriptDependencies <- function(fname){ 
    require(mvbutils) 
    rawCode <- readLines(fname) 
    toParse <- paste("localFunc <- function(){", paste(rawCode, sep = "\n", collapse = "\n"), "}", sep = "\n", collapse = "") 
    newFunc <- eval(parse(text = toParse)) 
    ix  <- match("data.table",search()) 
    vecPrune <- c("localFunc", ls("package:data.table")) 
    tmpRes <- foodweb(where = c(environment(),ix), prune = vecPrune, plotting = FALSE) 
    tmpMat <- tmpRes$funmat 
    tmpVec <- tmpMat["localFunc",] 
    return(tmpVec) 
} 

listDeps <- list() 
for(selFile in listFiles){ 
    listDeps[[selFile]] <- checkScriptDependencies(selFile) 
} 

は今、私はちょうどlistDepsを見る必要がある、と私は上記depMatから持っている素晴らしい小さな洞察の同じ種類を持っています。私はcheckScriptDependenciesを、他のコードから変更して、codetools::checkUsageによって解析されるスクリプトを送信しました。スタンドアロンコードを分析するために、このような小さな機能を持つのは良いことです。声明をfoodwebに改善した洞察のために@Spacedmanとにenvironment()を使用してください。

(本当のhungaRiansは私が名前と型の順序に矛盾していることに気づくでしょう - tooBad :)これ以上の理由はありますが、これは私が使用しているコードとまったく同じではありません。)


私は私のコードのためにfoodwebによって生成グラフの写真を掲載していませんでしたが、あなたはhttp://web.archive.org/web/20120413190726/http://www.sigmafield.org/2010/09/21/r-function-of-the-day-foodwebでいくつかの素晴らしい例を見ることができます。私の場合、その出力はkeyas.data.tableのような標準的な名前付き関数とともに、:=Jのdata.tableの使用を確実にキャプチャします。それは私のテキスト検索を取り除くようであり、いくつかの点で改善されています(例えば見落としていた機能を見つける)。

すべてfoodwebは優れたツールです。mvbutilsパッケージと、マークブレービングトンの他の素敵なパッケージ(debugなど)をお試しください。 mvbutilsをインストールする場合は、進化するRコードの管理に苦労していると思われる場合は、?changed.funsをチェックしてください。 :)