Получить имя элемента списка из индекса - PullRequest
0 голосов
/ 14 апреля 2020

Я пытаюсь использовать следующий код glue для создания информативного сообщения об ошибке

library(rlang)
library(glue)

my_function <- function(x) {
  UseMethod("my_function", x)
}

my_function.default <- function(x) {
  abort(glue(
    "Can't calculate my_function because { deparse(substitute(x)) } is of type ",
    glue_collapse(class(x))
  ))
}

Используя этот список тестов, мы видим, что он работает:

test <- list(
  x = c(1,2,3),
  y = c("one", "two", "three")
)

my_function(test[[1]])
Error: Can't calculate my_function because test[[1]] is of type numeric
Run `rlang::last_error()` to see where the error occurred. 

Но возможно ли использовать glue для возврата ошибки x, где написано test[[1]], что приводит к ошибке:

Can't calculate my_function because x is of type numeric

1 Ответ

1 голос
/ 18 апреля 2020

Вот функция, которая копается в выражении индексации, чтобы вывести имя индексируемого элемента. Вкратце, он преобразует выражения, которые следуют за шаблоном list[index], в names(list)[index], в то же время считая, что list$name уже имеет имя в выражении.

getElementNames <- function(ee) {
    ## Determine if ee is an indexing operation
    eel <- as.list(ee)
    isIdx <- purrr::map_lgl(exprs( `[`, `[[`, `$` ),
                            identical, eel[[1]])

    ## If not, return the expression itself as a string
    if(!any(isIdx)) return( deparse(ee) )

    ## The name may already be in the expression
    if( is.name(eel[[3]]) || is.character(eel[[3]]) )
        return( as.character(eel[[3]]) )

    ## Compose an expression indexing the names
    nms <- eval.parent(expr( names(!!eel[[2]])[!!eel[[3]]] ))

    ## Names might be missing
    `if`( is.null(nms), deparse(ee), nms )
}

Функция в действии:

test  <- list(a=4, b=5, c=6)
test2 <- 1:3
ftest <- function(x) abort(glue("Can't calculate {getElementNames(substitute(x))}"))

ftest( test[[2]] )    # index by numeric value
# Error: Can't calculate b

ftest( test$c )       # index by name
# Error: Can't calculate c

ftest( test[["a"]] )  # another way to index by name
# Error: Can't calculate a

i <- 2; j <- 3
ftest( test[i:j] )    # index multiple elements
# Error: Can't calculate b
# * Can't calculate c

ftest( test2[3] )     # index something with no names
# Error: Can't calculate test2[3]

ftest( fun_that_returns_list() )  # non-indexing expression
# Error: Can't calculate fun_that_returns_list()

ftest( 1:3 )                      # another non-indexing expression
# Error: Can't calculate 1:3

...