我可能接近解决方案,但我必须处理非导出的formatR函数。事实上,原始的tidy.source代码以及补丁版本调用了非导出的包函数,例如reflow_comments
.
为了说明问题和我遵循的步骤,让我们从一个测试补丁的tidy.source开始,它调用一个私有 formatR函数。
### Listing 1 - Modified tidy.source
tidy.source.mod=function (source, output, text){
#Print body first line of reflow_comments
head(reflow_comments,1)
}
source, output, text
参数是必需的,因为前面使用的knit传递。
现在我可以用tidy.source.mod修补tidy.source:
### Listing 2 - Patch tidy.source
## General clean up
if("knitr" %in% loadedNamespaces() ) detach('package:knitr', unload=TRUE)
if("formatR" %in% loadedNamespaces() ) detach('package:formatR', unload=TRUE)
if(exists("tidy.source"))rm(tidy.source)
library("formatR")
## Info
environment(tidy.source )
# <environment: namespace:formatR>
environment(formatR::tidy.source )
# <environment: namespace:formatR>
## Change tidy.source with tidy.source.mod
unlockBinding("tidy.source", env=as.environment("package:formatR"))
assign("tidy.source", tidy.source.mod, envir=as.environment("package:formatR"))
lockBinding("tidy.source", env=as.environment("package:formatR"))
unlockBinding("tidy.source", env=asNamespace ("formatR"))
assign("tidy.source", tidy.source.mod, asNamespace ("formatR") )
environment(tidy.source)= asNamespace( "formatR" )
lockBinding("tidy.source", env=asNamespace ("formatR"))
我们可以检查结果:
### Listing 3 - Check results
getAnywhere(tidy.source)
# A single object matching 'tidy.source' was found
# It was found in the following places
# .GlobalEnv
# package:formatR
# namespace:formatR
# with value
# function (){
# head(reflow_comments,1)
# }
# <environment: namespace:formatR>
tidy.source()
# 1 function (text, idx = grepl("^\\\\s*#+", text), width = getOption("width"))
显然tidy.source已正确替换为tidy.source.mod;命名空间已更新,因此tidy.source可以访问(第一行)非导出 reflow_comments
函数。
为了处理knitr,我们还需要一个文件来编织,为了简单起见,这里我使用了一个文本字符串。
### Listing 4 - Sample file/text to knit
library("knitr")
text="
\\documentclass{article}
\\begin{document}
<<comme, include=TRUE>>=
print('hello')
@
\\end{document}
"
knitr是否能够看到修补的tidy.source?我们可以在 R debug的帮助下进行检查。
debug(knit)
knit(text=text) #will enter debug session (prompt s'd be like 'Browse[2]>')
# debugging in: knit(text = text)
# debug: {
# knit body, very long, omitted
# }
tidy.source #command given inside the debug session
# function (){
# head(reflow_comments,1)
# }
tidy.source() # :-( reflow_comments is not accessible
Q #quit debug session
undebug(knit)
不幸的是,从knit中可以看到修补的tidy.source,但它无法访问未导出的formatR函数,这对于knit通常可以通过未修补的tidy.source 进行。
这里的一些提示可能也formatR::tidy.source()
不起作用:
formatR::tidy.source()
# Error in head(reflow_comments, 1) (from #2) : object 'reflow_comments' not found
namespace:formatR的环境是:
environment(formatR::tidy.source )
# <environment: R_GlobalEnv>
那是<environment: namespace:formatR>
在打补丁之前(参见清单 2 中的信息)。虽然environment(tidy.source )
在修补时很容易重置,但对于namespace:formatR我们得到一个错误:
environment(formatR::tidy.source )=asNamespace( "formatR" )
# Error in environment(formatR::tidy.source) = asNamespace("formatR") :
# object 'formatR' not found
我还在寻找......