Создание информативных ошибок `stopifnot()` с использованием NSE в 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)

Вывод дает это (не очень информативно)

Ошибка: eval(bquote(.(X) % в% e[[.(Z)]])) не равен TRUE

Я хочу, чтобы ошибка была более информативной, говоря так:

Ошибка: 5 % в% e[["label"]] не ИСТИНА

Как я могу заставить это работать? Или какой лучший подход для достижения того, чего я хочу

Я знаю, что мог бы написать условие if, не являющееся истинным, а затем напечатать свою собственную ошибку в качестве альтернативы, но лишний код - проблема. Я хотел бы понять, как заставить 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")

2 ответа

Решение

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 есть несколько пакетов, которые решают проблему значимых сообщений об ошибках. Я начал с assertthat а также assertive пакеты, но я сейчас использую checkmate для производственного кода, особенно для проверки аргументов функций. КСТАТИ, checkmate также расширяет Хэдли testthat пакет.

С checkmate,

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

возвращает сообщение об ошибке:

Ошибка в checkmate::assert_choice(5, e[["label"]]):
Утверждение в '5' не выполнено: должен быть элементом множества {'1','2','3'}.

Может также использоваться в функции

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

возвращая то же самое сообщение об ошибке.

Другие вопросы по тегам