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

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?

Related

Examples set using #examples fails devtools::check()

I am making an R package, and using roxygen2 to create documentation.
I have provided an example for one of the functions using:
#' #examples
#' \dontrun{
#' Train_model()
#' }
I have included an #export tag before this.
But, when I run devtools::check(). I get the following error:
Error in library("package1") :
there is no package called 'package1'
package1 is the name of the package I am creating.

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.

Why does the #family tag add dots between words in roxygen2?

I am writing an R package and create documentation using roxygen2. I build the package and the documentation using the button Build & Reload in RStudio. According to RStudio's output, it uses devtools::document(roclets=c('rd', 'namespace')) to compile the documentation.
I want to use the #family tag to link together a number of functions in the documentation and this is where my problem occurs. This line
#' #family functions returning some object
is converted in the .Rd file to the following
\seealso{
Other functions.returning.some.object: \code{\link{test2}}
}
I don't want the dots between the words. I have an older package, where this does not happen, even if I recompile the documentation in the exact same setting as I compile the new package. I can see no fundamental difference between this older package and my new attempt.
I have written a very simple test package, where the problem also occurs. It contains a single R file (testpackage.R):
#' Test function 1
#'
#' #param x a number
#'
#' #family functions returning some object
#' #family aggregate functions
#'
#' #export
test1 <- function(x) {
x*x
}
#' Test function 2
#'
#' #param x a number
#'
#' #family functions returning some object
#' #family aggregate functions
#'
#' #export
test2 <- function(x) {
x*x*x
}
The DESCRIPTION file is
Package: testpackage
Type: Package
Title: Package for testing purposes
Version: 1.0
Date: 2015-05-21
Author: Me
Maintainer: Me <me#somewhere.com>
Description: Package for testing purposes
License: GPL-3
NAMESPACE is generated by roxygen. For the documentation test1.Rd, I get:
% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/testpackage.R
\name{test1}
\alias{test1}
\title{Test function 1}
\usage{
test1(x)
}
\arguments{
\item{x}{a number}
}
\description{
Test function 1
}
\seealso{
Other aggregate.functions: \code{\link{test2}}
Other functions.returning.some.object: \code{\link{test2}}
}
with the unwanted dots in the \seealso section. Clearly, the number of words in the #family tag seems not to matter. I have tried enclosing the text in quotation marks, various kinds of brackets, etc. with no positive effect. Of course, I could edit the Rd files, but this would miss the point of using roxygen2.
R CMD check runs without warnings or errors on testpackage.
Why do these dots appear? And how can I get rid of them?
This is a bug in roxygen2 -- I've logged an issue here. It effectively results from the use of unstack(), which performs some unwanted conversions.
I upgraded to Roxygen 5.0.0 (which is now the CRAN version) and found that the problem went away.

Resources