开发一套依赖 R 包的最佳实践
Best practices for developing a suite of dependent R packages
我开始研究一系列 R 程序包,所有这些都共享大量的公共代码,这些代码位于自己的程序包中,我们称之为 myPackageUtilities
。所以我有几个包裹
myPackage1
、myPackage2
、等等...
所有这些包都依赖于 myPackageUtilities
中的每个方法。有关真实示例,请参阅 statnet on CRAN。这个想法是未来的开发人员可能会创建 myPackageN
,而不必 re-write/duplicate 所有支持代码,这个未来的开发人员可以简单地使用 mypackageUtilities
开始。
有并发症:
1) mypackageUtilities
中的部分 代码供最终用户使用,其余代码供内部开发使用。需要使用 roxygen2 正确记录最终用户代码。此代码包括 S3 类 和泛型,以及用户的各种辅助函数。
2) 依赖包(myPackage1
、myPackage2
等)可能会扩展 myPackageUtilities
.
中定义的 S3 泛型
我的问题是: assemble 所有这些的最佳方法是什么?这里有两个自然的(但不是穷举的)选项:
- Include
mypackageUtilities
under Imports: 对于所有依赖包,并强制用户单独加载 mypackageUtilities
,
- 在 Depends 下包括
mypackageUtilities
对于所有依赖包,并且非常有选择性地选择从 mypackageUtilities
导出的内容以避免搜索路径混乱。所有内部(非导出)代码都必须通过 myPackage1
中的 :::
访问,等等
我最初问过类似的问题,但很快发现情况很快变得复杂起来。例如:
- 如果我们使用 Imports: 而不是 Depends:,那么
mypackageUtilities
中定义的任何泛型都不会被 myPackage1
等找到。
- 这使得使用
mypackageUtilities
difficult/impossible 提供的通用模板几乎违背了整个设置的目的。
- 如果我在
mypackageUtilities
中定义了一个 S3 泛型并在那里记录它,我怎样才能让 roxygen2 在 myPackage1
中引用这些文档?
也许我对名称空间的工作方式有很深的误解,在这种情况下,这将是消除我的误解的好地方!
欢迎来到兔子洞。
您可能会惊喜地发现,您可以将函数从 myPackageUtilities
导入到 myPackage1
,然后从 myPackage1
导出它以使其可从全局环境访问。
所以,当你说你在 myPackageUtilities
中有一个函数,当加载 myPackage1
时,最终用户应该可以访问它,这就是我要包含在 [=] 文档中的内容16=] 在 myPackage1
#' @importFrom myPackageUtilities fn_name
#' @export fn_name
(参见 https://github.com/hadley/dplyr/blob/master/R/utils.r 示例)
这仍然留下如何 link 原始文档的问题。恐怕我对此没有一个好的答案。我目前的做法是,基本上,从原始来源复制参数文档,然后在我的 @details
部分写入 please see the documentation for \code{\link[myPackageUtilities]{fn_name}}
最后,我仍然认为你最好的选择是导出 myPackageUtilities
中将在 myPackageUtilities
之外使用的所有内容,并在你想要的每个包中进行组合导入导出来自 myPackageUtilities
的函数可以从全局环境访问。
我开始研究一系列 R 程序包,所有这些都共享大量的公共代码,这些代码位于自己的程序包中,我们称之为 myPackageUtilities
。所以我有几个包裹
myPackage1
、myPackage2
、等等...
所有这些包都依赖于 myPackageUtilities
中的每个方法。有关真实示例,请参阅 statnet on CRAN。这个想法是未来的开发人员可能会创建 myPackageN
,而不必 re-write/duplicate 所有支持代码,这个未来的开发人员可以简单地使用 mypackageUtilities
开始。
有并发症:
1) mypackageUtilities
中的部分 代码供最终用户使用,其余代码供内部开发使用。需要使用 roxygen2 正确记录最终用户代码。此代码包括 S3 类 和泛型,以及用户的各种辅助函数。
2) 依赖包(myPackage1
、myPackage2
等)可能会扩展 myPackageUtilities
.
我的问题是: assemble 所有这些的最佳方法是什么?这里有两个自然的(但不是穷举的)选项:
- Include
mypackageUtilities
under Imports: 对于所有依赖包,并强制用户单独加载mypackageUtilities
, - 在 Depends 下包括
mypackageUtilities
对于所有依赖包,并且非常有选择性地选择从mypackageUtilities
导出的内容以避免搜索路径混乱。所有内部(非导出)代码都必须通过myPackage1
中的:::
访问,等等
我最初问过类似的问题
- 如果我们使用 Imports: 而不是 Depends:,那么
mypackageUtilities
中定义的任何泛型都不会被myPackage1
等找到。- 这使得使用
mypackageUtilities
difficult/impossible 提供的通用模板几乎违背了整个设置的目的。
- 这使得使用
- 如果我在
mypackageUtilities
中定义了一个 S3 泛型并在那里记录它,我怎样才能让 roxygen2 在myPackage1
中引用这些文档?
也许我对名称空间的工作方式有很深的误解,在这种情况下,这将是消除我的误解的好地方!
欢迎来到兔子洞。
您可能会惊喜地发现,您可以将函数从 myPackageUtilities
导入到 myPackage1
,然后从 myPackage1
导出它以使其可从全局环境访问。
所以,当你说你在 myPackageUtilities
中有一个函数,当加载 myPackage1
时,最终用户应该可以访问它,这就是我要包含在 [=] 文档中的内容16=] 在 myPackage1
#' @importFrom myPackageUtilities fn_name
#' @export fn_name
(参见 https://github.com/hadley/dplyr/blob/master/R/utils.r 示例)
这仍然留下如何 link 原始文档的问题。恐怕我对此没有一个好的答案。我目前的做法是,基本上,从原始来源复制参数文档,然后在我的 @details
部分写入 please see the documentation for \code{\link[myPackageUtilities]{fn_name}}
最后,我仍然认为你最好的选择是导出 myPackageUtilities
中将在 myPackageUtilities
之外使用的所有内容,并在你想要的每个包中进行组合导入导出来自 myPackageUtilities
的函数可以从全局环境访问。