Best practices for developing a suite of dependent

2019-02-19 08:35发布

I am starting to work on a family of R packages, all of which share substantial common code which is housed in its own package, lets call it myPackageUtilities. So I have several packages

myPackage1, myPackage2, etc...

All of these packages depend on every method in myPackageUtilities. For a real-world example, please see statnet on CRAN. The idea is that a future developer might create myPackageN, and instead of having to re-write/duplicate all of the supporting code, this future developer can simply use mypackageUtilities to get started.

There are complications:

1) Some of the code in mypackageUtilities is intended for end-users, and the rest is for internal development purposes. The end-user code needs to be properly documented using roxygen2. This code includes both S3 classes and generics, as well as various helper functions for the user.

2) The dependent packages (myPackage1, myPackage2, etc.) will likely extend S3 generics defined in myPackageUtilities.

My question is: What is the best way to assemble all of this? Here are two natural (but non-exhuastive) options:

  1. Include mypackageUtilities under Imports: for all the dependent packages, and force users to separately load mypackageUtilities,
  2. Include mypackageUtilities under Depends: for all the dependent packages, and be very selective about what is exported from mypackageUtilities so as to avoid cluttering the search path. All of the internal (non-exported) code will have to accessed via ::: in myPackage1, etc.

I originally asked a similar question over here, but quickly discovered the situation gets complicated quickly. For example:

  • If we use Imports: instead of Depends:, then any generics defined in mypackageUtilities aren't found by myPackage1, etc.
    • This makes using the generic templates provided by mypackageUtilities difficult/impossible, and almost defeats the purpose of this entire set-up.
  • If I define an S3 generic in mypackageUtilities and document it there, how can I have roxygen2 reference these docs in myPackage1?

Perhaps I am deeply misunderstanding how namespaces work, in which case this would be a great place to clear up my misunderstanding!

1条回答
Summer. ? 凉城
2楼-- · 2019-02-19 09:15

Welcome to the rabbit hole.

You may be pleasantly surprised to learn that you can import a function from myPackageUtilities into myPackage1 and then export it from myPackage1 to make it accessible from the global environment.

So, when you say that you have a function in myPackageUtilities that should be accessible by the end user when myPackage1 is loaded, this is what I would include in my documentation for fn_name in myPackage1

#' @importFrom myPackageUtilities fn_name
#' @export fn_name

(See https://github.com/hadley/dplyr/blob/master/R/utils.r for an example)

That still leaves the question of how to link to the original documentation. And I'm afraid I don't have a good answer for that. My current practice is to, essentially, copy the parameters documentation from the original source and then in my @details section write please see the documentation for \code{\link[myPackageUtilities]{fn_name}}

In the end, I still think your best bet is to export everything from myPackageUtilities that will ever get used outside of myPackageUtilities and do a combination import-export in each package where you want a function from myPackageUtilities to be accessible from the global environment.

查看更多
登录 后发表回答