Pre- or post-process roxygen snippets - r

Is there some mechanism by which I can transform the comments that roxygen sees, preferably before it does the roxygen->rd conversion?
For example, suppose I have:
#' My function. Does stuff with numbers.
#'
#' This takes an input `x` and does something with it.
#' #param x a number.
myFunction <- function (x) {
}
Now, suppose I want to do some conversion of the comment before roxygen parses it, for example replacing all instances of things in backticks with \code{}. Ie:
preprocess <- function (txt) {
gsub('`([^ ]+)`', '\\\\code{\\1}', txt)
}
# cat(preprocess('Takes an input `x` and does something with it'.))
# Takes an input \code{x} and does something with it.
Can I feed preprocess into roxygen somehow so that it will run it on the doclets before (or after would work in this case) roxygen does its document generation?
I don't want to do a permanent find-replace in my .r files. As you might guess from my example, I'm aiming towards some rudimentary markdown support in my roxygen comments, and hence wish to keep my .r files as-is to preserve readability (and insert the \code{..} stuff programmatically).
Should I just write my own version of roxygenise that runs preprocess on all detected roxygen-style comments in my files, saves them temporarily somewhere, and then runs the actual roxygenise on those?

Revisiting this a couple of years later, it looks like Roxygen has a function register.preref.parsers that one can use to inject their own parsers into roxygen.
One such use of this is the promising maxygen package (markdown + roxygen = maxygen), which a very neat implementation of markdown processing of roxygen comments (albeit only to the CommonMark spec), and you can see how it is used in that package's macument function. I eagerly await "pandoc + roxygen = pandoxygen"... :)

Related

How to get roxygen2 to interpret backticks as code formatting?

The standard way of writing documentation with code formatting is by using \code{}.
That is, #' #param foo value passed on to \code{bar()} becomes
Arguments
foo    value passed on to bar()
However, I've seen some packages (i.e. dplyr) using backticks instead of \code{} to the same effect. This is much better, since it's less clunky and allows for very nice syntax highlighting.
However, if I try that on my own package, the backticks get interpreted as... just backticks, like any other character.
The documentation for dplyr::across(), for example, starts with:
#' #description
#' `across()` makes it easy to apply the same transformation to multiple [...]
which gets compiled and displayed in the man page as:
Description
across() makes it easy to apply the same transformation to multiple [...]
But if I try something similar on my package, I get:
Description
`across()` makes it easy to apply the same transformation to multiple [...]
Weirdly, I've forked the package glue (which also manages to use backticks for code formatting) for a simple PR, and if I build the package locally, the backticks work (I get code formatting). Can't for the life of me figure out why it works there but not for my package.
So, is there some setting I need to modify to get this to work? I checked the dplyr.Rproj but found nothing relevant. I also glanced at the Doxyfile, but didn't know what it did or what I'd even be looking for there.
All credit goes to #rawr's comment to the question, just formalizing it with an answer:
The secret is in the roxygen2 documentation: just add the following to the end of the package DESCRIPTION file:
# DESCRIPTION file
# [... rest of file ...]
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.2 # actually works since 6.0.0
As that code would imply, this sets roxygen2 to interpret the commands as good ol' Markdown like we're used to using here on SO and elsewhere. This also implies all the other standard Markdown commands such as **bold** and *italics*, as well as [text](http://www.url.com), code blocks defined by ```, itemized and enumerated lists, etc. It's a huge improvement across the board.
Though be careful and take a look at the documentation, since there are a few gotchas. For instance, an empty line isn't necessary to start lists, so don't start any lines with #' 1. [...] or #' * [...] or you'll accidentally create a list!). There's also a few things which don't work yet, but they're pretty minor.

How to export S3method both as method and normal function using roxygen2

There are similar, older questions out there, but since roxygen2 version 3.0.0 things have changed a bit (as I understand from other Q&A here on SO).
I have written an alternative function format.Date, which I want to export, both as method and as function.
Using the #export tag means roxygen2 recognises it as an S3-method for print, and registers it accordingly. And when I load my package, and print a date object, my method gets called. So far, so good.
But, when I then call format.Date, I still get the normal base-method. This also happens when I use debugonce(format.Date), the 'debug-mark' gets set on base::format.Date, so if my method gets called, nothing happens. Or if I want to inspect the source-code: very hard for a user to understand that what he sees with View(format.Date) is NOT what is executed.
And if a user looks into my package what functions I have provided, format.Date is not there.
So I want format.Date to be exported as both an S3-method, and as a normal function called format.Date. In order to do so, I expect my NAMESPACE file to contain both following lines:
S3method(format,Date)
export(format.Date)
Is this possible in roxygen2? I get the impression you could do this in earlier versions (as you could supply both #S3method/#method and #export), but I can't get it to work now.
Background-info: roxygen2 version 6.1.1 with R 3.5.1, run under Rstudio 1.1.453/MacOS 10.13.6
The ways I found are
#exportS3Method and an explicit #export line. Since roxygen2 changes often, this might change in the future:
#' #exportS3Method fortify
#' #export fortify.Date
Manually spelling out the NAMESPACE content (add no other #export or #method directives)
#' #rawNamespace S3method(fortify,Date)
#' export(fortify.Date)
Both will result in the NAMESPACE file containing the following lines, with the first one resulting in roxygen2 ordering things for you.
S3method(fortify,Date)
export(fortify.Date)

Using an R Markdown Document as a source for functions

I'm looking into R Markdown for documenting functions I regularly use. I will put them into an R Markdown file to document them and then be able to read my thinking behind the function if i come back to it months later
My question is, if i start a new R project, Is it possible to source the r markdown file and use the library of functions i have created just by calling them similarly to if i was sourcing a regular R file. I dont really wish to maintain two sets of function files
I appreciate this may be a beginners question but any help pointing to tutorials and the like would be greatly appreciated
Thanks
As was mentioned in the comments, you should probably create a package for this purpose. But if you insist on putting function definitions in scripts and document them using RMarkdown files, using read_chunk() from the knitr package might be the way to go.
Note that this approach differs slightly from what you requested. You wanted to have the function definition in the markdown file together with the documentation. And then you wanted to somehow source that file into your R script in order to use the function. I did not find a way to do this (even though it might be possible).
The alternative that I propose puts the function definition in its own R script, say fun.R. The Rmarkdown file then reads the function definition from fun.R and adds documentation. If you want to use the function in some other script, you can simply source fun.R (and not the markdown file). This still means that you have to maintain the code for the function definition only once.
So let me show this with an example. This is fun.R:
## ---- fun
fun <- function(x) x^2
The first line is an identifier that will be used later. The markdown file is as follows:
---
title: "Documentation of fun()"
output: html_document
---
This documents the function `fun()` defined in `fun.R`.
```{r,cache = FALSE}
knitr::read_chunk("fun.R")
```
This is the function definition
```{r fun}
```
This is an example of how to use `fun()`:
```{r use_fun}
fun(3)
```
The first chunk reads in fun.R using knitr::read_chunk. Later on, you can define an empty chunk that has the identifier that was used in fun.R as its name. This will act as if the contents of fun.R were written directly in this file. As you see, you can also use fun() in later chunks. This is a screenshot of the resulting html file:
In a script where you want to use fun() you simply add source("fun.R") to source the function definition.
You could also have several functions in a single R file and still document them separately. Simply put an identifier starting with ## ---- before each function definition and then create empty chunks referring to each one of the identifiers.
This is admittedly somewhat more complicated than what you asked for, because it involves two files instead of just one. But at least there is no redundancy
The klmr/modules package has been superseded by the box package by the same author. It is on CRAN. After the cat command below run these lines to display the roxygen2 help for add2.
box::use(./test)
box::help(test$add2)
Perhaps this is close enough -- you can use the github klmr/modules package (not the CRAN modules package) to combine roxygen2 documentation and code in a single file without creating a package. For example, after installing the modules package copy this to the clipboard and then paste it into the R console to create a single file module with embedded documentation. The subsequent code then imports it, runs a function from it and invokes help. See the documentation of the modules package for more info.
Note that this has the following advantages: (1) everything is in a single file, (2) if you later decide to move to using packages you can use the very same file in your package with roxygen2 -- no need to revise anything, (3) any learning of roxygen2 applies to packages too.
# create a file with our documentation and code
Lines <- "
#' Add two numbers.
#'
#' #param x the first number.
#' #param y the second number.
#' #return The sum.
#' #note This is just a simple example.
#'
#' This function is a simple example intended to show how to use the modules
#' package with roxygen2.
add2 <- function(x, y) x + y
"
cat(Lines, file = "test.R")
# now we can import it
# devtools::install_github("klmr/modules")
library(modules)
test <- import("test") # do not include the .R extension
test$add2(1, 2)
## [1] 3
# this will cause help page to appear
?test$add2

How to toggle roxygen comments in Rstudio?

Roxygen comments involve prefixing lines with #'.
When writing and testing examples for functions, it's nice to be able to toggle the comments on and off. I could copy and paste the code back and forward to vim and remove or add those comments, but that's not very elegant.
Is there any easy way to toggle roxygen comments in Rstudio?
Alternatively, is there another way to efficiently run example R code that is commented out by roxygen comment characters?
Update: Thinking laterally, I suppose using #example examples/foo.r is an alternative way of avoiding having to use Roxygen comments for the actual example code (i.e., by sourcing the example from a file, i.e., examples/foo.r).
With respect to your proposed alternative:
Alternatively, is there another way to efficiently run example R code that is commented out by roxygen comment characters?
If you press CTRL+[Enter] within a Roxygen2 #examples block, Rstudio will send the selected code (line or highlighted section) to the R console. To use just declare the #examples code block on a line preceding your roxygen commented code.
#' #examples
#' ... your original roxygen commented code ...
You can put an #examples block anywhere in your code. This becomes a drag if you are developing a package and you are using the block for its intended purpose.
If you are looking for a way to toggle code, I would use the approach proposed by #Roman in in the comments to your question.
You can write your own function that extract example code from your R file. This is analogous to purl in knit package or Stangle. Here an example of what you can do. The function is not efficient but I write it just to show the idea. It should be a good start point. It assumes also that you already source your R file or at least that the documented function already exist in the R session.
purl.examples <- function(fileName){
ll <- readLines(fileName)
ex.lines <- grep('#examples',ll) ## get the example's lines
## for each example loop till
## there is no comment (inefficient)
examples <- lapply(ex.lines , function(x){
i <- x+1
code <- list()
while(grepl("#'",ll[i])){
l <- c(code,gsub("#'","",ll[i],fixed=TRUE))
i <- i+1
}
code
})
}
Then you can call it like this for example:
lapply(purl.examples('code.R'),
function(ex) eval(parse(text=ex))) ## safer to use evaluate package here

Rd file name conflict when extending a S4 method of some other package

Actual question
How do I avoid Rd file name conflicts when
a S4 generic and its method(s) are not necessarily all defined in the same package (package containing (some of) the custom method(s) depends on the package containing the generic) and
using roxygenize() from package roxygen2 to generate the actual Rd files?
I'm not sure if this is a roxygen2 problem or a common problem when the generic and its method(s) are scattered across packages (which IMHO in general definitely is a realistic use-case scenario if you follow a modular programming style).
What's the recommended way to handle these situations?
Illustration
In package pkga
Suppose in package pkga you defined a generic method foo and that you've provided the respective roxygen code that roxygenize() picks up to generate the Rd file:
#' Test function
#'
#' Test function.
#'
#' #param ... Further arguments.
#' #author Janko Thyson \email{janko.thyson##rappster.de}
#' #example inst/examples/foo.R
#' #docType methods
#' #rdname foo-methods
#' #export
setGeneric(
name="foo",
signature=c("x"),
def=function(
x,
...
) {
standardGeneric("xFoo")
}
)
When roxygenizing() your package, a file called foo-methods.Rd is created in the man subdirectory that serves as the reference Rd file for all methods that might be created for this generic method. So far so good. If all of the methods for this generic are also part of your package, everything's good. For example, this roxygen code would make sure that documentation is added to foo-methods.Rd for the ANY-method of foo:
#' #param x \code{ANY}.
#' #return \code{TRUE}.
#' #rdname foo-methods
#' #aliases foo,ANY-method
#' #export
setMethod(
f="foo",
signature=signature(x="ANY"),
definition=cmpfun(function(
x,
...
) {
return(TRUE)
}, options=list(suppressAll=TRUE))
)
However, if package pkga provides the generic for foo and you decide in some other package (say pkgb) to add a foo-method for x being of class character, then R CMD check will tell you that there is a name clash with respect to Rd file names and/or aliases (as there already exists a Rd file foo-methods.Rd in pkga):
In package pkgb
#' #param x \code{character}.
#' #return \code{character}.
#' #rdname foo-methods
#' #aliases foo,character-method
#' #export
setMethod(
f="foo",
signature=signature(x="character"),
definition=cmpfun(function(
x,
...
) {
return(x)
}, options=list(suppressAll=TRUE))
)
To be more precise, this is the error that's thrown/written to file 00install.out
Error : Q:/pkgb/man/foo-methods.Rd: Sections \title, and \name must exist and be unique in Rd files
ERROR: installing Rd objects failed for package 'pkgb'
Due dilligence
I tried to change the values for #rdname and #aliases to foo_pkgb* (instead of foo*), but \title and \name still are set to foo when roxygenizing and thus the error remains. Any ideas besides manually editing the Rd files generated by roxygenize()?
EDIT 2012-12-01
In light of starting the bounty, the actual question might get a slightly broader flavor:
How can we implement some sort of an "inter-package" check with respect to Rd files and/or how can we consolidate S4 method help files scattered across packages into one single Rd file in order to present a single source of reference to the end-user?
The basic question is indeed "roxygenize"-only.
That's why I never had seen the problem.
While there are good reasons for the roxygenizing approach of package development,
I still see a very good reason not to go there:
Plea for much less extreme roxygenation
The resulting help pages tend to look extremely boring, not only the auto generated *.Rd files but also the rendered result.
E.g.
examples are often minimal, do not contain comments, are often not well formatted (using space, / new lines /..)
Mathematical issues are rarely explained via \eqn{} or \deqn{}
\describe{ .. } and similar higher level formatting is rarely used
Why is that? Because
1) reading and editing roxygen comments is so much more
"cumbersome" or at least visually unrewarding
than reading and editing *.Rd files in ESS or Rstudio or (other IDE that has *.Rd support built in)
2) If you are used that documentation
is the thing that's automatically generated at the end of your package building/checking
you typically tend to not considerung well written R documentation as something important
(but rather your R code, to which all the docs is just a comment :-)
The result of all that: People prefer writing documentation about their functions in vignettes or even blogs, github gists, youtube videos, or ... where it is very nice at the time of authoring, but is
pretty much detached from the code and bound to get outdated and withering (and hence, via Google search misleading your useRs)
--> The original motivation of roxygen of having code and documentation in the same place is entirely defeated.
I like roxygen and use it extensively at the time I create a new function...
and I keep and maintain it as long as my function is not in a package, or is not exported.
Once I decide to export it,
I run (the ESS equivalent of) roxygenize() once
and from then on take the small extra burden of maintaining a *.Rd file that is well formatted, contains its own comments (for me as author), has many nice examples, has its own revision control (git / svn / ...) history, etc.
I managed to generate NAMESPACE and *.Rd files for S4 methods for generics defined in another package than mine.
It took me the following steps:
Create NAMESPACE by hand as a workaround to a known roxygen2 bug.
Writing a NAMESPACE by hand is not so difficult at all!
Switch off NAMESPACE generation by roxygen2 in RStudio:
Build > more > Configure build tools > configure roxygen > do not use roxygen2 to generate NAMESPACE.
import the package containing the generic and export the S4 methods using exportMethods.
Write separate roxygen2 documentation for each of the S4 methods. Do not combine roxygen2 documentation (as I generally do for different methods of the same generic).
Add explicit roxygen tags #title and #description to the roxygen documentation of the S4 methods. Write #description explicitly, even if its value is identical as #title.
That makes it work for me.

Resources