|
| 1 | +# R package development |
| 2 | + |
| 3 | +## Key commands |
| 4 | + |
| 5 | + # To run code |
| 6 | + Rscript -e "devtools::load_all(); code" |
| 7 | + |
| 8 | + # To run all tests |
| 9 | + Rscript -e "devtools::test()" |
| 10 | + |
| 11 | + # To run all tests for files starting with {name} |
| 12 | + Rscript -e "devtools::test(filter = '^{name}')" |
| 13 | + |
| 14 | + # To run all tests for R/{name}.R |
| 15 | + Rscript -e "devtools::test_active_file('R/{name}.R')" |
| 16 | + |
| 17 | + # To run a single test "blah" for R/{name}.R |
| 18 | + Rscript -e "devtools::test_active_file('R/{name}.R', desc = 'blah')" |
| 19 | + |
| 20 | + # To redocument the package |
| 21 | + Rscript -e "devtools::document()" |
| 22 | + |
| 23 | + # To check pkgdown documentation |
| 24 | + Rscript -e "pkgdown::check_pkgdown()" |
| 25 | + |
| 26 | + # To check the package with R CMD check |
| 27 | + Rscript -e "devtools::check()" |
| 28 | + |
| 29 | +## Code Style |
| 30 | + |
| 31 | +- Always use `=` for assignment, never `<-`. |
| 32 | +- 2-space indentation, 120-character line limit. |
| 33 | +- `snake_case` for functions and variables, `CamelCase` for R6 classes. |
| 34 | +- When calling a function from imported package `foo` do not write |
| 35 | + `foo::bar()` but `bar()` |
| 36 | +- Double quotes for strings, explicit `TRUE`/`FALSE` (never `T`/`F`), |
| 37 | + explicit `1L` for integers. |
| 38 | +- Use implicit return values for functions. |
| 39 | +- Prefer `result = if (...) ... else ...` over |
| 40 | + `if (...) { result = ... } else { result = ... }` when the only |
| 41 | + difference between branches is the assigned value. |
| 42 | +- User-facing API (exported functions, public R6 methods) must have |
| 43 | + `checkmate` `assert_*()` argument checks. For internal code, match the |
| 44 | + existing level of defensiveness. |
| 45 | +- Use these mlr3misc utilities when appropriate: `map()`, `map_chr()`, |
| 46 | + `invoke()`, `calculate_hash()`, `str_collapse()`, `%nin%`, `%??%`. |
| 47 | +- Before implementing something, read similar existing files first to |
| 48 | + match the established patterns. |
| 49 | +- Always use `#nolint next` to disable linters for the next line instead |
| 50 | + of `# nolint` on the same line. |
| 51 | + |
| 52 | +## File structure and naming |
| 53 | + |
| 54 | +- Name the file as the most important contained function / class |
| 55 | +- No whitespaces, no special chart in filenames |
| 56 | +- Usually one large function / class, per file, but adding multiple |
| 57 | + smaller helpers is ok |
| 58 | + |
| 59 | +## Collation order |
| 60 | + |
| 61 | +- Derived classes must declare `#' @include ParentClass.R` in their |
| 62 | + roxygen header. This controls the `Collate:` field in DESCRIPTION so |
| 63 | + base classes load before derived classes. |
| 64 | + |
| 65 | +## Core dependencies |
| 66 | + |
| 67 | +- Use `checkmate` for arg-checks |
| 68 | +- Use `data.table` for efficient table structures |
| 69 | +- For OOP-stype use `R6` |
| 70 | +- Use `cli` to format messages, warnings, errors and prints |
| 71 | + |
| 72 | +## Testing |
| 73 | + |
| 74 | +- Tests for `R/{name}.R` go in `tests/testthat/test_{name}.R`. |
| 75 | +- All new code should have an accompanying test. |
| 76 | +- If there are existing tests, place new tests next to similar existing |
| 77 | + tests. |
| 78 | +- Strive to keep your tests minimal with few comments. |
| 79 | +- The full test suite takes a long time. Only run tests relevant to your |
| 80 | + changes with `devtools::test(filter = '^{name}')`. |
| 81 | + |
| 82 | +## Documentation |
| 83 | + |
| 84 | +- Every user-facing function should be exported and have roxygen2 |
| 85 | + documentation. |
| 86 | +- Wrap roxygen comments at 120 characters. |
| 87 | +- Write one sentence per line. |
| 88 | +- If a sentence exceeds the limit, break at a comma, “and”, “or”, “but”, |
| 89 | + or other appropriate point. |
| 90 | +- Internal functions should not have roxygen documentation. |
| 91 | +- Always re-document the package after changing a roxygen2 comment. |
| 92 | +- Don’t hand-edit generated artifacts: `man/`, or `NAMESPACE`. |
| 93 | +- Roxygen templates live in `man-roxygen/` |
| 94 | +- Bibliographic references go in `R/bibentries.R` and are cited with |
| 95 | + `` `r format_bib("key")` ``. |
| 96 | + |
| 97 | +## `NEWS.md` |
| 98 | + |
| 99 | +- Every user-facing change should be given a bullet in `NEWS.md`. Do not |
| 100 | + add bullets for small documentation changes or internal refactorings. |
| 101 | +- Each bullet should briefly describe the change to the end user and |
| 102 | + mention the related issue in parentheses. |
| 103 | +- A bullet can consist of multiple sentences but should not contain any |
| 104 | + new lines (i.e. DO NOT line wrap). |
| 105 | +- If the change is related to a function, put the name of the function |
| 106 | + early in the bullet. |
| 107 | +- Order bullets alphabetically by function name. Put all bullets that |
| 108 | + don’t mention function names at the beginning. |
| 109 | + |
| 110 | +## GitHub |
| 111 | + |
| 112 | +- If you use `gh` to retrieve information about an issue, always use |
| 113 | + `--comments` to read all the comments. |
| 114 | + |
| 115 | +## Natural Language |
| 116 | + |
| 117 | +- The following applies to all natural language text, so docs, |
| 118 | + commments, NEWS, etc, but not code |
| 119 | +- Use American english |
| 120 | +- Use the Oxford comma |
| 121 | +- Do not capitalize normal nouns or method names. “Bayesian” is |
| 122 | + capitalized, “random forest” is not. |
| 123 | +- Use cspell to check against typos, and add needed words to |
| 124 | + .cspell/project-words.txt if reasonable |
| 125 | + |
| 126 | +## Further agents files |
| 127 | + |
| 128 | +- Read and respect all files in the `.agents` folder |
0 commit comments