R Как проверить, вызывается ли пользовательская функция внутри определенной функции из определенного пакета

Я хочу создать функцию myfun, которую можно использовать только внутри другой функции, в моем случае dplyrs mutate или summarise. Я больше не хочу полагаться на dplyrс внутренностями (например mask$…).

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

search_calling_fn <- function(pattern) { call_st <- lapply(sys.calls(), `[[`, 1) res <- any(unlist(lapply(call_st, function(x) grepl(pattern, x, perl = TRUE)))) if (!res) { stop(«`myfun()` must only be used inside dplyr::mutate or dplyr::summarise») } else { return() } }

Это работает, как и ожидалось, как показано в двух приведенных ниже примерах (dplyr = 1.0.0).

library(dplyr) myfun <- function() { search_calling_fn(«^mutate|^summarise») NULL } # throws as expected no error mtcars %>% mutate(myfun()) myfun2 <- function() { search_calling_fn(«^select») NULL } # throws as expected an error mtcars %>% mutate(myfun2())

В этом подходе есть одна лазейка: myfun можно вызывать из функции с похожим именем, которая не является функцией dplyr. Интересно, как я могу проверить, из какого пространства имен приходит функция в моем стеке вызовов. rlang имеет функцию call_ns, но она будет работать только в том случае, если функция явно вызывается с package::…. Кроме того, при использовании mutate в стеке вызовов есть mutate_cols внутренняя функция и mutate.data.frame метод S3 — кажется, что оба делают получение пространства имен еще более сложным.

С другой стороны, мне интересно, есть ли лучший, более официальный подход для достижения того же результата: разрешить вызов myfun только в пределах dplyrs mutate или summarise.

Подход должен работать независимо от того, как вызывается функция:

  1. mutate
  2. dplyr::mutate

Дополнительное примечание

После обсуждения ответа @r2evans я понимаю, что решение должно пройти следующий тест:

library(dplyr) myfun <- function() { search_calling_fn(«^mutate|^summarise») NULL } # an example for a function masking dplyr’s mutate mutate <- function(df, x) { NULL } # should throw an error but doesn’t mtcars %>% mutate(myfun())

Таким образом, функция проверки должна не только смотреть на стек вызовов, но и пытаться увидеть, из какого пакета исходит функция в стеке вызовов. Интересно, что отладчик RStudios показывает пространство имен для каждой функции в стеке вызовов, даже для внутренних функций. Интересно, как он это делает, ведь environment(fun)) работает только с экспортированными функциями.

Придирка: вам не хватает закрытия } в конце функции search_calling_fn.   —  person TimTeaFan    schedule 06.07.2020

Спасибо, что заметили это! Я исправил это.   —  person TimTeaFan    schedule 06.07.2020

Связано: 1 и 2.   —  person TimTeaFan    schedule 06.07.2020

Ваш пример кода mutate никогда не даст сбоев, потому что x ленив; поскольку он никогда не используется, он никогда не реализуется, поэтому myfun никогда не вызывается. … но я понимаю вашу точку зрения, getAnywhere в моем ответе слишком нетерпелив.   —  person TimTeaFan    schedule 08.07.2020

Источник: ledsshop.ru

Стиль жизни - Здоровье!