[Roxygen-commits] r237 - in pkg: . R man

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Mon Jul 27 18:31:34 CEST 2009


Author: manuel
Date: 2009-07-27 18:31:31 +0200 (Mon, 27 Jul 2009)
New Revision: 237

Added:
   pkg/R/Rd2.R
   pkg/R/Rdapi.R
   pkg/R/Rdmerge.R
   pkg/R/Rdtank.R
   pkg/R/parseS4.R
   pkg/man/make.Rd2.roclet.Rd
Modified:
   pkg/DESCRIPTION
   pkg/NAMESPACE
   pkg/R/Rd.R
   pkg/R/namespace.R
   pkg/R/parse.R
   pkg/R/roxygen.R
   pkg/R/roxygenize.R
   pkg/man/roxygen-package.Rd
   pkg/man/roxygenize.Rd
Log:
merge manuel-branch: add Rd2 and friends; set version to 0.1-1.

Modified: pkg/DESCRIPTION
===================================================================
--- pkg/DESCRIPTION	2009-07-27 11:35:02 UTC (rev 236)
+++ pkg/DESCRIPTION	2009-07-27 16:31:31 UTC (rev 237)
@@ -1,5 +1,5 @@
 Package: roxygen
-Version: 0.1
+Version: 0.1-1
 License: GPL (>= 2)
 Description: A Doxygen-like in-source documentation system for Rd,
     collation, namespace and callgraphs.
@@ -8,7 +8,8 @@
     <Manuel.Eugster at stat.uni-muenchen.de>
 Maintainer: Peter Danenberg <pcd at roxygen.org>
 URL: http://roxygen.org
-Suggests: Rgraphviz (>= 1.19.2)
+Suggests: Rgraphviz (>= 1.19.2), tools (>= 2.9.1)
 Collate: 'functional.R' 'list.R' 'roxygen.R' 'string.R' 'parse.R'
-    'roclet.R' 'callgraph.R' 'description.R' 'collate.R' 'namespace.R'
-    'Rd.R' 'roxygenize.R'
+    'parseS4.R' 'roclet.R' 'callgraph.R' 'description.R' 'collate.R' 
+    'namespace.R' 'Rd.R' 'Rdmerge.R' 'Rdapi.R' 'Rdtank.R' 'Rd2.R'
+    'roxygenize.R'

Modified: pkg/NAMESPACE
===================================================================
--- pkg/NAMESPACE	2009-07-27 11:35:02 UTC (rev 236)
+++ pkg/NAMESPACE	2009-07-27 16:31:31 UTC (rev 237)
@@ -22,6 +22,7 @@
 export(parse.files)
 export(parse.text)
 export(make.Rd.roclet)
+export(make.Rd2.roclet)
 export(make.roclet)
 export(expression.from.partitum)
 export(roxygenize)

Modified: pkg/R/Rd.R
===================================================================
--- pkg/R/Rd.R	2009-07-27 11:35:02 UTC (rev 236)
+++ pkg/R/Rd.R	2009-07-27 16:31:31 UTC (rev 237)
@@ -1,480 +1,479 @@
-#' @include parse.R
-#' @include list.R
-#' @include string.R
-#' @include roclet.R
-#' @include parse.R
-roxygen()
-
-register.preref.parsers(parse.value,
-                        'name',
-                        'aliases',
-                        'title',
-                        'usage',
-                        'references',
-                        'concept',
-                        'note',
-                        'seealso',
-                        'example',
-                        'examples',
-                        'keywords',
-                        'return',
-                        'author',
-                        'TODO',
-                        'format',
-                        'source')
-
-register.preref.parsers(parse.name.description,
-                        'param',
-                        'method')
-
-register.preref.parsers(parse.name,
-                        'docType')
-
-register.srcref.parser('setClass',
-                       function(pivot, expression)
-                       list(S4class=car(expression)))
-
-register.srcref.parser('setGeneric',
-                       function(pivot, expression)
-                       list(S4generic=car(expression)))
-
-register.srcref.parser('setMethod',
-                       function(pivot, expression)
-                       list(S4method=car(expression),
-                            signature=cadr(expression)))
-
-#' Make an Rd roclet which parses the given files and, if specified, populates
-#' the given subdirectory with Rd files; or writes to standard out.  See
-#' \cite{Writing R Extensions}
-#' (\url{http://cran.r-project.org/doc/manuals/R-exts.pdf}) for details.
-#'
-#' The first paragraph of a roxygen block constitutes its description, the
-#' subsequent paragraphs its details; moreover, the Rd roclet supports these
-#' tags:
-#'
-#' \tabular{ll}{
-#' Roxygen tag \tab Rd analogue\cr
-#' \code{@@author} \tab \code{\\author}\cr
-#' \code{@@aliases} \tab \code{\\alias, ...}\cr
-#' \code{@@concept} \tab \code{\\concept}\cr
-#' \code{@@example} \tab \emph{n/a}\cr
-#' \code{@@examples} \tab \code{\\examples}\cr
-#' \code{@@format} \tab \code{\\format}\cr
-#' \code{@@keywords} \tab \code{\\keyword, ...}\cr
-#' \code{@@method} \tab \code{\\method}\cr
-#' \code{@@name} \tab \code{\\name}\cr
-#' \code{@@note} \tab \code{\\note}\cr
-#' \code{@@param} \tab \code{\\arguments{\\item, ...}}\cr
-#' \code{@@references} \tab \code{\\references}\cr
-#' \code{@@return} \tab \code{\\value}\cr
-#' \code{@@seealso} \tab \code{\\seealso}\cr
-#' \code{@@source} \tab \code{\\source}\cr
-#' \code{@@title} \tab \code{\\title}\cr
-#' \code{@@TODO} \tab \emph{n/a}\cr
-#' \code{@@usage} \tab \code{\\usage}\cr
-#' }
-#'
-#' \enumerate{
-#' \item{\code{@@author}}{See \dQuote{2.1.1 Documenting functions} from
-#'                        \cite{Writing R Extensions}.}
-#' \item{\code{@@aliases}}{A default alias is plucked from the \code{@@name} or
-#'                         assignee; otherwise, \code{@@alias a b ...} translates
-#'                         to \code{\\alias{a}}, \code{\\alias{b}}, &c.
-#'                         If you specify one alias, however, specify them all.}
-#' \item{\code{@@concept}}{See \dQuote{2.8 Indices} from
-#'                         \cite{Writing R Extensions}.}
-#' \item{\code{@@example}}{Each \code{@@example} tag specifies an example file
-#'                         relative to the package head; if the file resides in
-#'                         \file{tests}, for instance, it will be checked with
-#'                         \command{R CMD check}.
-#'                         The contents of the file will
-#'                         be concatenated under \code{\\examples{...}}.}
-#' \item{\code{@@examples}}{Verbatim examples; see \dQuote{2.1.1
-#'                          Documenting functions} from \cite{Writing R
-#'                          Extensions}.}
-#' \item{\code{@@format}}{See \dQuote{2.1.2 Documenting data sets} from
-#'                        \cite{Writing R Extensions}.}
-#' \item{\code{@@keywords}}{\code{@@keywords a b ...} translates to
-#'                          \code{\\keyword{a}}, \code{\\keyword{b}}, &c.}
-#' \item{\code{@@method}}{Use \code{@@method <generic> <class>} to document
-#'                        S3 functions.}
-#' \item{\code{@@name}}{In the absense of an explicit \code{@@name} tag, the
-#'                      name of an assignment is plucked from the assignee.}
-#' \item{\code{@@note}}{See \dQuote{2.1.1 Documenting functions} from
-#'                      \cite{Writing R Extensions}.}
-#' \item{\code{@@param}}{Each function variable should have a
-#'                       \code{@@param <variable> <description>} specified.}
-#' \item{\code{@@references}}{See \dQuote{2.1.1 Documenting functions} from
-#'                            \cite{Writing R Extensions}.}
-#' \item{\code{@@return}}{The return value of the function, or \code{NULL}.}
-#' \item{\code{@@seealso}}{See \dQuote{2.1.1 Documenting functions} from
-#'                         \cite{Writing R Extensions}.}
-#' \item{\code{@@source}}{See \dQuote{2.1.2 Documenting data sets} from
-#'                        \cite{Writing R Extensions}.}
-#' \item{\code{@@title}}{A default title is plucked from the first sentence
-#'                       of the description; that is, the first phrase ending
-#'                       with a period, question mark or newline.
-#'                       In the absence of a description, the title becomes
-#'                       the \code{@@name} or assignee; lastly, it can be
-#'                       overridden with \code{@@title}.}
-#' \item{\code{@@TODO}}{Note to developers to get off their asses.}
-#' \item{\code{@@usage}}{A default usage is construed from a function's formals,
-#'                       but can be overridden with \code{@@usage} (e.g. in the case
-#'                       of multiple functions in one Rd unit).}
-#' }
-#'
-#' @param subdir directory into which to place the Rd files; if
-#' \code{NULL}, standard out.
-#' @param verbose whether to declare what we're doing in the
-#' \var{subdir}
-#' @return Rd roclet
-#' @examples
-#' #' This sentence describes the function.
-#' #'
-#' #' Here are the details (notice the preceding blank
-#' #' line); the name, title, usage and alias will be
-#' #' automatically generated.
-#' #'
-#' #' @@param a a parameter
-#' #' @@return NULL
-#' f <- function(a=1) NULL
-#'
-#' #' S3 functions require a @@method tag for
-#' #' the time being.
-#' #'
-#' #' @@method specialize foo
-#' #' @@param f a generic foo
-#' #' @@param ... ignored
-#' #' @@return The specialized foo
-#' specialize.foo <- function(f, ...)
-#'   actually.specialize(f)
-#'
-#' roclet <- make.Rd.roclet('man')
-#' \dontrun{roclet$parse('example.R')}
-#' @export
-#' @aliases name aliases title usage references concept
-#' note seealso example examples keywords return author
-#' make.Rd.roclet
-#' @TODO param method setClass setGeneric setMethod
-#' make.Rd.roclet
-make.Rd.roclet <- function(subdir=NULL,
-                           verbose=TRUE) {
-  #' Translate a key and expressions into an Rd expression;
-  #' multiple expressions take their own braces.
-  #' @param key the expression's key
-  #' @param \dots the arguments
-  #' @return A string containing the key and arguments
-  #' in LaTeX-like gestalt.
-  Rd.expression <- function(key, ...)
-    sprintf('\\%s%s\n',
-            key,
-            Reduce.paste(function(expression)
-                         sprintf('{%s}', trim(expression)),
-                         c(...),
-                         ''))
-
-  #' Push the Rd-expression to standard out (or current
-  #' sink).
-  #' @param key the expression's key
-  #' @param \dots the arguments
-  #' @return \code{NULL}
-  parse.expression <- function(key, ...)
-    cat(Rd.expression(key, c(...)), file=filename, append=TRUE)
-
-  filename <- ''
-
-  reset.filename <- function()
-    assign.parent('filename', '', environment())
-
-  first.source.line <- function(partitum) {
-    srcfile <- srcfile(partitum$srcref$filename)
-    first.line <- car(partitum$srcref$lloc)
-    getSrcLines(srcfile, first.line, first.line)
-  }
-
-  #' What does the noop look like?
-  NULL.STATEMENT <- 'roxygen[[:space:]]*()'
-
-  #' Does the statement contain a noop-like?
-  #' @param source.line the line of source code
-  #' @return Whether the statement contains a noop
-  is.null.statement <- function(source.line)
-    length(grep(NULL.STATEMENT, source.line) > 0)
-
-  #' @note Doesn't work recursively!
-  de.tex <- function(string)
-    gsub('\\\\[^{]*\\{([^}]*)(}|)',
-         '\\1',
-         string,
-         perl=TRUE)
-
-  #' First sentence of a string, defined as first
-  #' period, question mark or newline.
-  #' @param description the string to be first-sentenced
-  #' @return The first sentence
-  first.sentence <- function(description) {
-    description <- de.tex(description)
-    r <- regexpr('[^.?\n]*(\\.(?!\\w)|\\?|\n|)',
-                 description,
-                 perl=TRUE)
-    sentence <- substr(description, r, attr(r, 'match.length'))
-    if (length(sentence) == 0 || is.null.string(sentence))
-      NULL
-    else {
-      chars <- nchar(sentence)
-      last.char <- substr(sentence, chars, chars)
-      if (last.char == '.' || last.char == '?')
-        sentence
-      else
-        paste(trim(sentence), '...', sep='')
-    }
-  }
-
-  #' If \code{@@title} is specified, use it; or
-  #' take the first sentence of the description;
-  #' or, lastly, take the name.
-  #' @param partitum the parsed elements
-  #' @param name the calculated name-fallback
-  #' @return The parsed title
-  parse.title <- function(partitum, name) {
-    if (!is.null(partitum$title))
-      partitum$title
-    else if (!is.null(first.sentence <-
-                      first.sentence(partitum$description)))
-      first.sentence
-    else
-      name
-  }
-  
-  #' Reconstruct the \name directive from amongst
-  #' \code{@@name}, \code{@@setMethod}, \code{@@setClass},
-  #' \code{@@setGeneric}, \code{@@assignee}, etc.
-  #' @param partitum the pre-parsed elements
-  #' @return \code{NULL}
-  parse.name <- function(partitum) {
-    name <- guess.name(partitum)
-    if (is.null(name) && !is.null(subdir)) {
-      filename <- partitum$srcref$filename
-      first.line <- car(partitum$srcref$lloc)
-      first.source.line <- first.source.line(partitum)
-      if (!is.null.statement(first.source.line))
-        warning(sprintf(paste('No name found for the',
-                              'following expression in %s',
-                              'line %s:\n  `%s . . .\''),
-                        filename,
-                        first.line,
-                        first.source.line),
-                immediate.=TRUE)
-    } else if (!is.null(name)) {
-      name <- trim(name)
-      if (!is.null(subdir)) {
-        assign.parent('filename',
-                      file.path(subdir, sprintf('%s.Rd', name)),
-                      environment())
-        if (verbose)
-          cat(sprintf('Writing %s to %s\n', name, filename))
-        unlink(filename)
-      }
-      parse.expression('name', name)
-      if (is.null(partitum$aliases))
-        parse.expression('alias', name)
-    }
-    if ((!is.null(name) || !is.null(partitum$title)) &&
-        !is.null(title <- parse.title(partitum, name)))
-      parse.expression('title', title)
-  }
-  
-  parse.function.name <- function(partitum) {
-    if (!is.null(partitum$method))
-      Rd.expression('method',
-          car(partitum$method),
-          cadr(partitum$method))
-    else
-      partitum$assignee
-  }
-
-  #' Turn a list of formal arguments into a human-readable
-  #' function-like.
-  #' @param partitum the pre-parsed elements
-  #' @return \code{NULL}
-  parse.formals <- function(partitum) {
-    formals <- partitum$formals
-    if (!is.null(formals)) {
-      name.defaults <- zip.c(names(formals), formals)
-      args <-
-        do.call(paste, c(Map(function(name.default) {
-          name <- car(name.default)
-          default <- cadr(name.default)
-          if (is.null.string(default))
-            name
-          else
-            sprintf('%s=%s', name, default)
-        },
-                             name.defaults),
-                         sep=', '))
-      parse.expression('usage',
-          do.call(paste,
-                  c(as.list(strwrap
-                            (sprintf('%s(%s)',
-                                     parse.function.name(partitum),
-                                     args),
-                             exdent=4)),
-                    sep='\n')))
-    }
-  }
-
-  #' Prefer explicit \code{@@usage} to a \code{@@formals} list.
-  #' @param partitum the pre-parsed elements
-  #' @return \code{NULL}
-  parse.usage <- function(partitum) {
-    if (is.null(partitum$usage))
-      parse.formals(partitum)
-    else
-      parse.expression('usage', partitum$usage)
-  }
-
-  #' Reset params; parse name and usage.
-  #' @param partitum the pre-parsed elements
-  #' @return \code{NULL}
-  pre.parse <- function(partitum) {
-    assign.parent('params', NULL, environment())
-    assign.parent('examples', NULL, environment())
-    parse.name(partitum)
-    parse.usage(partitum)
-  }
-
-  #' Parse params.
-  #' @param partitum the pre-parsed elements
-  #' @return \code{NULL}
-  post.parse <- function(partitum) {
-    parse.arguments()
-    parse.examples(partitum)
-    ## Assuming the previous sink was successful;
-    ## if not, it will destroy the sink stack.
-    ## (Should fail if unwritable, anyway.)
-    reset.filename()
-  }
-
-  roclet <- make.roclet(parse.expression,
-                        pre.parse,
-                        post.parse)
-
-  roclet$register.default.parsers('references',
-                                  'note',
-                                  'author',
-                                  'seealso',
-                                  'concept',
-                                  'docType')
-
-  roclet$register.parser('return',
-                         function(key, expressions)
-                         parse.expression('value', expressions))
-
-  #' Split a plural into its constituent singulars.
-  #' @param key the singular key
-  #' @param expressions the plurality of expressions
-  #' @return \code{NULL}
-  parse.split <- function(key, expressions) {
-    expression <- strcar(expressions)
-    rest <- strcdr(expressions)
-    parse.expression(key, expression)
-    if (!is.null.string(rest))
-      parse.split(key, rest)
-  }
-
-  roclet$register.parser('aliases',
-                         function(key, expressions)
-                         parse.split('alias', expressions))
-
-  roclet$register.parser('keywords',
-                         function(key, expressions)
-                         parse.split('keyword', expressions))
-
-  #' Split the introductory matter into its description followed
-  #' by details (separated by a blank line).
-  #' @param key ignored
-  #' @param expressions the to-be-parsed description and details
-  #' @return \code{NULL}
-  parse.description <- function(key, expressions) {
-    paragraphs <- car(strsplit(car(expressions), '\n\n', fixed=TRUE))
-    description <- car(paragraphs)
-    details <- do.call(paste, append(cdr(paragraphs), list(sep='\n\n')))
-    parse.expression('description', description)
-    if (length(details) > 0 && !is.null.string(details))
-      parse.expression('details', details)
-  }
-
-  roclet$register.parser('description', parse.description)
-
-  params <- NULL
-
-  #' Add a parameter to the global param list.
-  #' @param key ignored
-  #' @param expression the parameter
-  #' @return \code{NULL}
-  parse.param <- function(key, expression)
-    assign.parent('params',
-                  append(params, list(expression)),
-                  environment())
-    
-  #' Reduce and paste together the various parameters
-  #' in an Rd-readable list (with \code{\\item}s, etc.).
-  #' @param name.param name-param pair
-  #' @return A list of Rd-readable expressions
-  parse.params <- function()
-    Reduce.paste(function(name.param)
-                 Rd.expression('item',
-                     car(name.param),
-                     cadr(name.param)),
-                 params,
-                 '')
-
-  #' Paste and label the Rd-readable expressions
-  #' returned by \code{parse.params}.
-  #' @return \code{NULL}
-  parse.arguments <- function()
-    if (length(params) > 0)
-      parse.expression('arguments', parse.params())
-
-  roclet$register.parser('param', parse.param)
-
-  examples <- NULL
-
-  #' Parse individual \code{@@example} clauses by adding the
-  #' pointed-to file to a global store.
-  #' @param key ignored
-  #' @param expression the file containing the example(s)
-  #' @return \code{NULL}
-  parse.example <- function(key, expression)
-    assign.parent('examples',
-                  append(examples, expression),
-                  environment())
-
-  #' If \code{@@examples} is provided, use that; otherwise, concatenate
-  #' the files pointed to by each \code{@@example}.
-  #' @param partitum the parsed elements
-  #' @return \code{NULL}
-  parse.examples <- function(partitum) {
-    if (!is.null(partitum$examples))
-      parse.expression('examples', partitum$examples)
-    else {
-      examples <- Reduce(c, Map(function(file)
-                                tryCatch(readLines(trim(file)),
-                                         error=function(e) NULL),
-                                examples),
-                         NULL)
-      if (!is.null(examples))
-        parse.expression('examples',
-            do.call(paste, c(as.list(examples), sep='\n')))
-    }
-  }
-
-  roclet$register.parser('example', parse.example)
-
-  parse.todo <- function(key, value)
-    parse.expression('section', 'TODO', value)
-
-  roclet$register.parser('TODO', parse.todo)
-
-  roclet
-}
+#' @include list.R
+#' @include string.R
+#' @include roclet.R
+#' @include parse.R
+roxygen()
+
+register.preref.parsers(parse.value,
+                        'name',
+                        'aliases',
+                        'title',
+                        'usage',
+                        'references',
+                        'concept',
+                        'note',
+                        'seealso',
+                        'example',
+                        'examples',
+                        'keywords',
+                        'return',
+                        'author',
+                        'TODO',
+                        'format',
+                        'source')
+
+register.preref.parsers(parse.name.description,
+                        'param',
+                        'method')
+
+register.preref.parsers(parse.name,
+                        'docType')
+
+register.srcref.parser('setClass',
+                       function(pivot, expression)
+                       list(S4class=car(expression)))
+
+register.srcref.parser('setGeneric',
+                       function(pivot, expression)
+                       list(S4generic=car(expression)))
+
+register.srcref.parser('setMethod',
+                       function(pivot, expression)
+                       list(S4method=car(expression),
+                            signature=cadr(expression)))
+
+#' Make an Rd roclet which parses the given files and, if specified, populates
+#' the given subdirectory with Rd files; or writes to standard out.  See
+#' \cite{Writing R Extensions}
+#' (\url{http://cran.r-project.org/doc/manuals/R-exts.pdf}) for details.
+#'
+#' The first paragraph of a roxygen block constitutes its description, the
+#' subsequent paragraphs its details; moreover, the Rd roclet supports these
+#' tags:
+#'
+#' \tabular{ll}{
+#' Roxygen tag \tab Rd analogue\cr
+#' \code{@@author} \tab \code{\\author}\cr
+#' \code{@@aliases} \tab \code{\\alias, ...}\cr
+#' \code{@@concept} \tab \code{\\concept}\cr
+#' \code{@@example} \tab \emph{n/a}\cr
+#' \code{@@examples} \tab \code{\\examples}\cr
+#' \code{@@format} \tab \code{\\format}\cr
+#' \code{@@keywords} \tab \code{\\keyword, ...}\cr
+#' \code{@@method} \tab \code{\\method}\cr
+#' \code{@@name} \tab \code{\\name}\cr
+#' \code{@@note} \tab \code{\\note}\cr
+#' \code{@@param} \tab \code{\\arguments{\\item, ...}}\cr
+#' \code{@@references} \tab \code{\\references}\cr
+#' \code{@@return} \tab \code{\\value}\cr
+#' \code{@@seealso} \tab \code{\\seealso}\cr
+#' \code{@@source} \tab \code{\\source}\cr
+#' \code{@@title} \tab \code{\\title}\cr
+#' \code{@@TODO} \tab \emph{n/a}\cr
+#' \code{@@usage} \tab \code{\\usage}\cr
+#' }
+#'
+#' \enumerate{
+#' \item{\code{@@author}}{See \dQuote{2.1.1 Documenting functions} from
+#'                        \cite{Writing R Extensions}.}
+#' \item{\code{@@aliases}}{A default alias is plucked from the \code{@@name} or
+#'                         assignee; otherwise, \code{@@alias a b ...} translates
+#'                         to \code{\\alias{a}}, \code{\\alias{b}}, &c.
+#'                         If you specify one alias, however, specify them all.}
+#' \item{\code{@@concept}}{See \dQuote{2.8 Indices} from
+#'                         \cite{Writing R Extensions}.}
+#' \item{\code{@@example}}{Each \code{@@example} tag specifies an example file
+#'                         relative to the package head; if the file resides in
+#'                         \file{tests}, for instance, it will be checked with
+#'                         \command{R CMD check}.
+#'                         The contents of the file will
+#'                         be concatenated under \code{\\examples{...}}.}
+#' \item{\code{@@examples}}{Verbatim examples; see \dQuote{2.1.1
+#'                          Documenting functions} from \cite{Writing R
+#'                          Extensions}.}
+#' \item{\code{@@format}}{See \dQuote{2.1.2 Documenting data sets} from
+#'                        \cite{Writing R Extensions}.}
+#' \item{\code{@@keywords}}{\code{@@keywords a b ...} translates to
+#'                          \code{\\keyword{a}}, \code{\\keyword{b}}, &c.}
+#' \item{\code{@@method}}{Use \code{@@method <generic> <class>} to document
+#'                        S3 functions.}
+#' \item{\code{@@name}}{In the absense of an explicit \code{@@name} tag, the
+#'                      name of an assignment is plucked from the assignee.}
+#' \item{\code{@@note}}{See \dQuote{2.1.1 Documenting functions} from
+#'                      \cite{Writing R Extensions}.}
+#' \item{\code{@@param}}{Each function variable should have a
+#'                       \code{@@param <variable> <description>} specified.}
+#' \item{\code{@@references}}{See \dQuote{2.1.1 Documenting functions} from
+#'                            \cite{Writing R Extensions}.}
+#' \item{\code{@@return}}{The return value of the function, or \code{NULL}.}
+#' \item{\code{@@seealso}}{See \dQuote{2.1.1 Documenting functions} from
+#'                         \cite{Writing R Extensions}.}
+#' \item{\code{@@source}}{See \dQuote{2.1.2 Documenting data sets} from
+#'                        \cite{Writing R Extensions}.}
+#' \item{\code{@@title}}{A default title is plucked from the first sentence
+#'                       of the description; that is, the first phrase ending
+#'                       with a period, question mark or newline.
+#'                       In the absence of a description, the title becomes
+#'                       the \code{@@name} or assignee; lastly, it can be
+#'                       overridden with \code{@@title}.}
+#' \item{\code{@@TODO}}{Note to developers to get off their asses.}
+#' \item{\code{@@usage}}{A default usage is construed from a function's formals,
+#'                       but can be overridden with \code{@@usage} (e.g. in the case
+#'                       of multiple functions in one Rd unit).}
+#' }
+#'
+#' @param subdir directory into which to place the Rd files; if
+#' \code{NULL}, standard out.
+#' @param verbose whether to declare what we're doing in the
+#' \var{subdir}
+#' @return Rd roclet
+#' @examples
+#' #' This sentence describes the function.
+#' #'
+#' #' Here are the details (notice the preceding blank
+#' #' line); the name, title, usage and alias will be
+#' #' automatically generated.
+#' #'
+#' #' @@param a a parameter
+#' #' @@return NULL
+#' f <- function(a=1) NULL
+#'
+#' #' S3 functions require a @@method tag for
+#' #' the time being.
+#' #'
+#' #' @@method specialize foo
+#' #' @@param f a generic foo
+#' #' @@param ... ignored
+#' #' @@return The specialized foo
+#' specialize.foo <- function(f, ...)
+#'   actually.specialize(f)
+#'
+#' roclet <- make.Rd.roclet('man')
+#' \dontrun{roclet$parse('example.R')}
+#' @export
+#' @aliases name aliases title usage references concept
+#' note seealso example examples keywords return author
+#' make.Rd.roclet
+#' @TODO param method setClass setGeneric setMethod
+#' make.Rd.roclet
+make.Rd.roclet <- function(subdir=NULL,
+                           verbose=TRUE) {
+  #' Translate a key and expressions into an Rd expression;
+  #' multiple expressions take their own braces.
+  #' @param key the expression's key
+  #' @param \dots the arguments
+  #' @return A string containing the key and arguments
+  #' in LaTeX-like gestalt.
+  Rd.expression <- function(key, ...)
+    sprintf('\\%s%s\n',
+            key,
+            Reduce.paste(function(expression)
+                         sprintf('{%s}', trim(expression)),
+                         c(...),
+                         ''))
+
+  #' Push the Rd-expression to standard out (or current
+  #' sink).
+  #' @param key the expression's key
+  #' @param \dots the arguments
+  #' @return \code{NULL}
+  parse.expression <- function(key, ...)
+    cat(Rd.expression(key, c(...)), file=filename, append=TRUE)
+
+  filename <- ''
+
+  reset.filename <- function()
+    assign.parent('filename', '', environment())
+
+  first.source.line <- function(partitum) {
+    srcfile <- srcfile(partitum$srcref$filename)
+    first.line <- car(partitum$srcref$lloc)
+    getSrcLines(srcfile, first.line, first.line)
+  }
+
+  #' What does the noop look like?
+  NULL.STATEMENT <- 'roxygen[[:space:]]*()'
+
+  #' Does the statement contain a noop-like?
+  #' @param source.line the line of source code
+  #' @return Whether the statement contains a noop
+  is.null.statement <- function(source.line)
+    length(grep(NULL.STATEMENT, source.line) > 0)
+
+  #' @note Doesn't work recursively!
+  de.tex <- function(string)
+    gsub('\\\\[^{]*\\{([^}]*)(}|)',
+         '\\1',
+         string,
+         perl=TRUE)
+
+  #' First sentence of a string, defined as first
+  #' period, question mark or newline.
+  #' @param description the string to be first-sentenced
+  #' @return The first sentence
+  first.sentence <- function(description) {
+    description <- de.tex(description)
+    r <- regexpr('[^.?\n]*(\\.(?!\\w)|\\?|\n|)',
+                 description,
+                 perl=TRUE)
+    sentence <- substr(description, r, attr(r, 'match.length'))
+    if (length(sentence) == 0 || is.null.string(sentence))
+      NULL
+    else {
+      chars <- nchar(sentence)
+      last.char <- substr(sentence, chars, chars)
+      if (last.char == '.' || last.char == '?')
+        sentence
+      else
+        paste(trim(sentence), '...', sep='')
+    }
+  }
+
+  #' If \code{@@title} is specified, use it; or
+  #' take the first sentence of the description;
+  #' or, lastly, take the name.
+  #' @param partitum the parsed elements
+  #' @param name the calculated name-fallback
+  #' @return The parsed title
+  parse.title <- function(partitum, name) {
+    if (!is.null(partitum$title))
+      partitum$title
+    else if (!is.null(first.sentence <-
+                      first.sentence(partitum$description)))
+      first.sentence
+    else
+      name
+  }
+  
+  #' Reconstruct the \name directive from amongst
+  #' \code{@@name}, \code{@@setMethod}, \code{@@setClass},
+  #' \code{@@setGeneric}, \code{@@assignee}, etc.
+  #' @param partitum the pre-parsed elements
+  #' @return \code{NULL}
+  parse.name <- function(partitum) {
+    name <- guess.name(partitum)
+    if (is.null(name) && !is.null(subdir)) {
+      filename <- partitum$srcref$filename
+      first.line <- car(partitum$srcref$lloc)
+      first.source.line <- first.source.line(partitum)
+      if (!is.null.statement(first.source.line))
+        warning(sprintf(paste('No name found for the',
+                              'following expression in %s',
+                              'line %s:\n  `%s . . .\''),
+                        filename,
+                        first.line,
+                        first.source.line),
+                immediate.=TRUE)
+    } else if (!is.null(name)) {
+      name <- trim(name)
+      if (!is.null(subdir)) {
+        assign.parent('filename',
+                      file.path(subdir, sprintf('%s.Rd', name)),
+                      environment())
+        if (verbose)
+          cat(sprintf('Writing %s to %s\n', name, filename))
+        unlink(filename)
+      }
+      parse.expression('name', name)
+      if (is.null(partitum$aliases))
+        parse.expression('alias', name)
+    }
+    if ((!is.null(name) || !is.null(partitum$title)) &&
+        !is.null(title <- parse.title(partitum, name)))
+      parse.expression('title', title)
+  }
+  
+  parse.function.name <- function(partitum) {
+    if (!is.null(partitum$method))
+      Rd.expression('method',
+          car(partitum$method),
+          cadr(partitum$method))
+    else
+      partitum$assignee
+  }
+
+  #' Turn a list of formal arguments into a human-readable
+  #' function-like.
+  #' @param partitum the pre-parsed elements
+  #' @return \code{NULL}
+  parse.formals <- function(partitum) {
+    formals <- partitum$formals
+    if (!is.null(formals)) {
+      name.defaults <- zip.c(names(formals), formals)
+      args <-
+        do.call(paste, c(Map(function(name.default) {
+          name <- car(name.default)
+          default <- cadr(name.default)
+          if (is.null.string(default))
+            name
+          else
+            sprintf('%s=%s', name, default)
+        },
+                             name.defaults),
+                         sep=', '))
+      parse.expression('usage',
+          do.call(paste,
+                  c(as.list(strwrap
+                            (sprintf('%s(%s)',
+                                     parse.function.name(partitum),
+                                     args),
+                             exdent=4)),
+                    sep='\n')))
+    }
+  }
+
+  #' Prefer explicit \code{@@usage} to a \code{@@formals} list.
+  #' @param partitum the pre-parsed elements
+  #' @return \code{NULL}
+  parse.usage <- function(partitum) {
+    if (is.null(partitum$usage))
+      parse.formals(partitum)
+    else
+      parse.expression('usage', partitum$usage)
+  }
+
+  #' Reset params; parse name and usage.
+  #' @param partitum the pre-parsed elements
+  #' @return \code{NULL}
+  pre.parse <- function(partitum) {
+    assign.parent('params', NULL, environment())
+    assign.parent('examples', NULL, environment())
+    parse.name(partitum)
+    parse.usage(partitum)
+  }
+
+  #' Parse params.
+  #' @param partitum the pre-parsed elements
+  #' @return \code{NULL}
+  post.parse <- function(partitum) {
+    parse.arguments()
+    parse.examples(partitum)
+    ## Assuming the previous sink was successful;
+    ## if not, it will destroy the sink stack.
+    ## (Should fail if unwritable, anyway.)
+    reset.filename()
+  }
+
+  roclet <- make.roclet(parse.expression,
+                        pre.parse,
+                        post.parse)
+
+  roclet$register.default.parsers('references',
+                                  'note',
+                                  'author',
+                                  'seealso',
+                                  'concept',
+                                  'docType')
+
+  roclet$register.parser('return',
[TRUNCATED]

To get the complete diff run:
    svnlook diff /svnroot/roxygen -r 237


More information about the Roxygen-commits mailing list