Skip to content

Commit 3837a11

Browse files
committed
Improve method docs
Fixes #1451
1 parent 3b4695e commit 3837a11

File tree

1 file changed

+85
-25
lines changed

1 file changed

+85
-25
lines changed

vignettes/namespace.Rmd

Lines changed: 85 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,49 +19,109 @@ This is a little frustrating at first, but soon becomes second-nature.
1919

2020
## Exports
2121

22-
For a function to be usable outside your package, you must **export** it.
23-
By default roxygen2 doesn't export anything from your package.
24-
If you want an object to be publicly available, you must explicitly tag it with `@export`.
22+
In order for your users to use a function[^1] in your package, you must **export** it.
23+
In most cases, you can just use the `@export` tag, and roxygen2 will automatically figure out which `NAMESPACE` directive (e.g. `export()`, `exportS3method()`, `exportClasses()`, and `exportMethods()`) you need.
2524

26-
Use the following guidelines to decide what to export:
25+
[^1]: Including S3 and S4 generics and methods.
2726

28-
- **Functions**: export functions that you want to make available.
29-
Exported functions must be documented, and you must be cautious when changing their interface.
27+
### Functions
28+
29+
Functions should be exported if you want your users to available.
30+
If you export a function, you must also document it, and since other people will use it, you need to be careful if you later change the function interface.
3031

31-
- **Datasets**: all datasets are publicly available.
32-
They exist outside of the package namespace and must not be exported.
32+
```{r}
33+
#' Add two numbers together
34+
#'
35+
#' @param x,y Two numbers
36+
#' @export
37+
add <- function(x, y) {
38+
x + y
39+
}
40+
```
3341

34-
- **S3 classes**: if you want others to be able to create instances of the class `@export` the constructor function.
42+
### S3
43+
44+
S3 generics work like regular R functions so export them using the advice above: if you want users to call this function, export; if it's purely for internal use, don't export it.
45+
46+
```{r}
47+
#' Take an object to bizarro world
48+
#'
49+
#' @param x A vector.
50+
#' @export
51+
bizarro <- function(x, ...) {
52+
UseMethod("bizarro")
53+
}
54+
```
3555

36-
- **S3 generics**: the generic is a function, so `@export` if you want it to be usable outside the package.
56+
While S3 methods are regular functions with a special naming scheme, their "export" works a bit differently.
57+
S3 methods are exported only in the sense that when you call the generic with the appropriate method; a user can't directly access the function definition by typing the name of the generic.
58+
A more technically correctly term would be to say that the method is **registered** so that the generics can find it.
59+
You must register, i.e. `@export`, every S3 method regardless of whether or not the generic is exported, and roxygen2 will warn you if you have forgotten.
3760

38-
- **S3 methods**: every S3 method *must* be exported, even if the generic is not.
39-
Otherwise, the S3 method table will not be generated correctly and internal generics will not find the correct method.
40-
See below for instructions on how to export a method for a generic in a suggested package.
61+
```{r}
62+
#' @export
63+
bizarro.character <- function(x, ...) {
64+
letters <- strsplit(x, "")
65+
letters_rev <- lapply(letters, rev)
66+
vapply(letters_rev, paste, collapse = "", FUN.VALUE = character(1))
67+
}
68+
```
4169

42-
- **S4 classes**: export S4 classes if you want others to be able to extend them.
70+
You can document S3 methods, but you're not required to.
71+
If you document a method, you have three choices.
72+
If the method is particularly complex or has many arguments that the generic does not, you can document it in its own file.
73+
Otherwise you can use `@rdname` to document it with either the generic or the class.
4374

44-
- **S4 generics:** `@export` if you want the generic to be publicly usable.
75+
```{r}
76+
#' Take an object to bizarro world
77+
#'
78+
#' @description
79+
#' This is an S3 generic. This package provides methods for the
80+
#' following classes:
81+
#'
82+
#' * `character`: reverses the order of the letters in each element of
83+
#' the vector.
84+
#'
85+
#' @param x A vector.
86+
#' @export
87+
bizarro <- function(x, ...) {
88+
UseMethod("bizarro")
89+
}
4590
46-
- **S4 methods**: you only need to `@export` methods for generics in other packages.
91+
#' @export
92+
#' @rdname bizarro
93+
bizarro.character <- function(x, ...) {
94+
letters <- strsplit(x, "")
95+
letters_rev <- lapply(letters, rev)
96+
vapply(letters_rev, paste, collapse = "", FUN.VALUE = character(1))
97+
}
98+
```
4799

48-
### S3 methods for generics in suggested packages
100+
Typically, you will write methods for generics that are either defined in the current package or a package that is a hard dependency[^2] of your package.
101+
Sometimes, however, you will want to write a method for a suggested dependency.
102+
In this case, `@export` will not work because it relies on being able to see the generic.
103+
Instead, use `@exportS3Method`. This will use "delayed" method registration, which means the method will only be registered when the suggested package is loaded.
49104

50-
`@exportS3Method` tag allows you to generate `S3method()` namespace directives.
51-
Its primary use is for "delayed" method registration, which allows you to define methods for generics found in suggested packages (R \>= 3.6).
52-
For example,
105+
[^2]: i.e. listed the `Imports` or `Depends` fields in your `DESCRIPTION`.
53106

54107
```{r}
55108
#' @exportS3Method pkg::generic
56109
generic.foo <- function(x, ...) {
57110
}
58111
```
59112

60-
will generate
113+
### S4
114+
115+
- **Classes**: export the class object if you want others to be able to extend it.
116+
117+
- **Generics:** treat it like a function and `@export` if user facing.
118+
119+
- **Methods**: you only need to `@export` a method, if the generic lives in another package.
61120

62-
S3method(pkg::generic, foo)
121+
### Datasets
63122

64-
Which will cause the method to be registered only when pkg is loaded.
123+
Note that datasets should never be exported as they use a different mechanism.
124+
Instead, datasets will either be automatically exported if you set `LazyData: true` in your `DESCRIPTION`, or made available after calling `data()` if not.
65125

66126
### Manual exports
67127

@@ -85,15 +145,15 @@ The `NAMESPACE` also controls which functions from other packages are made avail
85145

86146
If you are using just a few functions from another package, we recommending adding the package to the `Imports:` field of the `DESCRIPTION` file and calling the functions explicitly using `::`, e.g., `pkg::fun()`.
87147

88-
```r
148+
``` r
89149
my_function <- function(x, y) {
90150
pkg::fun(x) * y
91151
}
92152
```
93153

94154
If the repetition of the package name becomes annoying you can `@importFrom` and drop the `::`:
95155

96-
```r
156+
``` r
97157
#' @importFrom pkg fun
98158
my_function <- function(x, y) {
99159
fun(x) * y

0 commit comments

Comments
 (0)