5

When developing an R package, it is common for me to just turn on Packrat and use a localized repository, and develop as I explore in a session. But when publishing the package, it is a big headache to recall and manually add every dependency I have used in the developed package. Is there a (semi-)automatic way to do this?

For example, in NodeJS development, we can just use npm install --save and the dependency will be added automatically to package.json.

xzhu
  • 5,675
  • 4
  • 32
  • 52
  • 1
    I *think* the standard way to do this is to manually insert roxygen(2) `@importFrom` statements in the code ... – Ben Bolker May 16 '16 at 21:54
  • 1
    At the very least, it is an extremely _common_ way. – joran May 16 '16 at 21:55
  • @joran: better ways? (or are you referring to the fact that (AFAIK) old-school/R-core developers don't tend to use roxygen?) – Ben Bolker May 16 '16 at 21:59
  • @BenBolker Yes, that's all I meant, that some "old-school" R folks might balk at calling roxygen2 the "standard" way. – joran May 16 '16 at 22:00

2 Answers2

4

Yes, use roxygen2 to generate your NAMESPACE file.

Example way to generate package level documentation:

#' @details 
#' \tabular{ll}{
#' Package: \tab \cr
#' Type: \tab Package\cr
#' Version: \tab 1.0.0\cr
#' Date: \tab 2016-05-15\cr
#' License: \tab MIT \cr
#' }
#' @useDynLib pkg
#' @importFrom Rcpp evalCpp
#' @importFrom methods is
#' @importFrom stats ts as.ts is.ts
#' @import ggplot2
"_PACKAGE" 

Note: I tend to keep my import statements together in the package-level documentation. You can use these same statements within function documentation.

Use @importFrom <pkg> <function1> <function2> for specific imports.

Otherwise, use @import <pkg> for all functions in a given package.

Edit

To lock it to a specific version, you will need to modify your DESCRIPTION file's Imports: section like so:

Imports: 
    Rcpp (>= 0.12.5),
    scales (<= 0.4.0),
    grid (== 0.7-4),
    stats
coatless
  • 20,011
  • 13
  • 69
  • 84
  • Does it handle specific versions? Do you think it's redundant to use both Roxygen2 and Packrat for dependency handling? – xzhu May 16 '16 at 22:01
  • I prefer import statements with the function documentation because it makes clear *where* in the code you need a given function - if that code goes away later, you know you don't need the dependency any more. – Ben Bolker May 16 '16 at 22:05
  • 1
    Note the edit for version specific package loads. @BenBolker I find it easier to centralize everything and prepend the package namespace when calling the package's function e.g. `stats::is.ts()` since I rarely remove dependencies. Again, either approach is valid. – coatless May 16 '16 at 22:42
3

A common way to do this (although not one that's used much by "old school" R programmers, who as far as I know maintain their NAMESPACE files by hand ...) is to manually insert roxygen2 @importFrom statements in the code ... e.g.

# returns a true family() object iff one was given
## to glmmTMB() in the first place ....
##' @importFrom stats family
##' @export
family.glmmTMB <- function(object, ...) {
   object$modelInfo$family
}

although it would certainly be helpful to have an automated system, to provide hints if nothing else. Certainly maintaining dependencies in this way (making sure to add @importFrom statements as needed for every function that has a dependency) is better than trying to keep track of when dependencies are (still) needed after developing the code.

  • @import and @importFrom (which translate to import and importFrom statements) are both legal, the R extensions guide says

    Using importFrom selectively rather than import is good practice and recommended notably when importing from packages with more than a dozen exports.

("good practice" translates to "CRAN maintainers will yell if you don't" ...)

  • I don't know if there's a way to do versioned importFrom statements: R puts package version dependencies in the Imports: field in the DESCRIPTION file and importFrom statements in the NAMESPACE file: roxygen2 generates this information automatically, but I don't think the mapping from roxygen2 directives to NAMESPACE/DESCRIPTION information is fine-grained enough to support this ...
  • Running R CMD check --as-cran gives hints about functions from recommended packages that need to be imported.
Ben Bolker
  • 211,554
  • 25
  • 370
  • 453