【发布时间】:2016-10-26 01:28:23
【问题描述】:
有时想要修补包中的一个函数,而不需要重新编译整个包。
例如,在 Emacs ESS 中,如果 tcltk 未加载,函数 install.packages() 可能会卡住。可能需要修补install.packages(),以便在安装前需要tcltk,并在安装包后卸载它。
temp() 的补丁版本 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)
应该重新加载所有内容。但是在重新加载graphics 库时会出现问题,至少在Windows 上是这样:
library(graphics)
# Error in FUN(X[[i]], ...) :
# no such symbol C_contour in package path/to/library/graphics/libs/x64/graphics.dll
哪种是(重新)加载graphics 库的正确方法?
【问题讨论】:
-
您在描述示例目的时迷失了我,但当我看到 eval(parse()) 时我停止阅读。
标签: r