Search code examples
rpackageroxygen2rd

Exported S3 method not found during check


In a package, I have a function foo that returns an object of class "foo". I also have a plot method for class "foo".

#' Create a "foo" object
#'
#' @param x An \R object.
#' 
#' @return
#' A "foo" object.
#'
#' @examples
#' foo_object <- foo(1)
#' plot.foo(foo_object)
#'
#' @export
foo <- function(x) {
    structure(x, class = "foo")
}

#' @export
#' @importFrom graphics plot
plot.foo <- function(x, ...) {
    class(x) <- setdiff(class(x), "foo")
    plot(x)
    invisible(NULL)
}

I can evaluate the example code without issue after I load the package with devtools::load_all. However, devtools::check complains:

Error in plot.foo(foo_out) : could not find function "plot.foo"
  Execution halted

It seems that my R session knows about plot.foo, but not devtools::check. What is going on?


Edit: To clarify, devtools::check passes when I replace the call plot.foo(foo_object) under @examples with plot(foo_object). That doesn't surprise me, and users should call the generic anyway. My question remains: why is devtools::check unable to find plot.foo, given that I have used the @export tag and S3method(plot, foo) appears in NAMESPACE after devtools::document?


Solution

  • If you want to be able to call plot.foo directly, then you will need to explicitly export that version as well. By convention, usually you do not export class-specific implemenations of generic functions from your package. Normally you just declare that the S3 method exists and leave the function unexported. Like if you call methods(plot) you'll see a bunch with asterisks which means they are unexpected and are not meant to be called directly. If you do for some reason want to export it as a separate function, you can add an additional export statement. For example

    #' @rdname foo-methods
    #' @export plot.foo
    #' @export
    #' @importFrom graphics plot
    plot.foo <- function(x, ...) {
      class(x) <- setdiff(class(x), "foo")
      plot(x)
      invisible(NULL)
    }