Spell checking your R package

TL;DR

Spell check your R package with the spelling package.

The default setup

I love the spelling package. It is easy to set up and it is very reliable. I do prefer to use it in a slightly different way, though, than what’s suggested in the package README, i.e. calling spelling::spell_check_setup().

My issues with the defaults are:

  • spelling::spell_check_setup() does not add the spelling package as a dependency. This is pretty easy to fix, though.
  • The spell check does not run with devtools::test() or testthat::test_local(), or when running the tests in RStudio or Positron. It only runs with R CMD check. This is a problem for me, because I do not run R CMD check too often, except on the CI.
  • If there is a spelling mistake, R CMD check does not fail. Since I am running R CMD check on the CI, and there is no CI failure, I often don’t learn about the spelling mistakes, only much later.

My goals are:

  • The spell check should be part of the regular tests.
  • Spelling errors should not cause check failures on CRAN.
  • Spelling errors should cause test and check failures locally and on the CI.
  • I want a printout of the spelling errors, should there be any.

Snapshot your spell checks

A pretty easy way to achieve all these is by using snapshot tests.

The idea is to run spelling::spell_check_package() in a regular test case, in a snapshot test, with a test snapshot that shows no errors:

1
2
❯ spelling::spell_check_package()
No spelling errors found.

Should you make a spelling mistake, the snapshot test will fail (on the CI, and on your machine, but not on CRAN), and it’ll also print out the spelling mistakes.

The only slightly tricky part is that spell_check_package() needs to be able to find the files of your package, and they are in a surprising place when the tests run as part of R CMD check.

So here is the piece of code that I add to a package as the tests/testthat/test-spelling.R file, in addition to adding the spelling package as a suggested package in DESCRIPTION:

Spell check as a test caseSee on GitHub
1
2
3
4
5
6
7
8
9
10
11
12
13
test_that("spelling", {
skip_on_cran()
skip_on_covr()

pkg <- test_path("../../")
if (!file.exists(file.path(pkg, "DESCRIPTION"))) {
pkg <- file.path(pkg, "00_pkg_src", .packageName)
}

expect_snapshot({
spelling::spell_check_package(pkg)
})
})

There is no need to run this for test coverage, hence the skip_on_covr() call. The second part takes care of finding the package root while running R CMD check. The expect_snapshot() will not fail on CRAN, but will fail locally and on the CI. A failure looks like this locally:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
❯ testthat::test_local()
✔ | F W S OK | Context
✔ | 17 | arrow-schema
[...]
✖ | 1 0 | spelling
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Failure (test-spelling.R:5:3): spelling
Snapshot of code has changed:
old | new
[1] Code | Code [1]
[2] spelling::spell_check_package(pkg) | spelling::spell_check_package(pkg) [2]
[3] Output | Output [3]
[4] No spelling errors found. - WORD FOUND IN [4]
- filess README.md:13 [5]

* Run `testthat::snapshot_accept('spelling')` to accept the change.
* Run `testthat::snapshot_review('spelling')` to interactively review the change.
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
✔ | 47 | utils
[...]

After adding this file to your package, run spelling::spell_check_package() manually, until your package does not have any spelling mistakes. Then run the snapshot test to record a snapshot without failures, and add the snapshot as well to your package.

That’s all.

Caveats?

It probably (?) does not work with testthat::check_package(). But I don’t really care about that.

This is not the spell check that CRAN uses during R CMD check.