
R/stopifnot_.R
stopifnot_.RdIf any of the expressions (in ...) are not all TRUE, an error is raised. If
a stop_expr() function exists for the expression expr, it is called to
generate the error message, otherwise a default message is created.
stopifnot_(...)
get_stop_fun(
x = NULL,
expr = substitute(x),
par. = list(),
call_it = TRUE,
force_stop = TRUE
)
mod_not(mod)
mod_content(x, expr)Any number of R expressions, which should each evaluate to (a logical vector of all) TRUE.
An expression to analyze
An expression object
A list of additional parameters to pass to the stop function,
optionally containing msg a string with custom message(s), arg a single
string with the name of the argument that failed the assertion, mod a
single string with starting modifier (it is recomputed), id an
identifier to append to the error class, or call the call where the error
was generated. Default is an empty list.
If TRUE, the corresponding stop_xxx() function is called
(if it exists) to generate the error message. If FALSE, see force_stop.
Default is TRUE.
If call_it is TRUE and no stop_xxx() function exists
for the core expression, or if it exists but does not stop, and if
force_stop = TRUE (default), a generic error message is generated and the
function stops. If force_stop = FALSE, no error is raised and information
about the stop function is returned.
A modifier string (could be "", "!", "any", "all",
"!any", "!all", or any combination of these).
For stopifnot_(), NULL if all statements in ... are TRUE.
For get_stop_fun(call_it = FALSE), a list with stop_fun the name
of the stop function, call the call to the stop function (if it exists,
otherwise NULL), mod the modifier, and expr the core expression,
excluding the modifier.
mod can be NULL or "" if no modifier is present. Otherwise, it is "!"
(not true), "any" (at least one element is true), "all" (all elements are
true), "!any" (all elements are wrong), or "!all" (at least one element is
wrong). The error message build by your stop_xxx() functions should take
this modifier into account to issue the correct error message for the core
expression.
For mod_not(), TRUE if the modifier starts with "!", FALSE
otherwise.
For mod_content(), a message with the content of expr and its
value x.
get_stop_fun() and mod_not() are utility functions to compute the stop
function call and manage a modifier (!, any() or all()) in expressions
to ease building error messages.
# stop <- stop_
# Note that |> try() is just there to catch error; do not use in your code!
x <- 1
stopifnot_(1 == 1, all.equal(pi, 3.14159265), x < 2) # No error
stopifnot_(1 == 1, all.equal(pi, 3.14159265), x > 2) |> try()
#> Error in stopifnot_(1 == 1, all.equal(pi, 3.14159265), x > 2) :
#> object 'x' not found
# Compare with the message you got using base::stopifnot():
stopifnot(1 == 1, all.equal(pi, 3.14159265), x > 2) |> try()
#> Error in eval(expr, envir) : x > 2 is not TRUE
stopifnot_(is.character(letters), length(letters) == 1) |> try()
#> Error in stopifnot_(is.character(letters), length(letters) == 1) :
#> ! `length(letters)` must be == `1`.
#> ℹ `length(letters)` is: 26.
stopifnot_(all.equal(pi, 3.141593), 2 < 2, (1:10 < 12), "a" < "b") |> try()
#> Error in stopifnot_(all.equal(pi, 3.141593), 2 < 2, (1:10 < 12), "a" < :
#> `pi` and `3.141593` are not equal
#> ℹ Mean relative difference: 1.102658e-07
# get_stop_fun() returns infos about a stop function when call_it = FALSE
get_stop_fun(length(letters) == 1L, call_it = FALSE)
#> $stop_fun
#> [1] "stop_=="
#>
#> $call
#> `stop_==`(length(letters), 1L, par. = list(mod = ""))
#>
#> $mod
#> [1] ""
#>
#> $expr
#> length(letters) == 1L
#>
get_stop_fun(length("a") != 1L, call_it = FALSE) # mod == "!", expr = "=="
#> $stop_fun
#> [1] "stop_=="
#>
#> $call
#> `stop_==`(length("a"), 1L, par. = list(mod = "!"))
#>
#> $mod
#> [1] "!"
#>
#> $expr
#> length("a") == 1L
#>
get_stop_fun(!any(c(TRUE, TRUE, NA)), call_it = FALSE) # mod == "!any"
#> $stop_fun
#> [1] "stop_c"
#>
#> $call
#> NULL
#>
#> $mod
#> [1] "!any"
#>
#> $expr
#> c(TRUE, TRUE, NA)
#>
# all! is the same as !any (and any! is !all)
get_stop_fun(all(!c(TRUE, FALSE, NA)), call_it = FALSE) # mod == "!any"
#> $stop_fun
#> [1] "stop_c"
#>
#> $call
#> NULL
#>
#> $mod
#> [1] "!any"
#>
#> $expr
#> c(TRUE, FALSE, NA)
#>
# Contrived and weird example: it got simplified for mod
get_stop_fun(all(any(!!all(!anyNA(x)))), call_it = FALSE) # mod == "!any"
#> $stop_fun
#> [1] "stop_anyNA"
#>
#> $call
#> NULL
#>
#> $mod
#> [1] "!any"
#>
#> $expr
#> anyNA(x)
#>
# Call the stop function (if it exists) to raise the error
get_stop_fun(is.numeric(letters) && length(letters) > 0L) |> try()
#> Error in get_stop_fun(is.numeric(letters) && length(letters) > 0L) :
#> `is.numeric(letters) && len ...` is not TRUE
# mod_not() can be used exclusively to build either a positive, or a negative
# sentence in your error message when the expression always returns a single
# logical value, because in this case "any" or "all" have no effect.
stop_length_one <- function(x, ..., par. = list()) {
arg <- lbl(.op$arg %||% par.$arg %||% substitute(x))
# length(x) == 1 always returns a single logical, can use mod_not() here
# and safely ignore 'any' or 'all' modifiers
if (mod_not(par.$mod)) {
stop(
"!" = "{.code {arg}} cannot have length 1.")
} else {
stop(
"!" = "{.code {arg}} must have length 1",
"*" = "Its length is {length(x)}.")
}
}
length("a") == 1 || stop_length_one("a")
#> [1] TRUE
(length(letters) == 1 || stop_length_one(letters)) |> try()
#> Error in stop_length_one(letters) :
#> {.code {arg}} must have length 1Its length is {length(x)}.
# This avoids writing two stop_xxx() functions, one for == and one for !=
(length("a") != 1 || stop_length_one("a", par. = list(mod = "!"))) |> try()
#> Error in stop_length_one("a", par. = list(mod = "!")) :
#> {.code {arg}} cannot have length 1.
(!length("a") == 1 || stop_length_one("a", par. = list(mod = "!"))) |> try()
#> Error in stop_length_one("a", par. = list(mod = "!")) :
#> {.code {arg}} cannot have length 1.
# any() or all() have no effect on single logical and can then be ignored
(any(length("a") != 1) ||
stop_length_one("a", par. = list(mod = "!all"))) |> try()
#> Error in stop_length_one("a", par. = list(mod = "!all")) :
#> {.code {arg}} cannot have length 1.
rm(stop)
#> Warning: object 'stop' not found