[Roxygen-commits] r253 - in pkg: . R src

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Sun Mar 13 02:21:33 CET 2011


Author: pcd
Date: 2011-03-13 02:21:33 +0100 (Sun, 13 Mar 2011)
New Revision: 253

Modified:
   pkg/R/Rd.R
   pkg/R/Rd2.R
   pkg/TODO
   pkg/src/roxygen
Log:
propagate filename-translation to Rd2; unix line-endings

Modified: pkg/R/Rd.R
===================================================================
--- pkg/R/Rd.R	2011-03-11 03:27:44 UTC (rev 252)
+++ pkg/R/Rd.R	2011-03-13 01:21:33 UTC (rev 253)
@@ -1,543 +1,543 @@
-#' @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)))
-
-##' Substitutions of questionable characters with a hacker-joke to
-##' boot.
-substitutions=c(
-  `!`='bang',
-  `"`='quote',
-  `#`='hash',
-  `$`='money',
-  `%`='grapes',
-  `&`='and',
-  `'`='single-quote',
-  `(`='open-paren',
-  `)`='close-paren',
-  `*`='star',
-  `+`='plus',
-  `,`='comma',
-  `-`='dash',
-  `.`='dot',
-  `/`='slash',
-  `:`='colon',
-  `;`='semi-colon',
-  `<`='less-than',
-  `=`='equals',
-  `>`='greater-than',
-  `?`='p',
-  `@`='asperand',
-  `[`='open-brace',
-  `\\`='backslash',
-  `]`='close-brace',
-  `^`='hat',
-  `_`='sub',
-  '`'='backtick',                       # let's add another ` to
-                                        # rectify syntax highlighting
-                                        # in emacs; thanks.
-  `{`='open-curly',
-  `|`='pipe',
-  `}`='close',
-  `~`='not'
-  )
-
-##' \code{NULL} if empty-string.
-##' @param string string to check
-##' @return \code{NULL} or identity
-nil.if.lambda <- function(string)
-  if (nchar(string)) string else NULL
-
-##' Translate file-system-questionable characters (i.e. punctuation
-##' within ASCII).
-##' @param filename the filename to translate
-##' @return the translated filename
-translate.questionable.characters <- function(filename)
-  do.call(Curry(paste, collapse="-"),
-          strapply(filename,
-                   pattern='([[:punct:]]|)([^[:punct:]]*|)',
-                   function(punctuation, letters)
-                   c(substitutions[nil.if.lambda(punctuation)],
-                     nil.if.lambda(letters))))
-
-#' 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',
-                                        translate.questionable.characters(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)
-      name.defaults <-
-        zip.c(names(formals),
-              Map(function(formal) tryCatch(toString(formal),
-                                            error=function(e) '<closure>'),
-                  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)))
+
+##' Substitutions of questionable characters with a hacker-joke to
+##' boot.
+substitutions=c(
+  `!`='bang',
+  `"`='quote',
+  `#`='hash',
+  `$`='cash',                           # sigil
+  `%`='grapes',
+  `&`='and',
+  `'`='single-quote',
+  `(`='open-paren',
+  `)`='close-paren',
+  `*`='star',
+  `+`='plus',
+  `,`='comma',
+  `-`='dash',
+  `.`='dot',
+  `/`='slash',
+  `:`='colon',
+  `;`='semi-colon',
+  `<`='less-than',
+  `=`='equals',
+  `>`='greater-than',
+  `?`='p',
+  `@`='asperand',
+  `[`='open-brace',
+  `\\`='backslash',
+  `]`='close-brace',
+  `^`='hat',
+  `_`='sub',
+  '`'='backtick',                       # let's add another ` to
+                                        # rectify syntax highlighting
+                                        # in emacs; thanks.
+  `{`='open-curly',
+  `|`='pipe',
+  `}`='close',
+  `~`='not'
+  )
+
+##' \code{NULL} if empty-string.
+##' @param string string to check
+##' @return \code{NULL} or identity
+nil.if.lambda <- function(string)
+  if (nchar(string)) string else NULL
+
+##' Translate file-system-questionable characters (i.e. punctuation
+##' within ASCII).
+##' @param filename the filename to translate
+##' @return the translated filename
+translate.questionable.characters <- function(filename)
+  do.call(Curry(paste, collapse="-"),
+          strapply(filename,
+                   pattern='([[:punct:]]|)([^[:punct:]]*|)',
+                   function(punctuation, letters)
+                   c(substitutions[nil.if.lambda(punctuation)],
+                     nil.if.lambda(letters))))
+
+#' 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',
+                                        translate.questionable.characters(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
[TRUNCATED]

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


More information about the Roxygen-commits mailing list