R: use el operador de tubería magrittr en un paquete escrito por usted mismo

100

Me gustaría usar el operador de tubería %>%introducido en el magrittrpaquete en un paquete que escribí yo mismo para encadenar dplyrtransformaciones de datos. magrittraparece como Importen el DESCRIPTIONarchivo. Después de cargar mi propio paquete y probar la función que usa el operador de tubería, aparece el siguiente mensaje de error:

Error en el nombre de la función (parámetro,: no se pudo encontrar la función "%>%"

Cambiar %>%a magrittr::%>%en el código fuente de la función tampoco ayuda porque el paquete ya no se puede construir.

alexander keth
fuente
4
No recomendaría el operador de tubería dentro de una función dentro de un paquete. Hace que la depuración sea mucho más difícil (la pila de llamadas se vuelve increíblemente profunda con la tubería). Para los paquetes, simplemente sobrescribiría una variable temporal, lo que facilita mucho las pruebas (piense: R le dice en qué línea ocurrió el error). La tubería está bien para uso interactivo, pero para la programación puede ser una carga.

Respuestas:

100

Debería haber funcionado correctamente si lo hubiera magrittrincluido en Depends. Sin embargo, esto no se recomienda . En su lugar, deja magrittren Importsy añadir la siguiente línea NAMESPACE:

importFrom(magrittr,"%>%")

Sugiero la lectura de las extensiones de escritura R . Su pregunta se aborda en los párrafos 1.1.3 y 1.5.1.

Tonytonov
fuente
1
@alexanderketh En ese caso, debe presionar la marca de verificación verde junto a la respuesta para marcarla como aceptada. ¡Bienvenido a SO!
tonytonov
54
Si está usando roxygen2, puede agregar #' importFrom magrittr "%>%"para que NAMESPACE se complete automáticamente durante roxygenize().
Roman Luštrik
38
@ RomanLuštrik, solo falta @, debería ser#' @importFrom magrittr "%>%"
Roah
13
Tenga en cuenta que esto solo le permitirá usarlo %>%internamente en su paquete. Si su API requiere que los usuarios encadenen funciones usando %>%, aún tendrán que cargar explícitamente magrittr. Una forma de resolver este problema es volver a exportar la función. A continuación, se muestra un ejemplo de cómo hacerlo.
Ramnath
Esto también es lo que hace el uso de este paquete, como se menciona aquí
jiggunjer
32

Una solución adicional: use el roxygenpaquete. Está implementado como parte del devtoolspaquete. Una vez que devtoolsesté instalado, la llamada devtools::document()actualizará tu NAMESPACE. También construye automáticamente archivos .Rd con documentación, lo cual es útil.

Todo lo que hace es agregar un comentario especial en el formato #' @import packagenamea un archivo para importar todas las funciones de ese paquete, o #' @importFrom packagename functionnamepara importar una función. Puede tener tantos de estos comentarios como desee en sus archivos, por lo que puede tener un conjunto de ellos en la parte superior de cada archivo, o con cada una de sus funciones que necesite una función externa.

Luego lo ejecuta devtools::document()y analiza su código en busca de esos comentarios, y luego crea un NAMESPACEarchivo apropiado para usted. Fácil.

Mike Stanley
fuente
1
Cuando hago esto, estropea los siguientes comentarios de oxígeno que pertenecen al archivo de ayuda para la primera función en el script R. ¿Cómo separo los comentarios de oxígeno global de los del archivo de ayuda?
jzadra
2
Normalmente pongo los comentarios de importación con cada función individualmente. De esa manera, si cambian otras funciones en el archivo, sus importaciones se mantienen precisas. Entonces, no hay definiciones globales.
Mike Stanley
32

Ahora existe una forma más sencilla de admitir la tubería en sus paquetes. El maravilloso paquete usethistiene la función use_pipe(). Ejecuta esa función una vez y se encarga de todo. Así es como use_pipe()se describe la función en la usethisdocumentación:

¿Es necesaria la configuración para usar la tubería de magrittr internamente en su paquete y reexportarla para los usuarios de su paquete?

Agrega magrittr a "Importaciones" en DESCRIPTION

Crea R / utils-pipe.R con la plantilla de oxígeno necesaria

Andrew Brēza
fuente
¿Agrega la línea use_pipe()al código que usa para construir el paquete? Por ejemplo, corro: 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). ¿Solo agregaría use_pipe()al principio?
Josh
1
@Josh, usas las usethisfunciones una vez cuando estás desarrollando el paquete. Esas funciones luego agregan las partes necesarias a las instrucciones de construcción y todo lo demás.
Andrew Brēza
18

Suponiendo que está usando RStudio, el devtoolspaquete de Hadley , y que aparece magrittren la sección Importaciones del DESCRIPTIONarchivo, aquí hay pasos que tomé para que %>%funcionen en las funciones de mi paquete.

Primero, escriba la función 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()
}

Segundo, corre devtools::document().

Tercero, corre devtools::load_all().

Se creará un archivo como este en su R/directorio y su función debería funcionar como se esperaba.

Jubbles
fuente
6
cual es el proposito de @name %>%aqui?
JelenaČuklina