Export error on overwriting primitives with S3 in R package - r

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.

Related

Using R, how to specify that a function will NOT use default namespace (S3)? roxygen2? [duplicate]

Since roxygen2 version 4.0.0, the #S3method tag has been deprecated in favour of using #export.
The package now tries to detect if a function is an S3 method, and automatically adds the line S3method(function,class) to the NAMESPACE file if it think it is one.
The problem is that if a function is not an S3 method but its name contains a . then roxygen sometimes makes a mistake and adds the line when it shouldn't.
Is there a way to tell roxygen that a function is not an S3 method?
As requested, here's a reproducible example.
I have a package that imports R.oo, with a function named check.arg.
library(roxygen2)
package.skeleton("test")
cat("Imports: R.oo\n", file = "test/DESCRIPTION", append = TRUE)
writeLines(
"#' Check an argument
#'
#' Checks an argument.
#' #param ... Some arguments.
#' #return A value.
#' #export
check.arg <- function(...) 0",
"test/R/check.arg.R"
)
roxygenise("test")
Now the namespace contains the line S3method(check,arg).
check is an S3 generic in R.oo, so roxygen is trying to be smart and guessing that I want check.arg to be an S3 method. Unfortunately, these functions are unrelated, so I don't.
(To preempt suggestions that I just rename check.arg: this is legacy code written by others, and I've created a checkArg replacement, but I need to leave check.arg as a deprecated function for compatibility.)
As Mr Flick commented, appending the full function name to the roxygen line works correctly. If I change the line to:
#' #export check.arg
then the NAMESPACE file contains:
export(check.arg)
Use #method generic class and #export instead of #S3method. Take a look at this thread:
S3 method help (roxygen2)

R-package development: Documenting and exporting functions with non-syntactic names

I'm writing a package (called pac) where I have a function with a non-syntactic name (called +f). I'm unable to correctly document and export this function.
Here's a reproducible example:
library(devtools)
setwd("~/yourpath")
create("pac")
Save the following function definition along with its documentation in pac/R/+f.R
#' Add two objects
#'
#' #name `+f`
#'
#' #param x an object
#' #param y an object
#' #return A sum
#' #export
`+f`<- function(x, y) {x + y}
Then run
document()
load_all()
`+f`(2, 2)
Which produces the output
> document()
Updating pac documentation
Loading pac
Writing NAMESPACE
Writing tick-plus-f-tick.Rd
> load_all()
Loading pac
Warning message:
In setup_ns_exports(path, export_all, export_imports) :
Objects listed as exports, but not present in namespace: +f
> `+f`(2, 2)
Error in `+f`(2, 2) : could not find function "+f"
As you can see, the function `+f` is not exported correctly, even though the NAMESPACE-file does have the following line:
export(`+f`)
On the other hand, since the documentation file pac/man/tick-plus-f-tick.Rd exists, I am able to display it by calling ?"`+f`".
How can I define and document a function with a non-syntactic name in a package? What's going on in the above example? Why isn't the function available when pac is loaded, even though the NAMESPACE-file includes an export-statement?

Include R6 class object in R package

I am currently developing an R package and I want to include an object of class R6, which is basically an environment, so that users can easily use it (same way it works with datasets in a package).
I have an R6ClassConstructor Gridworld:
Gridworld <- R6::R6Class( ... )
Then I can create a new instance using grid = Gridworld$new(), which generates an R6 class. I then want to save this object grid in the package, so that a user can use it by just typing in grid.
I tried to save grid as an .RData object in the /data folder and document the R6 class in the /R folder:
#' Gridworld
#' #format R6 class
"grid"
but this causes an error in devtools::document: file 'grid.RData' has magic number 'X'
How can I include this R6 class object in the package?
Maybe it would be best to call new when the package is loaded. This way you will not have any troubles regarding reference semantics.
See the answer here
In your case, this would look like
# file R/zzz.R
.onLoad <- function(libname, pkgname){
gridworldInstance <- Gridworld$new()
}
# documentation
#' Instance of grid world
#'
#' some description
#'
#' #name gridworldInstance
NULL
#' #export

Package function set as S3method instead of a generic function [duplicate]

Since roxygen2 version 4.0.0, the #S3method tag has been deprecated in favour of using #export.
The package now tries to detect if a function is an S3 method, and automatically adds the line S3method(function,class) to the NAMESPACE file if it think it is one.
The problem is that if a function is not an S3 method but its name contains a . then roxygen sometimes makes a mistake and adds the line when it shouldn't.
Is there a way to tell roxygen that a function is not an S3 method?
As requested, here's a reproducible example.
I have a package that imports R.oo, with a function named check.arg.
library(roxygen2)
package.skeleton("test")
cat("Imports: R.oo\n", file = "test/DESCRIPTION", append = TRUE)
writeLines(
"#' Check an argument
#'
#' Checks an argument.
#' #param ... Some arguments.
#' #return A value.
#' #export
check.arg <- function(...) 0",
"test/R/check.arg.R"
)
roxygenise("test")
Now the namespace contains the line S3method(check,arg).
check is an S3 generic in R.oo, so roxygen is trying to be smart and guessing that I want check.arg to be an S3 method. Unfortunately, these functions are unrelated, so I don't.
(To preempt suggestions that I just rename check.arg: this is legacy code written by others, and I've created a checkArg replacement, but I need to leave check.arg as a deprecated function for compatibility.)
As Mr Flick commented, appending the full function name to the roxygen line works correctly. If I change the line to:
#' #export check.arg
then the NAMESPACE file contains:
export(check.arg)
Use #method generic class and #export instead of #S3method. Take a look at this thread:
S3 method help (roxygen2)

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