如何在不使用 Depends 或 library() 的情况下使用另一个包中的 S3 方法,该包在其命名空间中使用 export 而不是 S3method
How to use S3 methods from another package which uses export rather than S3method in its namespace without using Depends or library()
我目前正在开发一个 R 包,并试图遵循 Hadley Wickham 在 http://r-pkgs.had.co.nz 提供的最佳实践指南。作为其中的一部分,我的目标是在 DESCRIPTION 文件的 Imports 部分而不是 Depends 中包含所有包依赖项,因为我同意不要不必要地改变全局环境的理念(许多 CRAN 和 Bioconductor 包不这样做) ' 似乎跟随)。
我想在我的一个包函数中使用 Bioconductor 包 rhdf5 中的函数,特别是 h5write()
。我现在 运行 遇到的问题是它没有在其名称空间中声明其 S3 方法。它们是使用(例如)
声明的
export(h5write.default)
export(h5writeDataset.matrix)
而不是
S3method(h5write, default)
S3method(h5writeDataset, matrix)
通用 h5write 定义为:
h5write <- function(obj, file, name, ...) {
res <- UseMethod("h5write")
invisible(res)
}
实际上,这意味着调用 rhdf5::h5write 失败,因为没有注册合适的 h5write 方法。
据我所知,有以下三种解决方案:
- 在 DESCRIPTION 文件中使用
Depends
而不是 Imports
。
- 在相关函数的代码中使用
library("rhdf5")
或require("rhdf5")
。
- 修改 rhdf5 的命名空间文件以使用
S3methods()
而不是 export()
。
所有这些都有缺点。选项 1 意味着包被加载并附加到全局环境,即使我的包中的相关函数从未被调用。选项 2 意味着在包中使用 library
,同时再次将包附加到全局环境,并且根据 Hadley Wickham 的指南也已弃用。选项 3 意味着依赖其他包作者在 Bioconductor 上更新他们的包,也意味着不再导出 S3 方法,这可能反过来破坏依赖于显式调用它们的其他包。
我错过了另一个选择吗?我查看了 Whosebug 的其他地方,发现了以下一些相关的问题 Importing S3 method from another package 和
How to export S3 method so it is available in namespace? 但没有任何内容可以直接解决我的问题。值得注意的是,与这两个中第一个的主要区别在于泛型和方法都在同一个包中,但问题是使用 export
而不是 S3method
.
重现错误的示例代码(无需创建包):
loadNamespace("rhdf5")
rdhf5::h5write(1:4, "test.h5", "test")
Error in UseMethod("h5write") :
no applicable method for 'h5write' applied to an object of class
"c('integer', 'numeric')
或者,https://github.com/NikNakk/s3issuedemo 处有一个框架包,它提供了一个单一的函数 demonstrateIssue()
来重现错误消息。可以使用 devtools::install_github("NikNakk/s3issuedemo")
.
安装
这里的关键是除了要使用的泛型之外,还要导入特定的方法。以下是如何让它为默认方法工作。
注意:这假设test.h5
文件已经存在。
#' @importFrom rhdf5 h5write.default
#' @importFrom rhdf5 h5write
#' @export
myFun <- function(){
h5write(1:4, "test.h5", "test")
}
我也贴出了我自己的小包来演示这个here。
我目前正在开发一个 R 包,并试图遵循 Hadley Wickham 在 http://r-pkgs.had.co.nz 提供的最佳实践指南。作为其中的一部分,我的目标是在 DESCRIPTION 文件的 Imports 部分而不是 Depends 中包含所有包依赖项,因为我同意不要不必要地改变全局环境的理念(许多 CRAN 和 Bioconductor 包不这样做) ' 似乎跟随)。
我想在我的一个包函数中使用 Bioconductor 包 rhdf5 中的函数,特别是 h5write()
。我现在 运行 遇到的问题是它没有在其名称空间中声明其 S3 方法。它们是使用(例如)
export(h5write.default)
export(h5writeDataset.matrix)
而不是
S3method(h5write, default)
S3method(h5writeDataset, matrix)
通用 h5write 定义为:
h5write <- function(obj, file, name, ...) {
res <- UseMethod("h5write")
invisible(res)
}
实际上,这意味着调用 rhdf5::h5write 失败,因为没有注册合适的 h5write 方法。
据我所知,有以下三种解决方案:
- 在 DESCRIPTION 文件中使用
Depends
而不是Imports
。 - 在相关函数的代码中使用
library("rhdf5")
或require("rhdf5")
。 - 修改 rhdf5 的命名空间文件以使用
S3methods()
而不是export()
。
所有这些都有缺点。选项 1 意味着包被加载并附加到全局环境,即使我的包中的相关函数从未被调用。选项 2 意味着在包中使用 library
,同时再次将包附加到全局环境,并且根据 Hadley Wickham 的指南也已弃用。选项 3 意味着依赖其他包作者在 Bioconductor 上更新他们的包,也意味着不再导出 S3 方法,这可能反过来破坏依赖于显式调用它们的其他包。
我错过了另一个选择吗?我查看了 Whosebug 的其他地方,发现了以下一些相关的问题 Importing S3 method from another package 和
How to export S3 method so it is available in namespace? 但没有任何内容可以直接解决我的问题。值得注意的是,与这两个中第一个的主要区别在于泛型和方法都在同一个包中,但问题是使用 export
而不是 S3method
.
重现错误的示例代码(无需创建包):
loadNamespace("rhdf5")
rdhf5::h5write(1:4, "test.h5", "test")
Error in UseMethod("h5write") :
no applicable method for 'h5write' applied to an object of class
"c('integer', 'numeric')
或者,https://github.com/NikNakk/s3issuedemo 处有一个框架包,它提供了一个单一的函数 demonstrateIssue()
来重现错误消息。可以使用 devtools::install_github("NikNakk/s3issuedemo")
.
这里的关键是除了要使用的泛型之外,还要导入特定的方法。以下是如何让它为默认方法工作。
注意:这假设test.h5
文件已经存在。
#' @importFrom rhdf5 h5write.default
#' @importFrom rhdf5 h5write
#' @export
myFun <- function(){
h5write(1:4, "test.h5", "test")
}
我也贴出了我自己的小包来演示这个here。