generated from r4ds/bookclub-template
-
Notifications
You must be signed in to change notification settings - Fork 18
/
16-function-documentation.Rmd
475 lines (335 loc) · 13.8 KB
/
16-function-documentation.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# (PART) Documentation {-}
# Function documentation
**Learning objectives:**
- Describe the benefits of well developed function documentation
- roxygen2 basics
- Discuss the definition of object documentation
- Demonstrate the object documentation workflow
- Discuss some general formatting and style guidelines
### Why care about object documentation?
- Documentation is an important component of packages
- How will users know how to use your package?
- Inform your future self
- Inform other contributors
### roxygen2 advantages
- code and documentation co-located
- use markdown rather than learning the markup language of `.Rd`
- automation of `.Rd` boilerplate
- tools for sharing content across documentation topics and vignettes
## roxygen2 basics
### Documentation workflow
Four main steps:
1. Opening move is add roxygen comments above your functions in your `R/.R` files
2. Run `devtools::document()`
3. Preview documentation with `?function`
4. Rinse and repeat
![](images/16-function-documentation/function-documentation-stages.png)
### roxygen2 comments, blocks, and tags
- Four basic building blocks:
1. **`#'`** - `roxygen` comment
1. **Multiple `#` lines** - a block
- Wrapped at 80 characters (Ctrl/Cmd + Shift + / or reflow comment)
1. **Tags** - Breaks up the blocks
- `@tagName details`
1. **Introduction**
- First sentence is the title
- Second paragraph is the description (what does the function do?)
- Paragraphs >= 3 allow for more detail
- All objects must have a title and description
- Details are optional
- Blocks and tags give documentation structure
Here's a simple first example: the documentation for `str_unique()`.
```{r}
#' Remove duplicated strings
#'
#' `str_unique()` removes duplicated values, with optional control over
#' how duplication is measured.
#'
#' @param string Input vector. Either a character vector, or something
#' coercible to one.
#' @param ... Other options used to control matching behavior between duplicate
#' strings. Passed on to [stringi::stri_opts_collator()].
#' @returns A character vector, usually shorter than `string`.
#' @seealso [unique()], [stringi::stri_unique()] which this function wraps.
#' @examples
#' str_unique(c("a", "b", "c", "b", "a"))
#'
#' # Use ... to pass additional arguments to stri_unique()
#' str_unique(c("motley", "mötley", "pinguino", "pingüino"))
#' str_unique(c("motley", "mötley", "pinguino", "pingüino"), strength = 1)
#' @export
str_unique <- function(string, ...) {
...
}
```
### Key markdown features
1. Backticks for inline code
```{r}
#' I like `thisfunction()`, because it's great.
```
2. Square brackets for auto-linked function
```{r}
#' It's obvious that `thisfunction()` is better than [otherpkg::otherfunction()]
#' or even our own [olderfunction()].
```
3. Vignettes
- `vignette("rd-formatting", package = "roxygen2")`
- `vignette("reuse", package = "roxygen2")`
- `vignette("linking", package = "pkgdown")`
4. Lists
```{r}
#' Best features of `thisfunction()`:
#' * Smells nice
#' * Has good vibes
```
## Title, description, details
### Title recommendations
1. Sentence case
1. not end in a full stop
1. followed by a blank line
1. succinct description of function
Bad titles:
- `str_detect()`: Detect the presence or absence of a pattern in a string
- `str_extract()`: Extract matching patterns from a string
- `str_locate()`: Locate the position of patterns in a string
- `str_match()`: Extract matched groups from a string
Good titles:
- `mutate()`: Create, modify, and delete columns
- `summarise()`: Summarize each group to fewer rows
- `filter()`: Subset rows using column values
- `select()`: Subset columns using their names and types
- `arrange()`: Arrange rows by column values
### Description recommendation
1. summarize goal of the function in single paragraph
1. Explicitly tag `@description` if multi-paragraph (or just need an empty line)
1. Write description after you've come back and forgot what your function does
### Details recommendation
1. most functions don't need this
1. use informative markdown headings
## Arguments
- This is where most of the work will be
- Use `@param` tag
- succinct summary of the inputs and what parameter does
- best practice to describe default argument values even if more work when they later change
- list fixed set of possible parameter values
- bulleted lists possible
### Multiple Arguments
document tightly coupled arguments by separating names with commas
```{r}
#' @param x,y A pair of character vectors.
```
### Inheriting Arguments
`@inheritParams`: reuse parameter documentation
- From source `@inheritParams function`
- From another package `@inheritParams package::function`
```{r inherit_params_example, eval=FALSE}
#' @param a This is the first argument.
foo <- function(a) a + 10
#' @param b This is the second argument.
#' @inheritParams foo
bar <- function(a, b) {
foo(a) * 10
}
# Equivalent to
#' @param a This is the first argument.
#' @param b This is the second argument.
bar <- function(a, b) {
foo(a) * 10
}
```
## Return Value
`@returns`
- Describes the output from the function.
## Examples
`@examples`
- Provides executable code on how to use the function in practice
- Must run without errors or use `\dontrun{}`
- **Keep in mind:** Most users will look at examples first
Tension between readable and realistic example code vs. no errors and side effects
Examples executed in 4 situations:
1. interactively with `example()`
1. `R CMD check` on your computer(s)
1. `R CMD check` by CRAN
1. pkgdown website building
### Contents
- Show basic functionality
- highlight easy to miss features
- avoid edge cases
- sectioning is awkward
- try to use built-in datasets
### Leave the world as you found it
There is no way to schedule clean up in examples like there are in functions and testing.
### Errors
If you need to demonstrate an error you can
- wrap code in `try()`
- wrap code in `\dontrun{}`
Recommend using `try()`
### Dependencies and conditional execution
Ok to do `library()` in the examples as
- expect suggested packages available during `R CMD check`
- cost of putting code inside `{...}` is high
Recommendation for conditional cases is to use `@examplesIf` tag
- hides machinery from users
- example code renders in pkgdown
- doesn't break CRAN's prohibition of putting code in `\dontrun{}`
### Intermixing examples and text
Alternative is using RMarkdown but downsides:
- code in ```` ```R ```` blocks is never run
- codes in ```` ```{r} ```` is run every time you document
## Re-using documentation
### Multiple functions
`@rdname`: document multiple functions in one place that have a lot in common
- Use with caution. Can lead to confusing documentation.
### Inheriting documentation
- `@inherit source_function` will inherit all supported components from `source_function()`.
- `@inheritSection source_function Section title` will inherit the single section with title "Section title" from `source_function()`.
- `@inheritDotParams` automatically generates parameter documentation for `...` for the common case where you pass `...` on to another function.
### Child documents
Can call a `.Rmd` file for frequently repeated text
## Past edition notes:
## Object documentation defined
- Focus for tonight is on object documentation
- What do you think when you hear the word object?
- Accessed via `?` or `help()`
- **Object documentation**: reference documentation.
- Purpose is to serve as a reference (e.g., a dictionary entry)
- Great use case for standardized naming conventions (e.g., `stringr` package)
- Difference between object documentation and vignettes
- **Object documentation** = A short-form reference guide
- **Vignettes** = A long-form document on how to use package objects to solve a problem
## Object documentation, an overview
![](images/16-function-documentation/roxygen-namespace.png)
- Documentation files are rendered from a syntax loosely based on `LaTex`.
- `HTML`
- Plain text
- PDF
- More on this syntax can be found in the [`R extensions manual`](https://cran.r-project.org/doc/manuals/R-exts.html#Rd-format)
- [`roxygen2`](https://roxygen2.r-lib.org/) provides a more user-friendly syntax to create documentation
- Comments using `@tags` >> `man/.Rd` files >> `HTML` or PDFs
- Code is intermingled with documentation
- Handles some boilerplate set up
- Abstracts away the differences for documenting different objects
- Manages the `NAMESPACE` (Chapter 13)
## The documentation workflow
- Two workflows
1. Fast, but links don't work
2. Slow, but the links work
- You may need to adjust some settings if build and reload doesn't work
![](images/16-function-documentation/function-documentation-workflow.png)
## Documenting functions
- Most commonly documented object
- Three common tags:
1. `@param name description`: describes the function's inputs or parameters.
- These need to be documented
- Multiple arguments can be documented in one place `@param x,y description`
1. `@examples`
- Provides executable code on how to use the function in practice
- Must run without errors or use `\dontrun{}`
- **Keep in mind:** Most users will look at examples first
1. `@return`
- Describes the output from the function.
- Addional tags
- `@section`
- `@seealso`
- `@family`
- `@alias`
- `@keyword`
- Checkout the [Rd (documentation) tags vignette](https://roxygen2.r-lib.org/articles/rd.html)
- Keep style conventions top of mind
- Check out the book for more details
- [`ggplot2` example](https://github.com/tidyverse/ggplot2/blob/main/R/aes.r)
## Documenting datasets
- A different process, see [Chapter 14](https://r-pkgs.org/data.html).
## Documenting packages
- Provide a help page for your package as a whole
- `package?foo`
- Intended to describe the most important components of the package
- Great place to put package level import statements
- [`ggplot2` example](https://github.com/tidyverse/ggplot2/blob/main/R/ggplot2-package.R)
## Documenting classes, generics, and methods
- S3 generics
- Are regular functions, so document them as such.
- [`dplyr::glimpse()` example](https://github.com/r-lib/pillar/blob/main/R/glimpse.R)
- S4 classes and methods
- Use `@slot` to document the slots of the class.
- Aim to keep all your documentation together
- Use `@rdname` or `@describeIn` to keep docs together
- Control ordering of code loading by using `@include`
- RC (reference classes)
- Uses the docstring in the method for the documentation
- Is included within the 'Methods' section
- You now only need one `roxygen` block per class
- Uses the `@field`
- See the `account` example in`regexcite`
## A note about special characters
- `@` denotes a tag, so use `@@` for a literal `@`
- `%` denotes start of a `LaTex` comment, so escape for a literal `%` `\%`
- Escape your backslashes (e.g., `\\`)
## Do repeat yourself
- Self-contained documentation vs. [`DRY` (don't repeat yourself)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
- Limit user frustration resulting from navigating multiple help files
- Two ways to handle:
1. `@inheritParams`: reuse parameter documentation
- From source `@inheritParams function`
- From another package `@inheritParams package::function`
```{r inherit_params_example2, eval=FALSE}
#' @param a This is the first argument.
foo <- function(a) a + 10
#' @param b This is the second argument.
#' @inheritParams foo
bar <- function(a, b) {
foo(a) * 10
}
# Equivalent to
#' @param a This is the first argument.
#' @param b This is the second argument.
bar <- function(a, b) {
foo(a) * 10
}
```
1. `@describeIn` or `@rdname`: document multiple functions in one place
- Use with caution. Can lead to confusing documentation.
- See the `foobar` example
- See the `arithmetic` example
## Text formatting
- Check out the [reference sheet](https://r-pkgs.org/man.html#text-formatting) in the book
- Use as a reference
- Generally follows a `LaTex` like syntax
- `\formatLikeThis{yourText}`
- Formatting that can be applied:
- Character formatting
- Linking to other docs or materials
- Lists
- Mathematical notation
- Tables
## Meeting Videos
### Cohort 1
`r knitr::include_url("https://www.youtube.com/embed/BN0mBuuLKz8")`
`r knitr::include_url("https://www.youtube.com/embed/oCbDqT8uIHY")`
### Cohort 2
`r knitr::include_url("https://www.youtube.com/embed/--GzGdfhCsI")`
### Cohort 3
#### Part 1
`r knitr::include_url("https://www.youtube.com/embed/---BWbMr5B0?start=1821")`
#### Part 2
`r knitr::include_url("https://www.youtube.com/embed/F3DnD4N-s5w")`
<details>
<summary> Meeting chat log </summary>
```
#### Part 1
00:01:58 Ryan Metcalf: Fix for BlueTooth: sudo kill bluetoothd
00:04:49 Brendan Lam: https://twitter.com/lucystats/status/959504698842652672
00:04:57 Brendan Lam: How to pronounce it (supposedly)
00:05:22 Ryan Metcalf: Awesome Brendan! great thread!
00:17:32 Ryan Metcalf: https://creativecommons.org/Government
00:18:59 Ryan Metcalf: Directly related to the US: https://resources.data.gov/open-licenses/
00:24:16 Ryan Metcalf: Quick side note: I received a block due to API key. You can acquire one at: http://api.census.gov/data/key_signup.html
00:41:21 Ryan Metcalf: The Google Verse turned up this link for R as a package is GPL-2 | GPL-3. https://www.r-project.org/Licenses/#:~:text=R%20as%20a%20package%20is,to%20see%20if%20this%20applies.
00:44:14 Isabella Velásquez: ??pivot_longer every day
00:49:28 Rex Parsons: I think you're right
01:06:38 Isabella Velásquez: I learned of this add in that helps with roxygen2 tags: https://github.com/matt-dray/snorkel
01:11:24 Ryan Metcalf: S3 Reference: https://adv-r.hadley.nz/s3.html?q=S3#implicit-class
```
</details>
### Cohort 4
`r knitr::include_url("https://www.youtube.com/embed/jr-NEbNFjV0")`