Rcpp: Roxygen support for modules?

Created on 21 Dec 2016  路  9Comments  路  Source: RcppCore/Rcpp

This was raised by James Curran in this StackOverflow question

Is there a cheap way to cover this from R/Attributes.R ?

Most helpful comment

For anybody still looking at this, here's a fully reproducible example showing four different ways to document Rcpp functions. Everything can be done directly inside the .cpp files. The only drawback is that function documentation doesn't always live next to functions, since (I think?) Rcpp only parses roxygen blocks at the top level.

Setup

devtools::create( "~/test/testpkg" )
devtools::document()                      # Sets up NAMESPACE, man/
usethis::use_rcpp()

Helper code inside ~/test/testpkg/R/zzz.R:

#' @useDynLib testpkg
NULL

Rcpp::loadModule("double_cpp", TRUE)

Write code inside ~/test/testpkg/src/mult.cpp:

#include <Rcpp.h>

// Approach 1: Standalone functions

//' Multiplies two doubles
//'
//' @param v1 First value
//' @param v2 Second value
//' @return Product of v1 and v2
//' @export
// [[Rcpp::export]]
double mult( double v1, double v2 ) {return v1*v2;}

// Approach 2: Nested items inside fields

//' @name Double
//' @title Encapsulates a double
//' @description Type the name of the class to see its methods
//' @field new Constructor
//' @field mult Multiply by another Double object \itemize{
//' \item Paramter: other - The other Double object
//' \item Returns: product of the values
//' }
//' @export
class Double {
public:
  Double( double v ) : value(v) {}
  double mult( const Double& other ) {return value * other.value;}
private:
  double value;
};

// Approach 3: Stand-alone pages for individual class methods

//' @name Double$new
//' @title Constructs a new Double object
//' @param v A value to encapsulate

// Approach 4: Module docstrings

RCPP_EXPOSED_CLASS(Double)
RCPP_MODULE(double_cpp) {
  using namespace Rcpp;

  class_<Double>("Double")
    .constructor<double>("Wraps a double")
    .method("mult", &Double::mult, "Multiply by another Double object")
    ;
}

Compile and install

devtools::load_all()      # Generates R/RcppExports.R with roxygen blocks
devtools::document()      # Generates man/*.Rd from R/RcppExports.R
devtools::install()

Test

In a fresh R session:

## Examine help pages
library( help=testpkg )     # Lists three functions: Double, Double$new and mult
?testpkg::mult              # Approach 1: stand-alone functions
?testpkg::Double            # Approach 2: nested field structure
?testpkg::`Double$new`      # Approach 3: individual class methods
testpkg::Double             # Approach 4: docstrings

## Ensure functionality
testpkg::mult(2, 3)    
# [1] 6

d1 = testpkg::Double$new(5)
d2 = testpkg::Double$new(3)
d1$mult(d2)
# [1] 15

All 9 comments

No unfortunately there isn't. The best approach here is to either write raw .Rd or write traditional roxygen in a .R file (with a NULL target).

I opened this as a reminder to us. I said at SO what you say here. We both know.

But shall we leave it open as a 'reminder' to add a helper function?

Keeping it open as a reminder makes sense.

I wrote the roxygen markup in a separate R file with a NULL target, adding a @name entry with the name of the cpp function to comment, but the @export statement does not make the function visible, and the documentation does not show up. Any clues?

That sounds like a roxygenize() question to me.

I only use roxygen to write Rd files and don't use it to update DESCRIPTION and NAMESPACE which I do by hand. And I think I may do that in one or two packages in the way you describe -- but as I only want the Rd file from it ... it's not an issue to me.

For anybody still looking at this, here's a fully reproducible example showing four different ways to document Rcpp functions. Everything can be done directly inside the .cpp files. The only drawback is that function documentation doesn't always live next to functions, since (I think?) Rcpp only parses roxygen blocks at the top level.

Setup

devtools::create( "~/test/testpkg" )
devtools::document()                      # Sets up NAMESPACE, man/
usethis::use_rcpp()

Helper code inside ~/test/testpkg/R/zzz.R:

#' @useDynLib testpkg
NULL

Rcpp::loadModule("double_cpp", TRUE)

Write code inside ~/test/testpkg/src/mult.cpp:

#include <Rcpp.h>

// Approach 1: Standalone functions

//' Multiplies two doubles
//'
//' @param v1 First value
//' @param v2 Second value
//' @return Product of v1 and v2
//' @export
// [[Rcpp::export]]
double mult( double v1, double v2 ) {return v1*v2;}

// Approach 2: Nested items inside fields

//' @name Double
//' @title Encapsulates a double
//' @description Type the name of the class to see its methods
//' @field new Constructor
//' @field mult Multiply by another Double object \itemize{
//' \item Paramter: other - The other Double object
//' \item Returns: product of the values
//' }
//' @export
class Double {
public:
  Double( double v ) : value(v) {}
  double mult( const Double& other ) {return value * other.value;}
private:
  double value;
};

// Approach 3: Stand-alone pages for individual class methods

//' @name Double$new
//' @title Constructs a new Double object
//' @param v A value to encapsulate

// Approach 4: Module docstrings

RCPP_EXPOSED_CLASS(Double)
RCPP_MODULE(double_cpp) {
  using namespace Rcpp;

  class_<Double>("Double")
    .constructor<double>("Wraps a double")
    .method("mult", &Double::mult, "Multiply by another Double object")
    ;
}

Compile and install

devtools::load_all()      # Generates R/RcppExports.R with roxygen blocks
devtools::document()      # Generates man/*.Rd from R/RcppExports.R
devtools::install()

Test

In a fresh R session:

## Examine help pages
library( help=testpkg )     # Lists three functions: Double, Double$new and mult
?testpkg::mult              # Approach 1: stand-alone functions
?testpkg::Double            # Approach 2: nested field structure
?testpkg::`Double$new`      # Approach 3: individual class methods
testpkg::Double             # Approach 4: docstrings

## Ensure functionality
testpkg::mult(2, 3)    
# [1] 6

d1 = testpkg::Double$new(5)
d2 = testpkg::Double$new(3)
d1$mult(d2)
# [1] 15

@ArtemSokolov Would you be interested in expanding this as a post for the Rcpp Gallery?

I would be happy to. Thanks for the suggestion, Dirk.
Will submit a pull request _before too long鈩.

Now posted at URL https://gallery.rcpp.org/articles/documenting-rcpp-packages/ -- so presumably ok to close this now?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zhiruiwang picture zhiruiwang  路  6Comments

steve-s picture steve-s  路  4Comments

kendonB picture kendonB  路  6Comments

PeteHaitch picture PeteHaitch  路  6Comments

iago-pssjd picture iago-pssjd  路  4Comments