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

getNamespaceExports() called from within .onLoad package function

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

让我们假设我们有一个名为 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") returns this:

> 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 函数计算上面的表达式,就像它们从外部上下文调用时计算的那样?

根据 ?.onLoad(强调我的):

After loading, loadNamespace looks for a hook function named .onLoad and calls it (with two unnamed arguments) before sealing the namespace and processing exports.

因此 .onLoad 在从您的包中导出任何内容之前运行。

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

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

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