我试图重写tidy.source包的knitr函数。问题是tidy.source是在由knitr包导入的formatR包中定义的。如果我跑:
get("tidy.source", envir=asNamespace("knitr"))
我知道原始密码了。因此,我很想用以下方法覆盖tidy.source:
assignInNamespace ("tidy.source", function()print("My tidy.source"), "knitr"),
但我明白:
Error in bindingIsLocked(x, ns) : no binding for "tidy.source"。
实际上,tidy.source是在formatR中定义的,并由knitr继承。通过以下方式:
assignInNamespace ("tidy.source", function()print("My tidy.source"), "formatR")
一切看起来都很顺利,但是再次检查get("tidy.source", envir=asNamespace("knitr"))显示,在knitr内部什么都没有改变。
有什么帮助吗?
编辑:
这一问题部分是过时的,因为新的开发版本的针织/成型R。非常感谢一辉注意到这一讨论,并决定更新他的包裹。请参见:
https://github.com/yihui/formatR/commit/6f70360f359caa8d2bb33190a1c89530defb0e98
我绝对可以从瑞典人转到针织者。
无论如何,有关导入包函数的覆盖的一般问题仍然没有解决。由于它不再与编织品/格式R包有关,所以我用更一般的术语重申它。
假设您有一个主要导入包imp的包。如果加载前者,则"package:main"显示在附加包的列表中,"main"和"sub"显示在加载的命名空间的名称中。
假设main导入导出的子函数exp.sub.func,后者依次调用非导出的子函数prv.sub.func。如果您想用您的exp.sub.func更改/自定义exp.sub.func.mod,您可以考虑使用:
assign("exp.sub.func", exp.sub.func.mod, asNamespace ("sub"))因此,通过运行sub::exp.sub.func,您将获得修补版本(即exp.sub.func.mod)。
不幸的是,只要您的exp.sub.func.mod一直依赖于prv.sub.func,您就会得到错误:
Error in [...] : object 'prv.sub.func' not found事实上:
environment(sub::exp.sub.func) 现在返回:<environment: R_GlobalEnv>,而它在修补之前是<environment: namespace:sub>。
问题是:如何将修补好的函数移动到适当的命名空间?
为了实现上面的问题,您当然可以使用任何包;在我的示例中,我使用formatR和tidy.source作为main和导入的命名空间,使用tidy.source()作为修补函数。
发布于 2012-11-28 02:01:07
更改formatR命名空间中的函数不会更改针织r使用的内容,因为已经加载。所以,你可以卸载和重新装载它。
assignInNamespace("tidy.source", function()print("My tidy.source"), "formatR")
detach('package:knitr', unload=TRUE)
library(knitr)
get("tidy.source", envir=asNamespace("knitr"))
#function()print("My tidy.source")发布于 2012-11-30 21:47:37
发布于 2012-11-30 13:53:37
这是一个可能的错误尝试,它允许tidy.source包中包含的函数参数之后的内联注释。
## ============ Possible (wrong?) ideas on inline comments ============
tidy.source.mod= function (source = "clipboard", keep.comment = getOption("keep.comment",
TRUE), keep.blank.line = getOption("keep.blank.line", TRUE),
keep.space = getOption("keep.space", FALSE), replace.assign = getOption("replace.assign",
FALSE), left.brace.newline = getOption("left.brace.newline",
FALSE), reindent.spaces = getOption("reindent.spaces",
4), output = TRUE, text = NULL, width.cutoff = getOption("width"),
...)
{
if (is.null(text)) {
if (source == "clipboard" && Sys.info()["sysname"] ==
"Darwin") {
source = pipe("pbpaste")
}
text = readLines(source, warn = FALSE)
}
if (length(text) == 0L || all(grepl("^\\s*$", text))) {
if (output)
cat("\n", ...)
return(list(text.tidy = "", text.mask = ""))
}
text.lines = text
if (keep.comment) {
if (!keep.space)
text.lines = gsub("^[[:space:]]+|[[:space:]]+$",
"", text.lines)
head.comment = grepl("^[[:space:]]*#", text.lines)
if (any(head.comment)) {
text.lines[head.comment] = gsub("\"", "'", text.lines[head.comment])
}
if (!keep.space) {
head.comment = head.comment & !grepl("^\\s*#+'",
text.lines)
text.lines = reflow_comments(text.lines, head.comment,
width.cutoff)
head.comment = grepl("^[[:space:]]*#", text.lines)
}
text.lines[head.comment] = sprintf("invisible(\"%s%s%s\")",
begin.comment, text.lines[head.comment], end.comment)
blank.line = grepl("^[[:space:]]*$", text.lines)
if (any(blank.line) && keep.blank.line) {
else.line = grep("^[[:space:]]*else(\\W|)", text.lines)
for (i in else.line) {
j = i - 1
while (blank.line[j]) {
blank.line[j] = FALSE
j = j - 1
warning("removed blank line ", j, " (you should not put an 'else' in a separate line!)")
}
}
text.lines[blank.line] = sprintf("invisible(\"%s%s\")",
begin.comment, end.comment)
}
text.lines = mask_inline(text.lines)
}
#modified code
ic=grepl( "%InLiNe_IdEnTiFiEr%", text.lines)
text.lines[ic]=substr(text.lines[ic], 1, nchar(text.lines[ic])-1)
text.lines[ic]= paste0(text.lines[ic], "%InLiNe_IdEnTiFiEr_mod%\"")
#end modified code
text.mask = tidy_block(text.lines, width.cutoff, replace.assign)
text.tidy = if (keep.comment)
unmask.source(text.mask)
else text.mask
text.tidy = reindent_lines(text.tidy, reindent.spaces)
if (left.brace.newline)
text.tidy = move_leftbrace(text.tidy, reindent.spaces)
#modified code
text.tidy= unlist(sapply(text.tidy, strsplit, "%InLiNe_IdEnTiFiEr_mod%", USE.NAMES=FALSE))
#end modified code
if (output)
cat(paste(text.tidy, collapse = "\n"), "\n", ...)
invisible(list(text.tidy = text.tidy, text.mask = text.mask))
}
## ====================================================
## ============ Implementation ============
## Clean-up
if("formatR" %in% loadedNamespaces() ) detach('package:formatR', unload=TRUE)
if(exists("tidy.source"))rm(tidy.source)
library("formatR")
## String with inline comments after arguments
text.input="paste(1 # comm
,7)
"
## The same in vector format
text.input=strsplit(text.input, "\n")[[1]]
## Implementation without patch
tidy.source(text=text.input) #newline removed with wrong result!
# paste(1 # comm, 7)
# Tentative patch
unlockBinding("tidy.source", as.environment("package:formatR") )
assign("tidy.source", tidy.source.mod, pos="package:formatR")
environment(tidy.source)= asNamespace( "formatR" )
## Implementation with patch
tidy.source(text=text.input) # apparently ok:
# paste(1 # comm
# , 7) https://stackoverflow.com/questions/13595145
复制相似问题