I want to make informative stopifnot()
errors.
I've read: http://r-pkgs.had.co.nz/tests.html (the section at the end on using NSE to make informative test error print out for the example seems relevant) and http://adv-r.had.co.nz/Computing-on-the-language.html but I cant get this to print an informative error in concise code:
e <- new.env()
e$label <- c(1,2,3)
check_in_y <- function(x, z, e) {
stopifnot(eval(bquote(.(x) %in% e[[.(z)]])))
}
check_in_y(5,"label", e)
The output gives this (not so informative)
Error: eval(bquote(.(x) %in% e[[.(z)]])) is not TRUE
I want the error to be more informative, saying this:
Error: 5 %in% e[["label"]] is not TRUE
How can I get this to work? Or what's the best approach to achieve what I want
I know I could write an if condition not true then print my own error as an alternative, but the extra code is a hassle. I'd like to understand how to get NSE to get this to work.
Edit: My motivation from this approach came from reading hadley's comments (at http://r-pkgs.had.co.nz/tests.html):
However, if the expectation fails this doesn’t give very informative output:
expect_floor_equal("year", "2008-01-01 00:00:00") ## Error: floor_date(base, unit) not equal to as.POSIXct(time, tz = "UTC") ## Mean absolute difference: 31622400
Instead you can use a little non-standard evaluation to produce something more informative. The key is to use bquote() and eval(). In the bquote() call below, note the use of .(x) - the contents of () will be inserted into the call.
expect_floor_equal <- function(unit, time) { as_time <- function(x) as.POSIXct(x, tz = "UTC") eval(bquote(expect_equal(floor_date(base, .(unit)), as_time(.(time))))) } expect_floor_equal("year", "2008-01-01 00:00:00") ## Error: floor_date(base, "year") not equal to as_time("2008-01-01 00:00:00")
stopifnot
is just a convenience function for
if(!all(condition)) stop(standard message)
For custom messages, just write the code. You can replace the stopifnot
call with two lines:
check_in_y <- function(x, z, e) {
b <- bquote(.(x) %in% e[[.(z)]])
if(!eval(b)) stop(deparse(b), " is not TRUE", call. = FALSE)
}
check_in_y(5, "label", e)
# Error: 5 %in% e[["label"]] is not TRUE