Захватить вывод следующего метода - PullRequest
0 голосов
/ 28 сентября 2018

Я создаю метод S3 для универсального элемента, определенного в другом пакете.Более ранний метод для универсального генерирует некоторый вывод на консоль, который не возвращается как часть возвращаемого значения функции, он выводится только на консоль.Я хотел бы захватить этот вывод для использования в моем собственном методе.

Я пытался использовать capture.output() на NextMethod(), но это просто приводит к странной ошибке:

foo <- function(x, ...) UseMethod("foo")
foo.bar <- function(x, ...) cat(x, "\n")
foo.baz <- function(x, ...) capture.output(NextMethod())

foo(structure(1, class = "bar"))
#> 1
foo(structure(1, class = c("baz", "bar")))
#> Error: 'function' is not a function, but of type 8

Это ожидаемое поведение, известное ограничение или ошибка?Я не смог найти ничего, что соответствует этой ошибке с помощью быстрого поиска.Как я могу получить выходные данные следующего метода S3 в другом методе S3?

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

Это ... "ожидаемое поведение".Я говорю это, потому что считаю, что это технически верно, но, вероятно, у пользователя нет возможности ожидать этого обязательно.Если вас не волнует, почему это происходит, но вы просто хотите посмотреть, как это обойти, перейдите к заголовку «Исправление», потому что в следующем объяснении ошибки мало что есть.

Чтоозначает 'function' is not a function, but of type 8?

type 8 относится к типу 8 SEXP.Из Раздела первого Руководства по внутренним компонентам R :

То, что пользователи R считают переменными или объектами, - это символы, которые связаны со значением.Значение можно рассматривать как SEXP (указатель) или структуру, на которую оно указывает, SEXPREC ...

В настоящее время используются SEXPTYPE 0:10 и 13:25 ....

нет SEXPTYPE Описание
...
3 замыкания CLOSXP
...
8 Встроенные функции BUILTINSXP

NextMethod() ожидает CLOSXPне BUILTINSXP.Мы можем увидеть это, если посмотрим на исходный код (около строки 717) do_nextmethod(), функцию C, лежащую в основе NextMethod()

SEXP attribute_hidden do_nextmethod(SEXP call, SEXP op, SEXP args, SEXP env)
{
    // Some code omitted
    if (TYPEOF(s) != CLOSXP){ /* R_LookupMethod looked for a function */
        if (s == R_UnboundValue)
            error(_("no calling generic was found: was a method called directly?"));
        else
            errorcall(R_NilValue,
              _("'function' is not a function, but of type %d"),
              TYPEOF(s));
    }

Так почему это произошло здесь?Вот где это становится сложно.Я полагаю, это потому, что, передавая NextMethod() через capture.output(), он вызывается с помощью eval(), который является встроенным (см. builtins()).

Так как мы можем справиться с этим?Читайте дальше ...

Исправление

Мы можем смоделировать вывод захвата с умным использованием sink(), cat() и tempfile():

foo.baz <- function(x, ...) {
    # Create a temporary file to store the output
    tmp <- tempfile("tmp.txt")
    # start sink()
    sink(tmp)
    # call NextMethod() just for the purpose of capturing output
    NextMethod()
    # stop sink'ing
    sink()
    # store the output in an R object
    y <- readLines(tmp)
    # here we'll cat() the output to make sure it worked
    cat("The output was:", y, "\n")
    # destroy the temporary file
    unlink(tmp)
    # and call NextMethod for its actual execution
    NextMethod()
}

foo(structure(1, class = c("baz", "bar")))
# 1 
0 голосов
/ 28 сентября 2018

Я не уверен, что то, что вы видели, задокументировано или нет: документация ?NextMethod ясно показывает, что это не обычная функция, но я не следил за всеми подробностями, чтобы увидеть, будет ли разрешено ваше использование.

Один из способов сделать то, что вы хотите, был бы

foo.baz <- function(x, ...) {class(x) <- class(x)[-1]; capture.output(foo(x, ...))}

Это предполагает, что метод был вызван непосредственно из вызова универсального;это не будет работать, если есть третий уровень, и foo.baz сам был вызван NextMethod().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...