2011-11-20 17 views
11

第三者パッケージ(CRANのライブラリ)内に存在する関数PackageFuncAを呼び出すとします。 PackageFuncAは同じサードパーティパッケージ内でPackageFuncBを呼び出します。 PackageFuncBを呼び出すときに実際にPackageFuncBの独自の実装を呼び出すような方法で、PackageFuncAを呼び出すことはできますか?つまり、私はPackageFuncBへの呼び出しを傍受できますか?パッケージ関数内のリダイレクト/インターセプト関数呼び出し

解決策は自分自身のPackageFuncB関数を作成し、PackageFuncAの環境ではなく同じ環境内でPackageFuncAを呼び出すことですが、do.callやevalで動作するようにはできませんでした。

+0

独自のPackageFunAを作成し、代わりに関数を呼び出すようにPackageFunBの呼び出しを変更する方が簡単でしょうか? – joran

+0

'?assignInNamespace'を参照してください – Andrie

+0

joran - 私は自分のバージョンのPackageFuncAを保守したくないでしょう。 – SFun28

答えて

10

これは、これを行う1つのライナーです。ここでPackageFuncAstats::acfであり、PackageFuncBはと置き換えたいstats:::plot.acfです。 my.plot.acf"Hello"を出力し、次に実数stats:::plot.acfを呼び出します。

# we want this to run in place of stats:::plot.acf 
my.plot.acf <- function(x, ...) { cat("Hello\n"); stats:::plot.acf(x, ...) } 

# this does it 
library(proto) 
acf <- with(proto(environment(acf), acf = stats::acf, plot.acf = my.plot.acf), acf) 

# test 
acf(1:10) 

プロト・オブジェクトは、proto関数を介してオブジェクトに挿入された機能は、その環境が自動的にそのオブジェクトにリセットしているような環境です。 proto()の最初の引数はprotoオブジェクトの親です。

上記の例では、acfという変数がprotoオブジェクトに挿入されたacfのバージョンを参照するように設定されています(これは、その環境がprotoオブジェクトに変更されていることを除いて)。新しいacf関数が実行されると、plot.acfは空き変数(acfで定義されていない)なので、acfの親で参照され、それは新しいplot.acfが見つかるprotoオブジェクトの環境です。 acfには他のフリー変数が含まれているかもしれませんが、protoオブジェクトに見つからないため、オリジナルの元の環境であるprotoオブジェクトの親を調べますacf

environment(stats::acf) <- proto object <- revised acf 

とプロトオブジェクトがplot.acfと改訂acfの両方が含まれています。図の面では、我々は<-が左サイドを意味し、これは右側の親である必要があります。

また、新しいplot.acfの環境をprotoオブジェクトに設定しました。私たちはこれをする必要があってもいなくてもよいでしょう。多くの場合、それは重要ではありません。この例では

acf <- with(p <- proto(environment(acf), acf = stats::acf), acf) 
p[["plot.acf"]] <- my.plot.acf 

、両方の仕事に近づく:それは新しいplot.acfの環境を設定しないことが重要だった場合、それがprotoは[[...]]を使用して挿入機能の環境を設定したことがないので、次のように行われます。

数行のコードを使用することを犠牲にしてプレーンな環境でこのすべてを行うことが可能であろう:私たちはプロトのようにeに改定acfを置いていないこの場合

# create new environment whose parent is the original acf's parent 
e <- new.env(parent = environment(stats::acf)) 

# the next statement is only need to overwrite any acf you already might have from 
# trying other code. If you were sure there was no revised acf already defined 
# then the next line could be omitted. Its a bit safer to include it. 
acf <- stats::acf 

# This sets the environment of the new acf. If there were no acf already here 
# then it would copy it from stats::acf . 
environment(acf) <- e 

# may or may not need next statement. In this case it doesn't matter. 
environment(my.plot.acf) <- e 

e$plot.acf <- my.plot.acf 

acf(1:10) 

を親を設定するだけです。実際には、acfeまたはprotoオブジェクトに配置することは厳密には必要ではありませんが、protoの場合は環境を再設定するという副作用があり、その後の副作用があったため、protoの場合のみ実行されました。一方、修正されたplot.acfeまたはprotoオブジェクトに置き、元のオブジェクトに先立って遭遇するようにする必要があります。

paperを参照してください。ここで示すテクニックはプロキシオブジェクトの例であるため、特にプロキシ開始ページ21を参照してください。

+0

リダイレクトしたい1つのインスタンスで、私のコードの他の部分でPackageFuncBの機能に影響を与えたくない!私はなぜこれを見つめなければならないのか分かりません。あなたの時間があれば、何が起こっているのかの簡単な説明は大きな助けになるでしょう。 – SFun28

+0

ok。いくつかの精緻化を追加しました。 –

+0

これは素晴らしいです!本当にありがとう – SFun28

0

PackageFuncAの新しいコピーを作成し、環境をリセットし、独自のバージョンのPackageFuncBを作成してください。

environment(PackageFuncA) <- globalenv() # makes a new copy of PackageFuncA 

PackageFuncB <- function(...) .... # will be called from your new PackageFuncA 

PackageFuncAが元のパッケージからアンエクスポート機能を使用する場合は、編集のビットを行うために必要がある場合があります。また、新しいPackageFuncBを別の場所で使用したくない場合は、グローバル環境に置く代わりに、新しいPackageFuncAの中にラップすることもできます。

関連する問題