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.
Related
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.
I am trying to include the following ggplot2 helper function in a package [it wraps labels in grid_facet(.~variable, labeller = "plot.label.wrap")]:
#' Label wrapper for ggplot
#'
#' Include in the facet_grid option of ggplot.
#' #param variable
#' #param value
#' #return wrapper
#' #export
plot.label.wrap <- function(variable, value) {
lapply(strwrap(as.character(value), width=15, simplify=FALSE),
paste, collapse="\n")
}
My DESCRIPTION file includes: Imports: ggplot2. The scripts that uses the function includes: library(ggplot2).
The package builds, reloads and gives the documentation upon ?plot.label.wrap. It can be found:
> getAnywhere(plot.label.wrap)
A single object matching ‘plot.label.wrap’ was found
It was found in the following places
registered S3 method for plot from namespace mypackage
namespace:mypackage
with value
function(variable, value) {
lapply(strwrap(as.character(value), width=15, simplify=FALSE),
paste, collapse="\n")
}
<environment: namespace:mypackage>
However:
> plot.label.wrap
Error: object 'plot.label.wrap' not found
So my question is, why is this function found in the namespace of mypackage but not on the command line itself?
the solution in the comments was to be more specific about the export like below
#' Label wrapper for ggplot
#'
#' Include in the facet_grid option of ggplot.
#' #param variable
#' #param value
#' #return wrapper
#' #export plot.label.wrap
plot.label.wrap <- function(variable, value) {
lapply(strwrap(as.character(value), width=15, simplify=FALSE),
paste, collapse="\n")
}
roxygen tries to be smart about things like the #usage, #details, and #exports to make things simplier, but sometimes, like in this example, it doesn't always work out.
plot is an S3 generic method which can be defined as plot.someclass which will create a plotting method for some object x with class "someclass" and can be called simply by plot(x).
roxygen thinks that someclass for your package was "label.wrap" and exported plot.label.wrap as an S3 method rather than a normal function, expecting you to use it as plot(x) where class(x) is "label.wrap" and not trying to use plot.label.wrap directly as you tried (and found it doesn't work).
Alternatively, like #shadow mentioned, you could avoid this confusion by not using periods in function names, eg plot_label_wrap, plot_label.wrap,plot_labelwrap, etc. You don't have to, but in a few rare circumstances, using periods causes unexpected behaviors.
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
I am writing a package that defines a new class, surveyor, and a print method for this, i.e. print.surveyor. My code works fine and I use roxygen for inline documentation. But R CMD check issues a warning:
Functions/methods with usage in
documentation object 'print.surveyor'
but not in code: print
I have used the following two pages, written by Hadley, as inspiration:
Namespaces and Documenting functions, both of which states that the correct syntax is #method function-name class
So my question is: What is the correct way of documenting the print method for my new class using Roxygen? And more specifically, how do I get rid of the warning?
Here is my code: (The commented documentation indicated attempts at fixing this, none of which worked.)
#' Prints surveyor object.
#'
#' Prints surveyor object
#'
## #' #usage print(x, ...)
## #' #aliases print print.surveyor
#' #param x surveyor object
#' #param ... ignored
#' #S3method print surveyor
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
And the roxygenized output, i.e. print.surveyor.Rd:
\name{print.surveyor}
\title{Prints surveyor object.}
\usage{print(x, ...)
#'}
\description{Prints surveyor object.}
\details{Prints surveyor object
#'}
\alias{print}
\alias{print.surveyor}
\arguments{\item{x}{surveyor object}
\item{...}{ignored}}
Update
As of roxygen2 > 3.0.0 the package has gotten a lot smarter at figuring all this out for you. You now just need the #export tag and roxygen will work out what kind of thing you are documenting and do the appropriate thing when writing the NAMESPACE etc during conversion.
There are exceptions where you may need to help out roxygen. An example that Hadley Wickham uses in his R Packages book is all.equal.data.frame. There is ambiguity in that function name as to what is the class and what is the generic function (all, all.equal, or all.equal.data)?
In such cases, you can help roxygen out by explicitly informing it of the generic and class/method, e.g.
#method all.equal data.frame
The original answer below explains more about the older behaviour if you need to explicitly use #method.
Original
The function should be documented with the #method tag:
#' #method print surveyor
On initial reading, #hadley's document was a little confusing for me as I am not familiar with roxygen, but after several readings of the section, I think I understand the reason why you need #method.
You are writing full documentation for the print method. #S3method is related to the NAMESPACE and arranges for the method to be exported. #S3method is not meant for documenting a method.
Your Rd file should have the following in the usage section:
\method{print}{surveyor}(x, ...)
if this works correctly, as that is the correct way to document S3 methods in Rd files.
As of roxygen2 > 3.0.0., you only need #export because roxygen can figure out that print.surveyor is an S3 method. This means that you now only need
#' Prints surveyor object.
#'
#' #param x surveyor object
#' #param ... ignored
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
However, in this case since the documentation isn't very useful, it'd probably better to just do:
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
#export only works if the generic is loaded. If the generic is in another package you need to import the generic. With current roxygen this is solved with a block like
#' #importFrom tibble data_frame
#' #export
tibble::data_frame
taken from dplyr/R/reexport-tibble.r . In this example, the data_frame method is imported from the tibble package, and tibble::data_frame is exported. Such re-exported objects are then documented in a reexports.Rd file that - needless to say - satisfies R CMD check.
I am making a package where I want to define a new method for plot. I am using roxygen in-source documentation. This question seems very similar to:
How to properly document a S3 method of a generic from a different package, using Roxygen?
and
Roxygen2 - how to properly document S3 methods
but I still cannot get it to work.
The relevant parts that are causing me trouble are:
#' Generic plot method
#'
#' #param x \dots
#' #param ... \dots
#' #export
plot <- function(x, ...) UseMethod("plot")
#' Default plot method
#'
#' #param x \dots
#' #param ... \dots
#' #importFrom graphics plot
#' #method plot default
#' #S3method plot default
plot.default <- function(x, ...) graphics::plot(x, ...)
#' Plotting function for ABI object
#'
#' Description.
#'
#' #param x ABI object as generated by newABI.
#' #param base Character. Bases to look at.
#' #param ... Other options passed to plot().
#' #return Nothing. Side-effect: plots graphs.
#' #method plot ABI
#' #S3method plot ABI
plot.ABI <- function(x, base, ...) {
#Overly simplified
plot(1, 1, main = base)
}
When I run this and investigate methods(plot), there is no method defined for ABI objects. Accessing the function by ABI:::plot (ABI is the name of the package) does work. Using :: does not.
During the package build check, there is a warning:
* checking S3 generic/method consistency ... WARNING
plot:
function(x)
plot.ABI:
function(x, base, ...)
See section ‘Generic functions and methods’ of the ‘Writing R
Extensions’ manual.
It seems that there is a disagreement in arguments. But I don't understand this, since the generic has arguments x and ... and so does my ABI method (in addition to base).
So there are two problems, which I hope stem from the same issue: The plot.ABI method is not exported and the package check throws a warning.
How do I solve this?
The problem is that your method needs to have the same arguments as the generic. Let's assume you are using the generic supplied with R:
> args(plot)
function (x, y, ...)
NULL
Now plot() is actually a special case as you can essentially ignore that there is an argument y there.
So your method needs to be as you have it:
plot.ABI <- function(x, base, ...)
The issue is that, contrary to your quoted script, you must have redefined the generic as
plot(x)
and as that is missing ..., R CMD check will rightly complain.
So, don't document or provide the generic if it already exists.
A few problems:
Don't include a generic that is already defined elsewhere. Just add your method.
The signatures of every method must at least include every element in the generic, in the same order. It's annoying sometimes, but it's incontrovertible.
Update
I had said, "Your #export needs to list the function name," but apparently this is not correct. See the comments. Note also that listing the method should export it. I seem to recall needing an explicit export in cases where you aren't including the generic in your package's namespace, but I could be wrong (so often am!).