test_is_integer <- test(is.integer(x))
test_is_integer(10L) # TRUE
test_is_integer("A") # FALSEcheckwriter
Easily write, compose, and edit functions for testing and checking objects in R.
This is a copy of the README for my package {checkwriter}, which is currently under construction. You can follow the development of {checkwriter} here.
{checkwriter} is a package for writing and composing fast object tests and checks with Tidyverse-style-guide-compliant error messages. {checkwriter} provides the following core functions:
test(), generate a test function which returnsTRUEorFALSEcheck(), generate a check function which returns it’s input if that input passes atest()and emits an error otherwiseand_checks(), combine severalcheck()functions using&&. Inputs must pass everytest()associated with the combinedcheck()functionsor_checks(), combine severalcheck()functions using||. Inputs must pass at least onetest()associated with the combinedcheck()functionsvectorize_check(), convert a scalarcheck()function to a vectorizedcheck()
Installation
You can install the development version of {checkwriter} from GitHub with:
# install.packages("devtools")
devtools::install_github("EthanSansom/checkwriter")Features
These are mostly un-implemented as of yet. Shown below are un-run examples which showcase the {checkwriter} interface.
A <checkwriter_test> is a function which returns TRUE or FALSE.
The first argument of a <checkwriter_test> functions is always x, the object to be tested. Other required test arguments can be supplied to ....
# Test whether `x` is length `len`. `null_or()` returns `NULL` if it's first
# argument is `NULL`. This means that, by default, `test_length(x)` always
# returns `TRUE`.
test_length <- test(null_or(len, len == length(x)), len = NULL)
test_length(1:5) # TRUE
test_length(1:5, len = 5L) # TRUE
test_length(1:5, len = 2L) # FALSEA <checkwriter_check> is a function which returns its input if a test is passed and emits an error otherwise.
check_is_integer <- check(
test = test_is_integer,
header = "{.arg {x_name}} must be an integer.",
bullets = "{.arg {x_name}} is {.obj_type_friendly {x}}."
)
check_is_integer(10L)
#> [1] 10
try(check_is_integer("A"))
#> Error:
#> ! `"A"` must be an integer.
#> ✖ `"A"` is a string.Note that we build up a check() function using a test(). The generated check inherits all of the arguments of its input test (e.g. len). Additionally, check() generates an argument arg_name = rlang::caller_arg(arg) for each of it’s test arguments. These names can then be used in error messages.
check_length <- check(
.test = test_length,
.header = "{.arg {x_name}} must be length {len}.",
.bullets = "{.arg {x_name}} is length {length(x)}."
)
check_length(1:5, len = 5, x_name = "x")
#> [1] 1 2 3 4 5
try(check_length(1:5, len = 2L, x_name = "x"))
#> Error:
#> ! `x` must be length 2.
#> ✖ `x` is length 5.Several checks can be composed with and_checks() to make a new <checkwriter_check> function. By default, checks composed using and_checks() emit a message with the error bullets associated with the first failed test (e.g. is.integer or len == length(x)).
check_int <- and_checks(
# If we're not checking the length `len` don't mention
# it in the error message.
.header = if_null_else(
len,
"{.arg {x_name}} must be an integer.",
"{.arg {x_name}} must be an integer of length {len}."
),
check_is_integer,
check_length
)
check_int(10L, len = 1L)
#> [1] 10
try(check_int(c(1L, 2L), len = 5L, x_name = "x"))
#> Error:
#> ! `x` must be an integer of length 5.
#> ✖ `x` is length 2.
try(check_int("B"))
#> Error:
#> ! `"B"` must be an integer.
#> ✖ `"B"` is a string.