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
- 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?
- 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
? - 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