There are three things that you might document for S7:
- Generics: mention that the function is a generic and list the available methods.
- Methods: link back to the generic; only document individually when the method has unique behavior or arguments.
- Classes: document the constructor.
Generics
S7 generics are functions, so document them as such. Export a generic if you want users to call it or other developers to write methods for it. If the generic is internal, you don’t need to document it.
The documentation should mention that the function is a generic, because this tells the reader that the behavior may vary depending on the input and that they can write their own methods. For simple generics, you can do this in the description:
#' Size of an object
#'
#' @description
#' `size()` is an S7 generic that determines the size of an object,
#' with methods available for the following classes:
#'
#' `r doclisting::methods_list("size")`
#'
#' @param x An object.
#' @param ... Not used.
#' @returns A single number.
#' @export
size <- new_generic("size", "x")For more complicated generics, you can use a # Methods
section to provide more detail:
#' Size of an object
#'
#' @description
#' `size()` determines the size of an object.
#'
#' # Methods
#' `size()` is an S7 generic with methods available for the following
#' classes:
#'
#' `r doclisting::methods_list("size")`
#'
#' @param x An object.
#' @param ... Not used.
#' @returns A single number.
#' @export
size <- new_generic("size", "x")See the S3 Generics section for more about using the doclisting package to automatically generate method lists.
It’s good practice to document the default method alongside the
generic using @rdname:
#' @rdname size
method(size, class_any) <- function(x, ...) {
length(x)
}Classes
S7 classes are constructor functions, so document them much like you’d document any other function. Export a class if you want users to create instances or other developers to extend it (e.g. by creating subclasses). Internal classes don’t need documentation.
Use @param to document the constructor arguments (which
correspond to class properties), and @returns to describe
the object that is returned. If the class has additional properties that
are not part of the constructor (e.g. read-only computed properties),
use @prop to document them.
#' A range
#'
#' Create a range represented by a numeric `start` and `end`. The start must
#' always be less than the end.
#'
#' @param start Start of range.
#' @param end End of range.
#' @prop length Length of the range (read-only).
#' @returns An `Range` S7 object.
#' @export
Range <- new_class(
"Range",
properties = list(
start = class_numeric,
end = class_numeric,
length = new_property(getter = function(self) self@end - self@start),
validator = function(self) {
if (self@start > self@end) {
"start must be less than or equal to end"
}
}
)
)If multiple classes share one Rd page (via @rdname), you
can prefix the property name with the class name to group properties by
class, e.g. @prop ClassName@prop_name description.
Methods
It is your choice whether or not to document S7
methods. S7 methods are registered with
method(generic, class) <- fn. Generally, it’s not
necessary to document straightforward methods.
It’s good practice, however, to document methods that have unique
behavior or arguments. If you do document a method, give it its own
roxygen block. When documenting a method, always include a link back to
the generic using [generic_name()] so the reader can easily
find the full documentation and other methods.
#' Size of a range
#'
#' The size of a range is its [size()], i.e. its length.
#'
#' @param x A `Range` object.
#' @param ... Not used.
#' @returns A single number.
method(size, Range) <- function(x, ...) {
x@length
}S7 methods are registered at load time via
S7::methods_register() in your .onLoad()
function, not through NAMESPACE directives, so you never
need to @export them. See
vignette("packages", package = "S7") for details.
