4

パッケージの関数が呼び出す関数をマスクしようとしています。

再現可能な(私が思う)例として、関数を見てくださいisTRUE

function (x) 
identical(TRUE, x)

何らかの理由で常に を返したいidenticalとします。したがって、常に「foobar」を返します。"foobar"isTRUE

# try override identical
identical <- function(...) { return('foobar') }
identical(TRUE, 'a') # 'foobar', as expected

今、私は を呼び出し、その関数内の への呼び出しが私のマスクされたバージョンにアクセスするisTRUEことを期待していますが、そうではありません:identical

isTRUE('a') # hope that this will return 'foobar'
# [1] FALSE

一般に、パッケージ化された関数内から呼び出された関数が一時的に別のものを返すようにするにはどうすればよいでしょうか?

環境

パッケージに関数があります:

myFunc <- function(...) {
    if (!require(rgdal)) {
        stop("You do not have rgdal installed")
    }
    # ...
}

rgdal がインストールされていない場合、関数がエラーをスローすることをテストしたいと思います。ただし、rgdal がインストールされています。(一時的に)そうではないと思いたいmyFuncので、やろうとしています:

require <- function(...) { return(FALSE) }

myFunc失敗することを期待して呼び出す前に。ただし、はこれにだまされず、 my の代わりにmyFuncまだ呼び出しているようです。base::requirerequire

(はい、これは些細なことのように思えます。myFuncなぜなら、rgdal がインストールされていない場合、ほとんどの場合エラーがスローされるからです。しかし、条件がより複雑になり、同じ方法でテストしたいとします。私の質問はまだ残っています)

4

2 に答える 2

2

プログラムで関数を作成できます

foo <- function(...) if(!require('MASS')) stop('foo')

testfun <- function(fun){
  require <- function(...) FALSE
  fff <- function(){}
    formals(fff) <- formals(fun)
    body(fff) <- body(fun)
  fff

}

testfoo <- testfun('foo')

requiretestfun関数が作成された時点でそのまま定義されます。

foo()
## Loading required package: MASS

detach(package:MASS)

testfoo()
# Error in testfoo() : foo

で似たようなことができますがlocal、もっと面倒だと思います

例えば

testfoo2 <- local({
  require <- function(...) FALSE
  foo <- function(...) if(!require('MASS')) stop('foo')
  })

testfoo2()
## Error in testfoo2() : foo

(mathematicacoffee から - この回答に基づくフォローアップ)。

関数を定義できました:

overrideIn <- function(f, ...) {                                                
    overrides <- list(...)                                                      
    nms <- names(overrides)[names(overrides) != '']                             
    # stub out the functions                                                    
    for (nm in nms) {                                                           
        assign(nm, overrides[[nm]])                                             
    }                                                                           

    # copy over f                                                               
    fff <- function () {}                                                       
    formals(fff) <- formals(f)                                                  
    body(fff) <- body(f)                                                        
    return(fff)                                                                 
}

私ができるように

f <- overrideIn(myFunc, require=function (...) FALSE)

今私が呼び出すfと、オーバーライドされたバージョンがrequire含まれているので、次のことができます(素晴らしいtestthatパッケージを使用して):

expect_that(f(), throws_error('You do not have rgdal installed'))

overide 関数のもう少し簡潔なバージョン (再び mnel)

overRideIn2 <- function(fun,...){
   e <- environment()
   .list <- list(...)
   ns <- nchar(names(.list))>0L

   list2env(.list[ns], envir = e) 

   fff <- as.function(as.list(fun))

  }
于 2013-03-07T03:04:29.047 に答える