R:修补包函数并重新加载基库

时间:2016-10-26 01:28:23

标签: r

偶尔会想要修补程序包中的函数,而无需重新编译整个程序包。

例如,在Emacs ESS中,如果未加载install.packages(),函数tcltk可能会卡住。有人可能希望修补install.packages()以便在安装前需要tcltk并在程序包设置后卸载它。

temp()的{​​{1}}修补版本可能是:

install.packages()

现在我们要替换原来的## Get original args without ending NULL temp=rev(rev(deparse(args(install.packages)))[-1]) temp=paste(paste(temp, collapse="\n"), ## Add code to load tcltk "{", " wasloaded= 'package:tcltk' %in% search()", " require(tcltk)", ## Add orginal body without braces paste(rev(rev(deparse(body(install.packages))[-1])[-1]), collapse="\n"), ## Unload tcltk if it was not loaded before by user " if(!wasloaded) detach('package:tcltk', unload=TRUE)", "}\n", sep="\n") ## Eval patched function temp=eval(parse(text=temp)) # temp ,并可能在install.packages()中插入代码。

为此,没有任何价值:

Rprofile

也就是说,该函数存储在getAnywhere("install.packages") # A single object matching 'install.packages' was found # It was found in the following places # package:utils # namespace:utils # with value # # ... install.packages() source follows (quite lengthy) 的包/命名空间内。此环境是密封的,因此在更换之前应解锁utils

install.packages()

再次使用## Override original function unlockBinding("install.packages", as.environment("package:utils")) assign("install.packages", temp, envir=as.environment("package:utils")) unlockBinding("install.packages", asNamespace("utils")) assign("install.packages", temp, envir=asNamespace("utils")) rm(temp) ,我们得到:

getAnywhere()

看起来补丁功能放在正确的位置。

不幸的是,运行它会给出:

getAnywhere("install.packages")
# A single object matching 'install.packages' was found
# It was found in the following places
#   package:utils
#   namespace:utils
# with value
#  
# ... the *new* install.packages() source follows

Error in install.packages(xxxxx) : could not find function "getDependencies" 是同一个getDependencies()包中的函数,但未导出;因此它不能在其命名空间之外访问 尽管输出utils,但修补后的getAnywhere("install.packages")仍然错位。

问题是我们需要重新加载install.packages()库以获得所需的效果,这也需要卸载导入它的其他库。

utils

detach("package:stats", unload=TRUE) detach("package:graphics", unload=TRUE) detach("package:grDevices", unload=TRUE) detach("package:utils", unload=TRUE) library(utils) 现在有效。

当然,我们也需要重新加载其他库。给定依赖关系,使用

install.packages()

应重新加载所有内容。但重新加载library(stats) 库时出现问题,至少在Windows上是这样的:

graphics

(重新)加载library(graphics) # Error in FUN(X[[i]], ...) : # no such symbol C_contour in package path/to/library/graphics/libs/x64/graphics.dll 库的正确方法是什么?

1 个答案:

答案 0 :(得分:2)

修补程序包中的函数是一个应该避免的低级操作,因为它可能会破坏执行环境的内部假设并导致不可预测的行为/崩溃。如果tck / ESS存在问题(我没有尝试重复),也许它应该修复或者可能有解决方法。特别是更改锁定绑定是需要避免的。

如果您真的想在说install.packages的开头/结尾处运行一些代码,可以使用trace。它将完成问题中提到的一些低级操作,但好的部分是,当R的一些新内部发生变化时,你不必担心修复它。

trace(install.packages, 
    tracer=quote(cat("Starting install.packages\n")),
    exit=quote(cat("Ending install packages.\n"))
)

相应地替换tracerexit - 无论如何都不需要exit,也许您不需要卸载软件包。不过,trace是一个非常有用的调试工具。

我不确定这是否能解决您的问题 - 如果它可以与ESS一起使用 - 但一般情况下您也可以将install.packages包装在您定义的函数中,并在工作区中说:

install.packages <- function(...) {
    cat("Entry.\n")
    on.exit(cat("Exit.\n"))
    utils::install.packages(...)
}

这确实是最干净的选择。