R: utiliser l'opérateur de tube magrittr dans un package auto-écrit

101

Je voudrais utiliser l'opérateur pipe %>%introduit dans le magrittrpackage dans un package que j'ai écrit moi-même pour enchaîner dplyrles transformations de données. magrittrest répertorié comme Importdans le DESCRIPTIONfichier. Après avoir chargé mon propre package et testé la fonction qui utilise l'opérateur pipe, j'obtiens le message d'erreur suivant:

Erreur dans le nom de la fonction (paramètre,: impossible de trouver la fonction "%>%"

Le passage %>%au magrittr::%>%code source de la fonction n'aide pas non plus car le package ne peut plus être construit.

alexander keth
la source
4
Je déconseillerais l'opérateur de tube à l'intérieur d'une fonction à l'intérieur d'un package. Cela rend le débogage beaucoup plus difficile (la pile d'appels devient incroyablement profonde avec le tuyau). Pour les packages, je remplacerais simplement une variable temporaire, ce qui rend les tests beaucoup plus faciles (pensez: R vous indiquant sur quelle ligne l'erreur s'est produite). Le tuyau est bien pour une utilisation interactive, mais pour la programmation, cela peut être un fardeau.

Réponses:

102

Cela aurait dû fonctionner correctement si vous aviez magrittrlisté dans Depends. Cependant, cela n'est pas conseillé . , Vous quittez la place magrittrdans Importset ajoutez la ligne suivante NAMESPACE:

importFrom(magrittr,"%>%")

Je suggère de lire Writing R extensions . Votre question est traitée aux paragraphes 1.1.3 et 1.5.1.

Tonytonov
la source
1
@alexanderketh Dans ce cas, vous devez appuyer sur la coche verte à côté de la réponse pour la marquer comme acceptée. Bienvenue à SO!
tonytonov
54
Si vous utilisez roxygen2, vous pouvez ajouter #' importFrom magrittr "%>%"pour que NAMESPACE soit rempli automatiquement pendant roxygenize().
Roman Luštrik
38
@ RomanLuštrik, juste manquant @, devrait être#' @importFrom magrittr "%>%"
Roah
13
Notez que cela ne vous permettra d'utiliser %>%qu'en interne dans votre package. Si votre API oblige les utilisateurs à enchaîner les fonctions à l'aide de %>%, ils devront toujours se charger explicitement magrittr. Une façon de résoudre ce problème consiste à réexporter la fonction. Voici un exemple de comment procéder.
Ramnath
C'est aussi ce que fait ce package, comme mentionné ici
jiggunjer
33

Il existe désormais un moyen plus simple de prendre en charge le tube dans vos packages. Le merveilleux package usethisa la fonction use_pipe(). Vous exécutez cette fonction une fois et elle gère tout. Voici comment la use_pipe()fonction est décrite dans la usethisdocumentation:

La configuration est-elle nécessaire pour utiliser le tube de magrittr en interne dans votre package et pour le réexporter pour les utilisateurs de votre package:

Ajoute magrittr à "Imports" dans DESCRIPTION

Crée R / utils-pipe.R avec le modèle roxygen nécessaire

Andrew Brēza
la source
Ajoutez-vous la ligne use_pipe()au code que vous utilisez pour créer le package? Par exemple, je lance: 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). Aurais-je juste ajouter use_pipe()au début?
Josh le
1
@Josh vous utilisez les usethisfonctions une fois lorsque vous développez le package. Ces fonctions ajoutent ensuite les pièces nécessaires aux instructions de construction et à tout le reste.
Andrew Brēza
32

Une solution supplémentaire - utilisez le roxygenpackage. Il est implémenté dans le cadre du devtoolspackage. Une fois devtoolsinstallé, l'appel devtools::document()mettra à jour votre NAMESPACEpour vous. Il crée également automatiquement des fichiers .Rd avec de la documentation, ce qui est pratique.

Tout ce que vous faites est d'ajouter un commentaire spécial dans le format #' @import packagenameà un fichier pour importer toutes les fonctions de ce package, ou #' @importFrom packagename functionnamepour importer une fonction. Vous pouvez avoir autant de ces commentaires que vous le souhaitez dans vos fichiers, vous pouvez donc en avoir un ensemble en haut de chaque fichier, ou avec chacune de vos fonctions nécessitant une fonction externe.

Ensuite, vous exécutez devtools::document()et il analyse votre code à la recherche de ces commentaires, puis il crée un NAMESPACEfichier approprié pour vous. Facile.

Mike Stanley
la source
1
Lorsque je fais cela, cela gâche les commentaires oxygène suivants qui se rapportent au fichier d'aide pour la première fonction du script R. Comment séparer les commentaires globaux sur l'oxygène de ceux du fichier d'aide?
jzadra
2
Je mets généralement les commentaires d'importation avec chaque fonction individuellement. De cette façon, si d'autres fonctions du fichier changent, vos importations restent exactes. Donc, il n'y a pas de définitions globales.
Mike Stanley
18

En supposant que vous utilisez RStudio, le devtoolspackage de Hadley , et répertorié magrittrdans la section Importations du DESCRIPTIONfichier, voici les étapes que j'ai suivies pour faire %>%fonctionner mes fonctions de package.

Tout d'abord, écrivez la fonction 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()
}

Deuxièmement, courez devtools::document().

Troisièmement, courez devtools::load_all().

Un fichier comme celui- ci sera créé dans votre R/répertoire et votre fonction devrait fonctionner comme prévu.

Jubbles
la source
6
quel est le but @name %>%ici?
JelenaČuklina