3

我想犯信息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)

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

错误:eval(bquote(.(x) %in% e[[.(z)]])) 不是 TRUE

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

错误:5 %in% e[["label"]] 不是 TRUE

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

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

编辑:我采用这种方法的动机来自阅读哈德利的评论(在http://r-pkgs.had.co.nz/tests.html):

但是,如果期望失败,这不会提供非常丰富的输出:

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

相反,您可以使用一些非标准评估来产生更多信息。关键是使用 bquote() 和 eval()。在下面的 bquote() 调用中,注意使用 .(x) - () 的内容将被插入到调用中。

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")
4

2 回答 2

6

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
于 2017-04-13T15:10:18.297 回答
4

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

checkmate,

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

checkmate::assert_choice(5, e$label)

返回错误信息:

错误:“5”上的断言失败:必须是集合 {“1”、“2”、“3”} 的元素,但为“5”。

也可以在函数中使用

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

返回错误消息:

check_in_y(5, "label", e) 中的错误:
'x' 上的断言失败:必须是集合 {'1','2','3'} 的元素,但是是 '5'。

于 2017-04-13T16:32:01.980 回答