如何在其命名空间中使用导出而不是S3method的其他包中的S3方法,而不使用Depends或library()

时间:2015-06-11 10:49:54

标签: r package r-package r-s3

我目前正在研究R套餐,并试图遵循Hadley Wickham在http://r-pkgs.had.co.nz提供的最佳做法指南。作为其中的一部分,我的目标是在DESCRIPTION文件的Imports部分中拥有所有的包依赖,而不是取决于因为我同意不必要地改变全局环境的理念(许多CRAN和Bioconductor的东西)包裹似乎没有跟随)。

我想在我的一个包函数中使用Bioconductor包rhdf5中的函数,特别是h5write()。我现在遇到的问题是它的NAMESPACE中没有声明其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方法。

据我所知,有三种解决方案:

  1. 在说明文件中使用Depends而不是Imports
  2. 在相关功能的代码中使用library("rhdf5")require("rhdf5")
  3. 将rhdf5的NAMESPACE文件修改为使用S3methods()而不是export()
  4. 所有这些都有缺点。选项1表示即使从不调用我的包中的相关函数,也会加载包并将其附加到全局环境。选项2意味着在包中使用library,同时将包附加到全局环境中,并且根据Hadley Wickham的指南也弃用。选项3意味着依赖另一个包作者在Bioconductor上更新他们的包,也意味着不再导出S3方法,这反过来可能会破坏依赖于明确调用它们的其他包。

    我错过了另一种选择吗?我已经在StackOverflow的其他地方查找并发现了以下有些相关的问题Importing S3 method from another packageHow 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")安装。

1 个答案:

答案 0 :(得分:9)

此处的关键是除了要使用的通用之外还导入特定方法。以下是如何使其适用于默认方法。

注意:这假定test.h5文件已存在。

#' @importFrom rhdf5 h5write.default
#' @importFrom rhdf5 h5write
#' @export
myFun <- function(){
    h5write(1:4, "test.h5", "test")
}

我也提出了我自己的小包,展示了这个here