loading...

If 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)

Arguments

...

Any number of R expressions, which should each evaluate to (a logical vector of all) TRUE.

x

An expression to analyze

expr

An expression object

par.

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.

call_it

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.

force_stop

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.

mod

A modifier string (could be "", "!", "any", "all", "!any", "!all", or any combination of these).

Value

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.

Details

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.

See also

Examples

# 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