Search code examples
rliterate-programmingroxygen

How to escape % in roxygen literate programming?


The default value of a parameter of my function contains a "%". This seems to be a problem for roxygen, it produces a lot of warnings and R CMD check fails when trying to build latex documentation.

How can I make this function (and its documentation) work? Using %% or \% instead of % does not help.

#' Test escape \% from in-source documentation (roxygen).
#'
#' What happens when parameters contain special latex characters? 
#'
#' @param x unsuspicious parameter 
#' @param format sprintf format string (default "\%5.0f")
#'
#' @return formatted string
#' @export
#' @author Karsten Weinert
testroxy <- function(x, format = "%5.0f") {
  sprintf(format,x)
}

Solution

  • #!/usr/bin/perl
    use strict;
    use File::Temp qw/tempfile/;
    use File::Copy;
    
    my $usage = <<EOD
    
      $0 file1.Rd [file2.Rd ...]
    
      When using roxygen to generate documentation for an R pacakge, if a default
      argument has a percent sign in it then roxygen will copy it directly into
      the .Rd file. Since .Rd is basically latex, this will be interpreted as a
      comment and case the file to be parsed incorrectly.
    
      For percent signs elsewhere in your documentation, for example in the
      description of one of the parameters, you should use "\%" so parse_Rd
      interprets it correctly.
    
      But you cannot do this in the default arguments because they have to be
      valid R code, too.
    
      Since the .Rd files are automatically generated they should not have
      any latex comments in them anyway.
    
      This script escapes every unescaped % within the file.
    
      The .Rd files are modified in place, since it would be easy to
      generate them again with R CMD roxygen.
    
    EOD
    ;
    
    my $n_tot = 0;
    my $n_file = @ARGV;
    my $n_esc_file = 0;
    foreach my $fn (@ARGV)  {
    
      print STDERR ' ' x 100, "\rWorking on $fn\t";
      open my $fh, $fn or die "Couldn't open $fn: $!";
      my ($tmp_fh, $tmp_fn) = tempfile();
    
      my $n;
      while(<$fh>)  {
        $n += s/(?<!\\)%/\\%/g;  # if % is not preceded with backslash then replace it with '\%'
        print $tmp_fh $_;
      }
      $n_tot += $n;
      $n_esc_file ++ if $n;
      print "Escaped $n '%'\n" if $n;
      close $tmp_fh;
      move($tmp_fn => $fn);
    }
    
    print "\n";
    
    print "$n_file files parsed\n";
    print "$n_esc_file contained at least one unescaped %\n";
    print "$n_tot total % were escaped\n";
    

    This is my inelegant solution. Save the perl script as, for example, escape_percents.pl, then the sequence would be like this:

    R CMD roxygen my.package
    perl escape_percents.pl my.package.roxygen/man/*.Rd
    R CMD install my.package.roxygen
    

    This may introduce more problems, for example if you have example code using %% as the modulus operator, but it has been handy for me.