R: Expand an S3 method defined in another package - r

Let's say that package A defines and documents foo() and implements it for bar1 objects.
In a new package B, I would like to expand this method and add its support for bar2 objects.
Currently, I start by reexporting the method:
#' #rdname foo
#' #importFrom A foo
#' #export
A::foo
And then went on extending its behaviour:
#' #rdname foo
#' #method foo bar2
#' #export
foo.bar2 <- function(x, newparam = 3.14, ...){
dosomething(x, newparam)
}
Unfortunately, it seems like this creates a conflict upon devtools checking, which returns the following warning:
> checking Rd metadata ... WARNING
Rd files with duplicated name 'reexports':
'foo.Rd'
Rd files with duplicated alias 'reexports':
'foo.Rd'
Thus, I wonder what this the best way of expanding a method without creating conflict in definition or documentation? Can I do this without having to Depend on the package A? Thanks!

Related

Documenting a package that defines a function with the same name

I am writing a package named foo that defines an S3 class named foo with various S3 methods. I have written a constructor function foo() that returns a foo object. It seemed practical to name the class after the package, and the function after the class, and I hoped that:
package?foo would bring up the package help page.
?foo and ?foo::foo would bring up the function help page.
But what happens is that:
Both package?foo and ?foo bring up the package help page.
Only ?foo::foo brings up the function help page.
Is there a way to give a package and a function the same name that produces my desired behaviour?
Currently I have a file foo_package.R like this:
#' The foo package
#'
#' A very useful package.
#'
#' #docType package
#' #name foo
NULL
and a file foo.R like this:
#' The foo function
#'
#' A very useful function.
#'
#' #param x A data frame.
#' #return A foo object.
#' #export
foo <- function(x) {
structure(x, class = c("foo", "data.frame"))
}
Any hints are appreciated...
Following the second link in #MrFlick's comment, which points to the text under "Packages" in vignette("rd"), I was able to get the expected behaviour.
foo.R is unchanged, but foo-package.R now reads:
#' The foo package
#'
#' A very useful package.
#'
#' #docType package
#' #keywords internal
#' #aliases foo-package
"_PACKAGE"
Now, as desired:
package?foo and ?"foo-package" bring up the package help.
?foo and ?foo::foo bring up the function help.

S3methods in NAMESPACE not exported

I am developing an R package using devtools::document() to create the NAMESPACE file. Several of the functions are S3methods for summary, predict, plot, print where the generic is in base or stats.
I am using #export as Hadley recommends and that leads to the correct S3method entry in the NAMESPACE, and the package passes all checks -as-cran. The functions are not exported in the NAMESPACE, however, so calling print.myclass is not found (I understand that is the desired behavior to avoid cluttering up the NAMESPACE). However, calling the function by Mypackage::print.myclass also leads to an error that the function is not an exported object from Mypackage.
Question: is that the correct behavior? Or are there other steps needed to have the function exported? I have tried adding both #method print Myclass and #export but with no luck. Using R 3.4.2 with devtools 1.13.3 under MAC OS X 10.12.6
Thanks! Merlise
Edited: updated to have the code that will add/export method and export function
Simple example - build a skeleton package in RStudio with function:
#' test for export of S3 methods
#'
#' #title "print hello world for any object"
#' #param x object
#' #param digits optional number specifying the number of digits to display
#' #param ... other parameters to be passed to \code{print.default}
#' #export print.hello
#' #export
print.hello = function (x, digits = max(3, getOption("digits") - 3), ...)
{
cat("\n Hello World \n")
invisible()
}
The NAMESPACE now has
# Generated by roxygen2: do not edit by hand
S3method(print,hello)
export(print.hello)
Using #export with no arguments exports the method while #export print.hello exports the function, but does not add the method to the NAMESPACE (which would lead to an error with the package check). Having both would allow the method and the function to be exported.
First of all, in order to formally define a S3 method and export it properly without manually changing the namespace file (assuming you are using roxygen),
#' test for export of S3 methods
#'
#' #title "print hello world for any object"
#' #param x object
#' #param digits optional number specifying the number of digits to display
#' #param ... other parameters to be passed to \code{print.default}
#'
#' #rdname print
#' #export print
print <- function(x, ...){
UseMethod("print")
}
#' #rdname print
#' #export print.hello
#' #export
print.hello <- function (x, digits = max(3, getOption("digits") - 3), ...)
{
cat("\n Hello World \n")
invisible()
}
This more or less gives you the expected behavior for testPackage::print.hello. The more important thing here is to understand what exactly S3 method is for. It is used for method dispatching in R and the suffix after . should always stand for the class of object you are supposed to put in as the first argument of the function. That is, in this case, if you want to use print.hello with a single call of print, you would have to put a class of hello, try the example below after you successfully build and load the testpackage
a = 1
print(a) # method dispatched as print.default because class of a is numeric
# 1
class(a) <- 'hello'
print(a) # method dispatched as print.hello
# Hello World
This is the correct behaviour for your NAMESPACE file. :: accesses exported variables, so testPackage::print.hello should fail.
::: accesses internal variables, so testPackage:::print.hello should work for you.

Export error on overwriting primitives with S3 in R package

I'm trying to create a S3 method in my package called dimnames. This is a primitive in R, but there should be an S3 in my package with the same name.
I've got the following file dimnames.r
#' S3 overwriting primitive
#'
#' #param x object
#' #export
dimnames = function(x) {
UseMethod("dimnames")
}
#' title
#'
#' #export
dimnames.data.frame = function(x) {
dimnames.default(x)
}
#' title
#'
#' #export
dimnames.list = function(x) {
lapply(x, dimnames)
}
#' title
#'
#' #export
dimnames.default = function(x) {
message("in S3 method")
base::dimnames(x)
}
I then create a package from it (in R=3.3.2):
> package.skeleton("rpkg", code_files="dimnames.r")
> setwd("rpkg")
> devtools::document() # version 1.12.0
And then check the package
R CMD build rpkg
R CMD check rpkg_1.0.tar.gz
I get the following output (among other messages):
Warning: declared S3 method 'dimnames.default' not found
Warning: declared S3 method 'dimnames.list' not found
Loading the package and checking its contents, dimnames.data.frame is exported while dimnames.default and dimnames.list are not. This does not make sense to me. As far as I understand, I declared the exports correctly. Also, the NAMESPACE file looks good to me:
S3method(dimnames,data.frame)
S3method(dimnames,default)
S3method(dimnames,list)
export(dimnames)
Why does this not work, and how to fix it?
(Bonus points for: why do I need #' title in the S3 implementations when they should not be needed with roxygen=5.0.1?)
S3 methods are only exported if it is desired that the user be able to access them directly. If they are always to be invoked via the generic then there is no need to export them.
The problem with R CMD check is likely due to defining your own generic for dimnames. Normally one just defines methods and leverages off the primitive generic already in R. Remove the dimnames generic from dimnames.r.
There should be no problem in adding methods for new classes but you may have problems trying to override the functionality of dimnames for existing classes that R's dimnames handles itself.

Control where method documentation goes for simple generic, while hiding from package index

I'm writing an R package and largely following Hadley's book on the topic. I'm running into a problem with documenting methods for simple generics like print, plot, head, and tail. When I use the #describeIn tag to control where the method documentation goes, I get the nice feature of them showing up in the help file for the main analysis function that returns an object of the given class. The problem is that these generics also show up in the package's index. If I add #keywords internal to the generics, then they are removed from the package's index, but so is the main analysis function (they are in the same .R file). If I document the generics in a separate .R file, then I can gain control over what is and is not in the package's index, but I have two issues: the main analysis function doesn't come first in the Usage section of the help file; and if add the #keywords internal for the generics, this removes the analysis function from the package index too, even though they are documented (in this instance) in separate files. The crux of the problem seems to be that #keywords internal applies to all functions in the given .R file, and maybe even any function referenced in #describeIn, while #describeIn is designed for documenting multiple functions in a given .R file.
For now, I have the analysis function and generics in the same .R file to control where the method documention goes and its ordering in the Usage section, but am not using #keywords internal and leaving the index cluttered.
Here's a rough sketch of an exported analysis function:
#' #inheritParams foo
#' #export
seats <- function(judgeit.object, ...) {
[...omitted...]
class(out.object) <- "judgeit.seats"
return(out.object)
}
And a generic:
#' #describeIn seats Print a \code{\link{seats}} output
#' #keywords internal
#' #export
print.judgeit.seats <- function(x,...) print(x$output,...)
I want the help file for ?seats to look like this:
seats(judgeit.object, ...)
## S3 method for class 'judgeit.seats'
print(x, ...)
## S3 method for class 'judgeit.seats'
head(x, ...)
## S3 method for class 'judgeit.seats'
tail(x, ...)
I do not want print.judgeit.seats, head.judgeit.seats, etc. to appear in the package index, because it quickly becomes very cluttered.
Unfortunately, I am not aware of any easy fix for what you are asking.
Tags and their effect
#export will make your function visible in the global environment. CRAN requires that you document any such functions that is not hidden (i.e. that starts with .).
If you use #describeIn or #rdname, an automatic alias is created. Any alias creates an entry in the index, but points to the same .Rd file. For example, adding
#' #name myfunction
#' #aliases foo foobar`
would create foo and foobar entries in the index, but refer to the myfunction.Rd documentation file. If you try to delete manually the \alias{} in the .Rd file, CRAN will complain.
#describeIn will list the functions in the order they appear in the .R files (if they are documented in multiple files, they are listed according to the alphabetical order of the .R file, then the order of appearance). Reordering your functions can give you what you want.
#keywords internal (along with #export, a title and a description) will have Roxygen create a .Rd file that can be accessed by the user using ?, but will not be visible in the index (if you have only the tags, Roxygen will not create a .Rd file and you will get a warning because your function is not documented).
If you have a #keywords internal in any of the functions calling #describeIn, that function will be masked from the index. This does not apply to all functions in a .R file, only those which are aliases.
#usage requires you to have an alias for each method documented. You can try using instead #section Usage:, but note sections are listed in alphabetical order and the spacing will be larger.
Workaround
If you document a NULL function, you can add the #param you want. and include a multiple lines #Section: Usage field to include (manually) the S3 methods with your comments. Give it a name such as #name Seats (it cannot be the name of the function, otherwise you have ?seats pointing to two different files).
Then, document your function seats with a different #name tag and a different title, and use #internal' to hide it from the user. Use \code{\link{seats}}` to refer to that documentation.
#' Seats
#' Description of the function
#' #param judgeit.object object
#' #param x object from seats
#' #param ... additional arguments
#' #name seats
#' #section Usage:
#' \preformatted{seats(judgeit.object, ...)
#' ## S3 method for class 'judgeit.seats'
#' print(x, ...)
#' ## S3 method for class 'judgeit.seats'
#' head(x, ...)
#' ## S3 method for class 'judgeit.seats'
#' tail(x, ...)}
NULL
#' Seats function
#' #name internal-function
#' #inheritParams seats
#' #export
#' #keywords internal
#' #seealso \code{\link{seats}}
seats <- function(judgeit.object, ...) {
[...omitted...]
class(out.object) <- "judgeit.seats"
return(out.object)
}
#' Print a \code{\link{seats}} output
#'
#' #inheritParams seats
#' #describeIn internal-function
#' #export
print.judgeit.seats <- function(x,...) print(x$output,...)
This way, the user calling ?seats will be pointed to the overall documentation.

How to declare a base S3 function so it can also be used in other packages?

In R, I wish to declare a new S3 class, and then define methods for it in two packages.
Currently, this works fine for one package, but the second package to load masks the first, an then the class methods for package one are not found (and it ends up calling the .default method.
Asked on devotees google list, and got the working solution from Hadley to create a third package, declare the base class there, then import and export that namespace in the two real packages. But I'd really rather not use a third package...
Any suggestions? (not this is all being built with devtools, which treats S3 objects appropriately, based on the . in the function name)
For those not familiar with S3, you declare a default handler, class handlers, and a stub function which figures out a class handler exists, and if not calls the default handler.
So, in package1, I define and export a base class, some useful handlers, and a default.
#' #export
#' myFun <- function(x, ...){
#' UseMethod("myFun", x)
#' }
#' #export
#' myFun.x1 <- function(x, ...){
#' message("hi, I handled an x1 object from package 1")
#' }
#' #export
#' myFun.default <- function(x,...){
#' print("myFun is not defined")
#'}
In package 2, I wish just to define and export some additional object handlers
#' #export
#' myFun.x2 <- function(x, ...){
#' message("hi, I handled an x2 object from package 2")
#' }
The second package depends on the several fns in package 1, so I depend on it in the DESCRIPTION file:
Depends:
packageOne
FYI, if I import packageOne, I get the error
Error : object 'myFun' not found whilst loading namespace 'packageTwo'
Depending on package1 ensures that it is loaded and available whenever package2 is loaded, but R's resolve chain seems only to look in which ever package loads last for handlers. Calling an S3 function for an object with a handler in package 1 works fine. But if the handler is defined in package2, the lookup table fails to find a handler in package 2, and calls default in package 1.
I guess I could write a myFun.defaul handler in package 2 which explicitly calls package1's version of myFun. Suggestions welcomed
#' #export
#' myFun.default <- function(x,...){
#' package1::myfun(x, ...)
#'}
perhaps that will work

Resources