CodeSOD: Do Nothing

Ivan encountered a strange bug. His organization uses the R language, which has a handy-dandy documentation language attached to it, for Rd files. The language itself is an organically grown hodge-podge of R and LaTeX, built to make it easy to format both plain text and R code within the documentation. It lets you use LaTeX-like commands, but also mix in R code to control the output.

Ivan's problem was that one of his macros, which we'll call \mymacro, only worked sometimes. The specific cases where it failed were where the macro expanded into multi-line output, which once upon a time wasn't a thing that Rd supported, but is supported, and clearly wasn't the problem. Ivan poked at it from that direction, suspecting there was maybe a regression, and then spent a lot of time trying to understand the places where the macro did and didn't work.

It took some time, but eventually the key difference was that the pages that worked also called another macro, \doi{}, which itself called \Sexpr[stage=build]{...}. Now, there's one important thing to note about the \Sexpr macro: it's meant to invoke R code inside of your documentation. And that made all the difference.

The documentation which didn't contain R code would be stored as a raw documentation file in the package. Before rendering the documentation, the parseRd tool would need to parse the file and generate the documentation output. This would happen after the package was built and distributed. Since the \mymacro might expand into nothing, this was technically unparseable at that point, and would cause the documentation render to fail.

On the other hand, documentation which did contain R code would be parsed and the parse tree would be stored in the package. There would be no parse step when the documentation got rendered. The whole "expanding to nothing" problem didn't exist in this situation.

So the fix was obvious, at least to Ivan:

--- man/macros/macros.Rd +++ man/macros/macros.Rd @@ -1,2 +1,3 @@ +\newcommand{\mustbuild}{\Sexpr[results=hide,stage=build]{}} -\newcommand{\mymacro}{\ifelse{html}{\out{...}}{...}} +\newcommand{\mymacro}{\mustbuild\ifelse{html}{\out{...}}{...}}

He added a \mustbuild macro which hides the results of a null operation, then added a call to that macro inside \mymacro. Now the documentation generates properly, even in older version of R which don't support some of the macro techniques being used (since the parse tree itself is cached, after macro expansion is complete).

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

This post originally appeared on The Daily WTF.

Leave a Reply

Your email address will not be published.