我正在尝试屏蔽包中函数调用的函数。
作为一个可重现的(我认为)示例,请查看函数isTRUE
:
function (x)
identical(TRUE, x)
假设由于某种原因我希望identical
总是返回"foobar"
,因此isTRUE
将始终返回“foobar”:
# 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
之前希望它会失败。但是,myFunc
似乎没有被此欺骗,仍然会调用base::require
而不是require
。
(是的,这似乎是一件微不足道的事情,因为如果我没有安装rgdal,肯定myFunc
肯定会抛出一个错误,但现在假设条件更复杂,我想在同一个地方进行测试方式 - 我的问题仍然存在)
答案 0 :(得分: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')
现在创建函数时, require
被定义为testfun
。
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
(来自mathcoffee - 基于此答案的跟进)。
我能够定义一个函数:
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'))
一个稍微简洁的覆盖功能版本(mnel再次)
overRideIn2 <- function(fun,...){
e <- environment()
.list <- list(...)
ns <- nchar(names(.list))>0L
list2env(.list[ns], envir = e)
fff <- as.function(as.list(fun))
}
答案 1 :(得分:0)
我正在尝试上面解释的 mnel 和 mathematical.coffee 相同的overrideIn
技巧,最后我找到了来自here的另一种选择:
overRideIn3 <- function(fun,...){
e <- environment()
overrides <- list(...)
ns <- nchar(names(overrides)) > 0L
list2env(overrides[ns], envir = e)
environment(fun) <- e
fun
}
请注意,所有这些动态范围设计技巧仅适用于fun
的范围。这意味着fun
调用的任何帮助函数都无法访问overrides
中提供的定义,除非fun
还使用overRideIn
包装这些帮助函数。