R: использовать оператор трубы magrittr в самописном пакете

102

Я хотел бы использовать оператор канала, %>%представленный в magrittrпакете, в пакете, который я написал сам, для цепочки dplyrпреобразований данных. magrittrотображается как Importв DESCRIPTIONфайле. После загрузки моего собственного пакета и тестирования функции, использующей оператор канала, я получаю следующее сообщение об ошибке:

Ошибка в имени функции (параметр,: не удалось найти функцию "%>%"

Изменение %>%на magrittr::%>%в исходном коде функции также не помогает, потому что пакет больше не может быть собран.

Александр Кет
источник
4
Я бы посоветовал не использовать оператор pipe внутри функции внутри пакета. Это значительно усложняет отладку (стек вызовов становится безумно глубоким с конвейером). Для пакетов я просто перезаписал временную переменную, что значительно упростило тестирование (подумайте: R сообщает вам, в какой строке произошла ошибка). Канал хорош для интерактивного использования, но для программирования это может быть обузой.

Ответы:

102

Он должен был работать правильно, если бы вы magrittrуказали в Depends. Однако это не рекомендуется . Вместо этого, вы оставляете magrittrв Importsи добавьте следующую строку NAMESPACE:

importFrom(magrittr,"%>%")

Я предлагаю читать расширения Написание R . Ваш вопрос освещен в пунктах 1.1.3 и 1.5.1.

Тонитонов
источник
1
@alexanderketh В этом случае вы должны нажать зеленую галочку рядом с ответом, чтобы отметить его как принятый. Добро пожаловать в SO!
tonytonov
55
Если вы используете roxygen2, вы можете добавить, #' importFrom magrittr "%>%"чтобы NAMESPACE заполнялась автоматически во время roxygenize().
Роман Луштрик,
38
@ RomanLuštrik, просто не хватает @, должно быть#' @importFrom magrittr "%>%"
Роа
13
Обратите внимание, что это позволит вам использовать только %>%внутри вашего пакета. Если ваш API требует, чтобы пользователи связали функции с помощью %>%, им все равно придется явно загружать magrittr. Один из способов решить эту проблему - повторно экспортировать функцию. Вот пример того, как это сделать.
Рамнат
Это также то, что делает пакет usethis, как упоминалось здесь
jiggunjer
33

Теперь есть более простой способ поддерживать канал в ваших пакетах. Замечательный пакет usethisимеет функцию use_pipe(). Вы запускаете эту функцию один раз, и она обрабатывает все. Вот как use_pipe()функция описана в usethisдокументации:

Необходима ли установка для использования канала magrittr внутри вашего пакета и его повторного экспорта для пользователей вашего пакета:

Добавляет magrittr в "Импорт" в ОПИСАНИИ

Создает R / utils-pipe.R с необходимым шаблоном roxygen

Эндрю Бреза
источник
Вы добавляете строку use_pipe()в код, который используете для сборки пакета? Например, я бегу: usethis::use_description(usethis_description); usethis::use_build_ignore(directories); usethis::use_build_ignore(paste0(pkg_name, ".Rproj")); if (file.exists(file.path(pkg_path, "NAMESPACE"))) { file.remove(file.path(pkg_path, "NAMESPACE")) }; devtools::document(pkg_path); devtools::check(pkg_path); devtools::load_all(pkg_path); devtools::install(pkg_path). Мог бы я просто добавить use_pipe()в начале?
Джош
1
@Josh вы используете usethisфункции один раз при разработке пакета. Затем эти функции добавляют необходимые части в инструкции по сборке и все остальное.
Эндрю Бреза 09
32

Еще одно решение - использовать roxygenпакет. Он реализован как часть devtoolsпакета. После devtoolsустановки приложение devtools::document()обновит ваше приложение NAMESPACEдля вас. Он также автоматически создает файлы .Rd с документацией, что очень удобно.

Все, что вам нужно сделать, это добавить специальный комментарий в формате #' @import packagenameк файлу для импорта всех функций из этого пакета или #' @importFrom packagename functionnameдля импорта функции. Вы можете иметь столько комментариев, сколько хотите, в ваших файлах, поэтому вы можете иметь их набор в верхней части каждого файла или с каждой из ваших функций, для которых требуется внешняя функция.

Затем вы запускаете, devtools::document()и он анализирует ваш код в поисках этих комментариев, а затем создает NAMESPACEдля вас соответствующий файл. Легко.

Майк Стэнли
источник
1
Когда я это делаю, это портит следующие кислородные комментарии, относящиеся к файлу справки для первой функции в сценарии R. Как мне отделить глобальные комментарии по кислороду от комментариев из файла справки?
jzadra
2
Я обычно помещаю комментарии импорта к каждой функции индивидуально. Таким образом, если другие функции в файле изменятся, ваш импорт останется точным. Итак, глобальных определений нет.
Майк Стэнли,
18

Предполагая, что вы используете RStudio, devtoolsпакет Хэдли и перечислены magrittrв разделе «Импорт» DESCRIPTIONфайла, вот шаги, которые я предпринял, чтобы заставить %>%работать функции моего пакета.

Сначала напишите функцию foo.R:

#' Convert \code{data.frame} to \code{list}.
#' 
#' @importFrom magrittr %>%
#' @name %>%
#' @rdname pipe
#' @export
#' @param x A \code{data.frame} object.
#' @examples
#' my_result <- foo(iris)
#'
foo <- function(x) {
    x %>%
        as.list()
}

Во-вторых, беги devtools::document().

В-третьих, беги devtools::load_all().

Файл , как это будет создан в вашей R/директории и ваша функция должна работать , как ожидалось.

Jubbles
источник
7
какова здесь цель @name %>%?
JelenaČuklina