从.onLoad包函数中调用getNamespaceExports()

时间:2017-08-31 14:25:46

标签: r scope namespaces package environment

为什么getNamespaceExports().onLoad上下文自动调用而不是从外部代码调用时返回不同的结果?

我们假设我们有一个名为testpackage的R包。此程序包包含一个名为hello.R的R文件,其中包含以下内容:

#' @export
package_var <- "some value"

#' @export
call_when_onload <- function(pkgname) {
  print(getNamespaceExports(pkgname))
  print(do.call("getNamespaceExports",list(pkgname),envir = globalenv()))
}

.onLoad <- function(libname, pkgname){
  print(sprintf("Executing onload procedure for package %s...",pkgname))
  call_when_onload(pkgname)
}

该软件包有一个NAMESPACE文件,如下所示:

# Generated by roxygen2: do not edit by hand

export(call_when_onload)
export(package_var)

现在问题是:在记录和构建包之后,library("testpackage")会返回:

> library(testpackage)
[1] "Executing onload procedure for package testpackage..."
character(0)
character(0)

但是当我调用testpackage::call_when_onload("testpackage")时,我得到以下输出(正如预期的那样):

> testpackage::call_when_onload("testpackage")
[1] "package_var"      "call_when_onload"
[1] "package_var"      "call_when_onload"

为什么呢?如何使.onLoad函数评估上面的表达式,就像它们从外部上下文调用时的评估一样?

1 个答案:

答案 0 :(得分:1)

Per ?.onLoad(强调我的):

  

加载后,loadNamespace会查找名为.onLoad的钩子函数,并在密封命名空间和处理导出之前调用它(带有两个未命名的参数)

所以.onLoad会在从您的包中导出任何内容之前运行。

如果要获取所有导出的对象,一种方法是从包中读取NAMESPACE文件并进行处理:

f <- base::system.file("NAMESPACE", package="pkgname")
objs <- readLines(f)
exps <- objs[grepl("export", objs)]
sub("^export[^\\(]*\\(([^\\)]+)\\)", "\\1", exps)

可能需要进行一些调整才能完全匹配getNamespaceExports的输出。