Creating an RPackage - UseMethod can't find function - r

I'm trying on my first attempt on creating an R package. I have some functions that follows below.
#' #export
overview <- function(x, ...) {
UseMethod("overview")
}
overview.query <- function(return.query, ...) {
Now when I use the devtools::load_all() (which loads all functions) everything works, and overview.query is executed when I pass an object of class query.
But rebuilding, and the UseMethod can't find the overview.query function anymore (all functions are thus not loaded), what have I done wrong?
Error message: no applicable method for 'overview' applied to an object of class "c('query', 'data.frame')"
I thought that only functions that are to be exposed to the user are to be #export'ed, and all other functions would still be visible internally to the other package functions.

When you create a generic function to apply to an S3 object, you need to export both the UseMethod statement and the function itself, as in:
#' #export
overview <- function(x, ...) {
UseMethod("overview")
}
#' #export
overview.query <- function(return.query, ...) {
which ought to eliminate the error as that method is now available to the user.
This is applicable to roxygen2 versions 3+ (currently on 5). See this answer for more info:
How to properly document S3 methods

Related

S4 error: methods can be defined, but the generic function is implicit, and cannot be changed

I'm creating the following method via S4
#' #name +
#' #title Expand outputs
#' #description
#'
#' Operator outputs of function 'create'
#'
#' #return expanded creation
#' #exportMethod +
#' #aliases +
#' #export
setGeneric('+', function(dt, ...) standardGeneric('+'))
setMethod('+', signature(dt = 'data.table'), function(dt, out) {
return(create(dt, out))
})
I put the following into my R package. When I run devtools::document(), I run into the following problem:
Error in setGeneric("+", function(dt, ...) standardGeneric("+")) :
‘+’ dispatches internally; methods can be defined, but the generic function is implicit, and cannot be changed.
This appears to be a fatal error, and I cannot create documentation otherwise.
(1) What does this error mean? I'm unsure how I'm supposed to debug this.
(2) When creating an R package, what would be the correct way to work with this error? Should I create the documentation first with another name besides + and then change this afterwards?
As a builtin function, the definition of the generic + cannot be changed, as the error message says. Much of R would break if you did redefine it this way.
+ is defined to have two arguments, e1 and e2. Using this framework, you can modify your example to be
setMethod('+', signature(e1 = 'data.table', e2='ANY'), function(dt, out) {
return(create(dt, out))
})
One thing to note is that e1 is always the first argument, even if argument names are used. so "+"(e2=A,e1=B) is equal to A+B, not B+A.

How to create new method for generics in ggplot2?

I'm trying to create a new guide for ggplot2 and in the process I had to create a new method for the ggplot2 generic guide_train(). In my code I have
# constructor function which returns an object of
# class = c("guide", "colorbar2", "colorbar")
#' #export
guide_colourbar2 <- function(...) {
# things
}
# methods
#' #export
guide_train.colorbar2 <- function(guide, scale) {
# things
}
The problem is that now CMD check complains that there's no documentation for guide_train.colorbar2. I gather this is because roxygen2 exports it as regular function (export(guide_train.colorbar2)). But since this method is internal to ggplot2 workings, it makes no sense to document it.
Creating my own generic dispatch changes my NAMESPACE so that the new method is exported as S3method(guide_train,colorbar2) and solves the CMD check warning, but now the new guide doesn't work. Using it throws
Error in UseMethod("guide_train") : no applicable method for
'guide_train' applied to an object of class "c('guide', 'colorbar2')"
In this vignette it says that "If you want to add a new method to an S3 generic, import it with #importFrom pkg generic." But adding #importFrom ggplot2 guide_train to my function definition makes my package fail to load with error
Error : object ‘guide_train’ is not exported by 'namespace:ggplot2'
This is the first time I'm working with the S3 system, but it seems to me that the correct way would be the #importFrom way and the real problem is that ggplot2 doesn't export the generic. Is that the case or there are other problems with my code?

Function imported from dependency not found, requires library(dependency)

I am trying to create an R package that uses functions from another package (gamlss.tr).
The function I need from the dependency is gamlss.dist::TF (gamlss.dist is loaded alongside gamlss.tr), but it is referenced in my code as simply TF within a call to gamlss.tr::gen.trun.
When I load gamlss.tr manually with library(), this works. However, when I rely on the functions of the dependency automatically being imported by my package through #import, I get an "object not found" error as soon as TF is accessed.
My attempt to be more explicit and reference the function I need as gamlss.dist::TF resulted in a different error ("unexpected '::'").
Any tips on how to use this function in my package would be much appreciated!
The code below reproduces the problem if incorporated into a clean R package (as done in this .zip), built and loaded with document("/path/to/package"):
#' #import gamlss gamlss.tr gamlss.dist
NULL
#' Use GAMLSS
#'
#' Generate a truncated distribution and use it.
#' #export
use_gamlss <- function() {
print("gen.trun():")
gamlss.tr::gen.trun(par=0,family=TF)
#Error in inherits(object, "gamlss.family") : object 'TF' not found
#gamlss.tr::gen.trun(par=0,family=gamlss.dist::TF)
#Error in parse(text = fname) : <text>:1:1: unexpected '::'
y = rTFtr(1000,mu=10,sigma=5, nu=5)
print("trun():")
truncated_dist = gamlss.tr::trun(par=0,family=TF, local=TRUE)
model = gamlss(y~1, family=truncated_dist)
print(model)
}
use_gamlss() will only start working once a user calls library(gamlss.tr).
This is due to bad design of gamlss.tr in particular the trun.x functions (they take character vectors instead of family objects / they evaluate everything in the function environment instead of the calling environment).
To work around this, you have to make sure that gamlss.distr is in the search path of the execution environment of gamlss.tr functions (This is why ## import-ing it in your package does not help: it would need to be #' #import-ed in gamlss.tr).
This can be achieved by adding it to Depends: of your package.
If you want to avoid that attaching your package also attaches gamlss.distr, you could also add the following at the top of use_gamlss:
nsname <-"gamlss.dist"
attname <- paste0("package:", nsname)
if (!(attname %in% search())) {
attachNamespace(nsname)
on.exit(detach(attname, character.only = TRUE))
}
This would temporarily attach gamlss.dist if it is not attached already.
You can read more on namespaces in R in Hadley Wickham's "Advanced R"

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.

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