4
votes

I have the following dependency chain in a package I'm developing:

  • My package uses a class (trajectory) defined in package A (simmer).
  • It also uses an S3 method for that class (plot.trajectory), which is defined in package B (simmer.plot).
  • I can import package A as a whole, but I cannot import package B as a whole, because it contains replacements for other functions defined in package A (the get_mon functions), so I get unwanted warnings about the original functions being replaced.

How do I use/import the S3 method without importing the rest of package B, preferably via roxygen2?

The roxygen2 documentation suggests the following:

If you want to add a new method to an S3 generic, import it with @importFrom pkg generic.

For my example, this would be @importFrom simmer.plot plot, but this returns a warning that plot is not exported by simmer.plot. The same thing happens if I import the generic first, using @importFrom graphics plot.

2
What you quoted there is if you're importing the generic from another package, and adding an S3 method in your package. Have you tried #' @importFrom simmer.plot plot.trajectory?duckmayr
I have! I got a warning that plot.trajectory isn't exported by simmer.plot, even though I can see that it is on its GitHub repository: github.com/r-simmer/simmer.plot/blob/master/NAMESPACEAccidental Statistician
Fair enough. That was just my best guess without having tried it. I was surprised you said it didn't work, so I did a quick search, and it seems like several others have ran into the same problem, all without anyone figuring it out! stackoverflow.com/q/23112762/8386140 stackoverflow.com/q/42952244/8386140 stackoverflow.com/q/32680169/8386140 If I don't have time to look into it and you don't get an answer, I might put up a bounty for this. Interesting questionduckmayr
Have you tried accessing the function with simmer.plot:::plot.trajectory()?BigFinger
This doesn't solve this particular problem, because the overloaded functions are needed, as I stated in my answer below, but you only need to import a single valid function from a package and then the S3 methods registered there are readily available. See stackoverflow.com/a/59667634/6788081Iñaki Úcar

2 Answers

2
votes

Iñaki Úcar's mention of the @rawNamespace tag led me to work out a version that doesn't import any of package B's exported functions, using the getNamespaceExports function mentioned in this answer:

#' @rawNamespace import(packageB, except = getNamespaceExports("packageB"))

The @rawNamespace tag in roxygen2 inserts raw code into the NAMESPACE file. getNamespaceExports returns the names of all exported functions in a namespace: this can be a package that you haven't attached.

For my specific example, I can write this:

#' @import simmer
#' @rawNamespace import(simmer.plot, except = getNamespaceExports("simmer.plot"))

which puts these lines in the NAMESPACE:

import(simmer)
import(simmer.plot, except = getNamespaceExports("simmer.plot"))
2
votes

Use (see this):

#' @rawNamespace import(simmer, except=c(get_mon_arrivals, get_mon_resources, get_mon_attributes))
#' @import simmer.plot

because you really need to use the overloaded functions in simmer.plot so that the plot methods there can work. An equivalent, but shorter version:

#' @rawNamespace import(simmer, except=getNamespaceExports("simmer.plot"))
#' @import simmer.plot