6

Before you aim and shoot

I'm aware that this question is closely related to this post. In fact, I followed the advice given in the various answers, but still feel that the resulting help file is a bit "awkward" or at least seems a bit "mashed together" and thus my questions

Actual questions

  1. When documenting a S4 generic and its respective methods, how do I end up with an Rd-file structure that lets a user clearly distinguish between the various methods, making it very clear which part of the documentation belongs to which method in particular?
  2. Given that I provided @alias tags, how do I actually use them when trying to get help for a particular method? Something like ?foo-character-method instead of just typing ?foo?
  3. Is it a good practice to better not document the a) signature arguments in the generic method at all since each method will definitely contain the respective documentation and b) the return value as this is also up to the respective methods?

Right now, I feel like I'm ending up with a help file which doesn't really seem to be able to handle a proper distinction between the generic and the various methods - at least not visually.

But maybe I'm still not completely getting this ;-). In this case any pointer would be greatly appreciated!


Here's a reproducible example that produces package mypkg containing a S4 generic and two methods. I tried to follow the advice given in this post and Writing R Extensions

Ensuring directories

sapply(c("src", "package"), dir.create, showWarnings=FALSE)

Generic method definition

gnrc.roxy <- c(
    "#' Doing Something Useful",
    "#'", 
    "#' Description here.",
    "#'", 
    "#' @param x A signature argument for method dispatch.",
    "#' @param y A signature argument for method dispatch.",
    "#' @param arg.1 A \\code{logical} scalar. If \\code{TRUE} (default)", 
    "#'      something happens; else not.",
    "#' @param arg.2 A \\code{numeric} vector containing some useful numbers.", 
    "#' @param ... Further arguments.",
    "#' @return Depends on the actual method.", 
    "#' @references \\url{http://www.rappster.de/}",
    "#' @author Janko Thyson \\email{janko.thyson@@rappster.de}",
    "#' @examples", 
    "#'   foo(x=\"a\", y=letters[1:5])",
    "#'   foo(x=\"a\", y=1:5)",
    "#' @docType methods",
    "#' @rdname foo-methods",
    "#' @export"
)    
gnrc.def <- c(
    "setGeneric(",
    "    name=\"foo\",",
    "    signature=c(\"x\", \"y\"),",
    "    def=function(",
            "x,",
            "y,",
            "arg.1=TRUE,",
            "arg.2,",
            "...",
    ") {",
    "standardGeneric(\"foo\")",       
    "})"
)
path <- "src/gnrc_foo.R"
write(gnrc.roxy, file=path)
write(gnrc.def, file=path, append=TRUE)

Definitions of associated methods

mthd1.roxy <- c(
    "#' @param x A \\code{character} scalar.",
    "#' @param y A \\code{character} vector.",
    "#' @return A \\code{character} vector.", 
    "#' @docType methods",
    "#' @rdname foo-methods",
    "#' @rdname foo-methods",
    "#' @aliases foo,character,character-method",
    "#' @export"
)    
mthd1.def <- c(
    "setMethod(",
        "f=\"foo\",",
        "signature=signature(x=\"character\", y=\"character\"),", 
        "definition=function(",
            "x,",
            "y,", 
            "...",
        ") {",
        "print(x);print(y);return(y)",
        "})"
)    
path <- "src/mthds_foo.R"
write(mthd1.roxy, file=path)
write(mthd1.def, file=path, append=TRUE)

mthd2.roxy <- c(
    "#' @param x A \\code{character} scalar.",
    "#' @param y A \\code{numeric} vector.",
    "#' @return A \\code{numeric} vector.", 
    "#' @docType methods",
    "#' @rdname foo-methods",
    "#' @rdname foo-methods",
    "#' @aliases foo,character,numeric-method",
    "#' @export"
)    
mthd2.def <- c(
    "setMethod(",
        "f=\"foo\",",
        "signature=signature(x=\"character\", y=\"numeric\"),", 
        "definition=function(",
            "x,",
            "y,", 
            "...",
        ") {",
        "print(x);print(y);return(y)",
        "})"
)    
write(mthd2.roxy, file=path, append=TRUE)
write(mthd2.def, file=path, append=TRUE)

# Test source to see if methods were defined correctly
#sapply(list.files("src", full.names=TRUE), source)

Create the package skeleton

# Ensure empty package directory
subdirs <- list.files("package", full.names=TRUE)
if (length(subdirs)) {
    sapply(subdirs, unlink, recursive=TRUE)
}

pkg.name    <- "mypkg"
path        <- file.path("package", pkg.name)

package.skeleton(
    name=pkg.name, 
    path="package", 
    code_files=list.files("src", full.names=TRUE, recursive=TRUE)
)

Roxygenize

require("roxygen2")
roxygenize(package.dir=path)

Patching Rd files

Some things need to be patched in order to allow for an automated check and build process that does not require any manual intervention such as manually editing Rd files etc.

rdfiles <- list.files(file.path(path, "man"), full.names=TRUE)

# 1) Removing unnecessary file './package/mypgk/man/foo.Rd'
file <- grep("foo.Rd", rdfiles, value=TRUE)
if (length(file)) {
    unlink(file)
}

# 2) Patching './mypkg/man/mypkg-package.Rd' to pass R CMD CHECK
file <- grep(paste(pkg.name, "-package.Rd", sep=""), rdfiles, value=TRUE)
if (length(file)) {
    cnt <- readLines(file, warn=FALSE)
    idx.0 <- grep("\\\\examples\\{", cnt)
    if (length(idx.0)) {
        idx.1 <- grep("\\}", cnt)
        idx.1 <- max(idx.1[which(idx.1 > idx.0)])
        exnew <- c(
            "\\examples{",
            "# TODO: add examples",
            "}"
        )
        cnt <- cnt[-(idx.0:idx.1)]
        cnt <- append(cnt, exnew, after=idx.0-1)
        write(cnt, file=file)
    }
}

Check the package

shell(paste("R CMD check", path), intern=FALSE)

Build and install the package

shell(paste("R CMD INSTALL",  path), intern=FALSE)

Investigate the help file

require("mypkg")

foo(x="a", y=letters)
foo(x="a", y=1:10)

?foo

Alternative way: separation of build and install

shell(paste("R CMD INSTALL --build --data-compress=gzip ",  path), intern=FALSE)

install.packages(paste0(pkg.name, "_1.0.zip"), type="win.binary")

require("mypkg")

?foo
Community
  • 1
  • 1
Rappster
  • 12,762
  • 7
  • 71
  • 120
  • 1
    I think you should have a look at the development version of [Roxygen3](https://github.com/hadley/roxygen3). Lately Hadley is doing a lot on it. Btw, great question (+1). – Henrik Sep 18 '12 at 11:50

0 Answers0