如何附加包含非导出功能的包?

how to attach a package including the non-exported functions?

当从外部包调试函数时,我经常发现自己将函数复制到一个新的脚本来添加我的更正,但我必须在脚本的开头添加一堆 foo=extpack:::foo函数访问包的内部函数。

在经常更改单行的情况下,克隆和构建包将是一种完全矫枉过正的做法。

有没有办法附加包及其所有内部功能?

类似于library(extpack, attach_nonexported=TRUE)

您可以通过以下操作从包命名空间中获取所有函数作为环境:

getNamespace("ggplot2")

因此您可以将它们附加到您的搜索路径(类似于使用未导出的函数调用 library):

attach(getNamespace("ggplot2"))

如果您喜欢列表中的它们,您可以这样做

as.list(getNamespace("ggplot2"))

或者如果您希望它们出现在全局工作区中,您可以这样做:

list2env(as.list(getNamespace("ggplot2")), globalenv())

不用说,你应该只在交互式会话中而不是在编写包时做这种事情。

修复此类错误的最佳方法是将修改函数的环境设置为与原始环境相同的环境。例如,要修复 extpack::badfn 使用

badfn <- function(...) { ... } # new version in your global workspace

environment(badfn) <- environment(extpack::badfn)

这意味着它在调用时会看到私有函数,但它不会替换原来位置的 extpack::badfn,因此调用它的其他 extpack 函数仍会调用原来的函数一。如果你想让他们打电话给你,请使用

assignInNamespace("badfn", badfn, "extpack")

进行上述更改后。

如果其他包导入 extpack::badfn,它得到的内容将取决于操作的确切顺序,所以在这种情况下,您最好硬着头皮用您的修复重建整个包到位。

如果你真的想模拟库调用,我们可以在包含所有函数的搜索路径上创建一个“package:yourpkg”:

magrittr::as_pipe_fn
#> Error: 'as_pipe_fn' n'est pas un objet exporté depuis 'namespace:magrittr'
magrittr:::as_pipe_fn
#> function (expr, env) 
#> {
#>     eval(call("function", lambda_fmls, expr), env)
#> }
#> <bytecode: 0x0000000013917228>
#> <environment: namespace:magrittr>

attach_all <- function(pkg) {
  pkg <- as.character(substitute(pkg))
  pkg_long <- paste0("package:", pkg)
  eval(bquote(with(
    setNames(list(getNamespace(pkg)), pkg_long), 
    attach(.(as.symbol(pkg_long)))
  )))
}

attach_all(magrittr)

search()
#>  [1] ".GlobalEnv"        "package:magrittr"  "package:stats"    
#>  [4] "package:graphics"  "package:grDevices" "package:utils"    
#>  [7] "package:datasets"  "package:methods"   "Autoloads"        
#> [10] "tools:callr"       "package:base"
as_pipe_fn
#> function (expr, env) 
#> {
#>     eval(call("function", lambda_fmls, expr), env)
#> }
#> <bytecode: 0x0000000013917228>
#> <environment: namespace:magrittr>

reprex package (v0.3.0)

于 2020-10-09 创建

使用起来可能会让你紧张package:mypkg,如果是这样,请随意更改这部分,结果是一样的。

另一种方法是将未导出的函数附加到不同的环境,以便您可以在需要时独立分离它:

attach_unexported <- function(pkg) {
  pkg <- as.character(substitute(pkg))
  all_funs <- lsf.str(asNamespace(pkg))
  exported <- getNamespaceExports(pkg)
  unexported_funs <- setdiff(all_funs, exported)
  pkg_long <- paste0(pkg, "_unexported")
  eval(bquote(with(
    setNames(list(mget(unexported_funs, asNamespace(pkg))), pkg_long), 
    attach(.(as.symbol(pkg_long)))
  )))
}

attach_unexported(magrittr)

search()
#>  [1] ".GlobalEnv"          "magrittr_unexported" "package:stats"      
#>  [4] "package:graphics"    "package:grDevices"   "package:utils"      
#>  [7] "package:datasets"    "package:methods"     "Autoloads"          
#> [10] "tools:callr"         "package:base"
as_pipe_fn
#> function (expr, env) 
#> {
#>     eval(call("function", lambda_fmls, expr), env)
#> }
#> <bytecode: 0x0000000013a05bd0>
#> <environment: namespace:magrittr>

`%>%`
#> Error in eval(expr, envir, enclos): objet '%>%' introuvable

reprex package (v0.3.0)

于 2020-10-09 创建