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

时间:2020-10-03 09:53:32

标签: r debugging import r-package

从外部程序包调试功能时,我经常发现自己将功能复制到新脚本中以添加我的更正,但是我必须在脚本的开头添加一堆foo=extpack:::foo才能使功能访问软件包的内部功能。

在经常更改一行的情况下,克隆和构建程序包是完全过头了。

有没有办法将包装及其所有内部功能连接起来?

类似library(extpack, attach_nonexported=TRUE)

3 个答案:

答案 0 :(得分:8)

您可以通过以下方式从软件包命名空间中获取所有功能作为环境:

getNamespace("ggplot2")

因此,您可以执行以下操作将它们附加到搜索路径(类似于使用未导出的函数调用library

attach(getNamespace("ggplot2"))

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

as.list(getNamespace("ggplot2"))

或者如果希望它们出现在全局工作区中,则可以执行以下操作:

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

不用说,您应该只在交互式会话中执行这种操作,而不是在编写程序包时。

答案 1 :(得分:3)

如果您真的想模拟库调用,我们可以在包含所有功能的搜索路径上创建一个“ 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创建

答案 2 :(得分:1)

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

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

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

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

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

进行上述更改后。

如果其他软件包导入了extpack::badfn,则其获取的内容将取决于操作的确切顺序,因此,在这种情况下,最好是硬着头皮,并在适当的位置修复整个软件包