S3 Method Consistency Warning When Building R Package with Roxygen

S3 method consistency warning when building R package with Roxygen

I think this happens because a method must have all the same arguments as the generic. So add ... to the arguments of common.list(). Like this:

common.list <- function(word.list, overlap = "all", equal.or = "more", ...)

Similarly, common.default() should have word.list as an argument.

r - S3 generic/method consistency when different arguments needed

I am not sure I would use S3 here. Not answering your specific question, but consider something like this. Of course, this is irrelevant if your actual use case is far enough away from your example.

foo <- function(x, y) {
if (is.list(x)) return(do.call(foo, x))

paste(x, y)
}

So now you can get the behavior you want, and just document x as being a list of arguments or the first argument. Otherwise, you'll create some annoying things such as requiring the user to explicitly name the argument every time.

foo("a", "b")
# [1] "a b"

foo(list(x = "a", y = "b"))
# [1] "a b"

foo(list(y = "a", x = "b"))
# [1] "b a"

foo("a", "b", z = "c")
# Error in foo("a", "b", z = "c") : unused argument (z = "c")

foo(list("a", "b", z = "c"))
# Error in (function (x, y) : unused argument (z = "c")

If compelled, you can accomplish the same thing using S3. But either way, you probably want to just name the argument the same thing and document it as having two meanings.

foo <- function(x, y, ...) UseMethod('foo')

foo.default <- function(x, y, ...) paste(x, y)

foo.list <- function(x, y, ...) do.call(foo, x)

An example of this is the plot function in base.

x
the coordinates of points in the plot. Alternatively, a single plotting structure, function or any R object with a plot method can be provided.

y
the y coordinates of points in the plot, optional if x is an appropriate structure.

Here, x is either the x coordinate or a valid plotting structure. And then y is only used if needed.

S3 method help (roxygen2)

The bug you are seeing is mostly likely caused because the list method of the common generic is not being exported, so common.default gets called instead. You can pick up this problem using devtools::missing_s3 - the function is a bit heuristic, so you may get a few false positives (e.g. it can't currently tell that is.list isn't a method). This is an incredibly common problem (it has caught me so many times), and the next iteration of roxygen will do more to prevent it.

Currently, to correctly export S3 methods with roxygen you need to do either:

  • @S3method generic class (and nothing else) if you don't want to document the method
  • @method generic class and @export if you want to export and document it.

You should never have @S3method and @method in the same documentation block.

Update for roxygen2 >3.0.0

Now roxygen automatically figures out if a function is an S3 method so:

  • Never use @S3method or @method
  • Use @export if you want the method to be exported (which you normally do, even if the generic isn't)

S3 generic/method consistency - How to dispatch according to chosen type?

In the code in the question MyFun is not a generic and MyFun.algo1 and MyFun.algo2 are not S3 methods even though the names seem to suggest that. It would be beter to change it to something like this which is not suggestive of something it is not, won't trigger any checks and is more compact.

Myfun <- function(x, type = c("algo1", "algo2"), A, B, ...) {
type <- match.arg(type)
do.call(type, list(x, A, B, ...))
}

algo1 <- function(x, A, B, ...) "algo1"
algo2 <- function(x, A, B, ...) "algo2"

# test run
Myfun(1, "algo1", 2, 3)
## [1] "algo1"

# another test run
Myfun(1, A = 2, B = 3)
## [1] "algo1"

Roxygen2 - how to properly document S3 methods

The @method tag generates \method entries in the \usage field in Rd files.

The @S3method tag generates S3method() entries in the NAMESPACE file.

The @export tag generates export() entries in the NAMESPACE file.

Here is my example:

#' A description of MyHappyFunction
#'
#' A details of MyHappyFunction
#'
#' @title MyHappyFunction: The my happy function
#' @param x numeric number
#' @param ... other arguments
#' @examples
#' a <- 1
#' class(a) <- "lm"
#' MyHappyFunction(a)
#'
#' @rdname MyHappyFunction
#' @export MyHappyFunction
MyHappyFunction <- function(x, ...){
UseMethod("MyHappyFunction")
}

#' @return \code{NULL}
#'
#' @rdname MyHappyFunction
#' @method MyHappyFunction lm
#' @S3method MyHappyFunction lm
MyHappyFunction.lm = function(x, ...) {
# do some magic
}

#' @return \code{NULL}
#'
#' @rdname MyHappyFunction
#' @method MyHappyFunction default
#' @S3method MyHappyFunction default
MyHappyFunction.default = function(x, ...) {
# do some magic
}

Sample Image

3 From the wiki page...

I guess that it means "you do not write @S3method generic mymethod myobject."

Importing a package's S3 methods without importing its functions

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"))

R package documentation: Found the following apparent S3 methods exported but not registered

I don't know Roxygen2 very well, but it appears that you have declared is.nan.data.frame to be the is.nan method for class data.frame. Since you did that, you should call it as is.nan(df) in the help page example.

If you don't want it to be the method, you just want it to be a regular function using dots in the name, then you shouldn't have @method is.nan data.frame. But you indicate that you do want it to be a method.

Edited to add: Just to summarize your comments, the following fixes got rid of all the errors:

  • use @export by itself without naming the function (as suggested by @KonradRudolph)
  • remove the @usage line
  • use is.nan(df) in the example (as I suggested)


Related Topics



Leave a reply



Submit