在 R 中使用 NSE 产生信息性的 `stopifnot()` 错误

Making informative `stopifnot()` errors using NSE in R

我想要提供信息 stopifnot() 错误。

我读过: http://r-pkgs.had.co.nz/tests.html(最后关于使用 NSE 为示例打印信息性测试错误的部分似乎相关) 和 http://adv-r.had.co.nz/Computing-on-the-language.html 但我无法用简洁的代码打印信息性错误:

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)

输出给出了这个(信息量不大)

Error: eval(bquote(.(x) %in% e[[.(z)]])) is not TRUE

我希望错误信息更丰富,这样说:

Error: 5 %in% e[["label"]] is not TRUE

我怎样才能让它工作?或者什么是实现我想要的最好方法

我知道我可以写一个 if condition not true 然后打印我自己的错误作为替代,但是额外的代码很麻烦。我想了解如何让 NSE 让它发挥作用。

编辑: 我采用这种方法的动机来自于阅读 hadley 的评论(在 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 只是

的便利函数
if(!all(condition)) stop(standard message)

对于自定义消息,只需编写代码即可。您可以用两行替换 stopifnot 调用:

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

CRAN 上有许多软件包可以解决有意义的错误消息问题。我从 assertthatassertive 包开始,但我现在将 checkmate 用于生产代码,尤其是用于检查函数的参数。顺便说一句,checkmate 还扩展了 Hadley 的 testthat 包。

checkmate,

checkmate::assert_choice(5, e[["label"]])

以及

checkmate::assert_choice(5, e$label)

return错误信息:

Error: Assertion on '5' failed: Must be element of set {'1','2','3'}, but is '5'.

函数中也可以使用

check_in_y <- function(x, z, e) {
  checkmate::assert_choice(x, e[[z]])
}
check_in_y(5, "label", e)

其中 return 是错误信息:

Error in check_in_y(5, "label", e) :
Assertion on 'x' failed: Must be element of set {'1','2','3'}, but is '5'.