R: use o operador de tubo magrittr em pacote escrito

101

Eu gostaria de usar o operador de canal %>%introduzido no magrittrpacote em um pacote que eu mesmo escrevi para encadear dplyrtransformações de dados. magrittrestá listado como Importno DESCRIPTIONarquivo. Depois de carregar meu próprio pacote e testar a função que usa o operador de tubo, recebo a seguinte mensagem de erro:

Erro em functionname (parâmetro,: não foi possível encontrar a função "%>%"

Mudar %>%para magrittr::%>%no código-fonte da função também não ajuda porque o pacote não pode mais ser compilado.

alexander keth
fonte
4
Eu desaconselho o operador de pipe dentro de uma função dentro de um pacote. Isso torna a depuração muito mais difícil (a pilha de chamadas fica insanamente profunda com o tubo). Para pacotes, eu apenas sobrescreveria uma variável temporária, o que torna o teste muito mais fácil (pense: R dizendo a você em que linha o erro ocorreu). O pipe é adequado para uso interativo, mas para programação pode ser um fardo.

Respostas:

101

Deveria ter funcionado corretamente se você tivesse magrittrlistado em Depends. No entanto, isso não é recomendado . Em vez disso, você deixa magrittrem Importse adicione a seguinte linha NAMESPACE:

importFrom(magrittr,"%>%")

Eu sugiro a leitura de extensões R escrevendo . A sua pergunta é abordada nos parágrafos 1.1.3 e 1.5.1.

Tonytonov
fonte
1
@alexanderketh Nesse caso, você deve atingir a marca verde ao lado da resposta para marcá-la como aceita. Bem-vindo ao SO!
tonytonov
54
Se estiver usando roxygen2, você pode adicionar #' importFrom magrittr "%>%"para que NAMESPACE seja preenchido automaticamente durante roxygenize().
Roman Luštrik
38
@ RomanLuštrik, faltando apenas @, deveria ser#' @importFrom magrittr "%>%"
Roah
13
Observe que isso só permitirá que você use %>%internamente em seu pacote. Se sua API requer que os usuários encadeiem funções usando %>%, eles ainda terão que carregar explicitamente magrittr. Uma maneira de resolver esse problema é reexportar a função. Aqui está um exemplo de como fazer isso.
Ramnath
Isso também é o que o uso deste pacote faz, conforme mencionado aqui
jiggunjer
33

Agora existe uma maneira mais fácil de apoiar o tubo em seus pacotes. O maravilhoso pacote usethistem a função use_pipe(). Você executa essa função uma vez e ela trata de tudo. É assim que a use_pipe()função é descrita na usethisdocumentação:

A configuração é necessária para usar o pipe de magrittr internamente em seu pacote e para reexportá-lo para usuários de seu pacote:

Adiciona magrittr a "Importações" em DESCRIPTION

Cria R / utils-pipe.R com o modelo roxygen necessário

Andrew Brēza
fonte
Você adiciona a linha use_pipe()ao código que usa para construir o pacote? Por exemplo, eu 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). Eu apenas adicionaria use_pipe()no início?
Josh
1
@Josh você usa as usethisfunções uma vez quando está desenvolvendo o pacote. Essas funções, então, adicionam as partes necessárias às instruções de construção e tudo mais.
Andrew Brēza
32

Uma solução adicional - use o roxygenpacote. É implementado como parte do devtoolspacote. Uma vez devtoolsinstalado, chamar devtools::document()irá atualizar seuNAMESPACE para você. Ele também cria arquivos .Rd com documentação, o que é útil.

Tudo o que você faz é adicionar um comentário especial no formato #' @import packagenamea um arquivo para importar todas as funções desse pacote, ou#' @importFrom packagename functionname para importar uma função. Você pode ter quantos comentários quiser em seus arquivos, portanto, pode ter um conjunto deles no topo de cada arquivo, ou com cada uma de suas funções que precisa de uma função externa.

Em seguida, você executa devtools::document()e analisa seu código procurando esses comentários e, em seguida, cria um NAMESPACEarquivo apropriado para você. Fácil.

Mike Stanley
fonte
1
Quando eu faço isso, ele bagunça os seguintes comentários de oxigênio que pertencem ao arquivo de ajuda para a primeira função no script R. Como separo os comentários do oxigênio global dos do arquivo de ajuda?
jzadra
2
Normalmente coloco os comentários de importação com cada função individualmente. Dessa forma, se outras funções no arquivo forem alteradas, suas importações permanecerão precisas. Portanto, não há definições globais.
Mike Stanley
18

Supondo que você esteja usando o RStudio, o devtoolspacote do Hadley , e listado magrittrna seção Importações do DESCRIPTIONarquivo, aqui estão as etapas que executei para fazer o %>%trabalho em minhas funções de pacote.

Primeiro, escreva a função 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, corra devtools::document() .

Terceiro, corra devtools::load_all().

Um arquivo como este será criado em seu R/diretório e sua função deverá funcionar conforme o esperado.

Jubbles
fonte
6
qual é o propósito @name %>%daqui?
JelenaČuklina