R: sử dụng toán tử ống magrittr trong gói tự viết


100

Tôi muốn sử dụng toán tử đường ống được %>%giới thiệu trong magrittrgói trong một gói do tôi tự viết để dplyrchuyển đổi dữ liệu chuỗi . magrittrđược liệt kê như Importtrong DESCRIPTIONtệp. Sau khi tải gói của riêng tôi và kiểm tra chức năng sử dụng toán tử đường ống, tôi nhận được thông báo lỗi sau:

Lỗi trong tên hàm (tham số,: không thể tìm thấy hàm "%>%"

Thay đổi %>%thành magrittr::%>%mã nguồn của hàm cũng không giúp được gì vì không thể xây dựng gói nữa.


4
Tôi sẽ khuyên chống lại toán tử đường ống bên trong một hàm bên trong một gói. Nó làm cho việc gỡ lỗi khó khăn hơn rất nhiều (ngăn xếp cuộc gọi trở nên cực kỳ sâu với đường ống). Đối với các gói, tôi chỉ ghi đè một biến tạm thời, điều này giúp việc kiểm tra dễ dàng hơn rất nhiều (hãy nghĩ: R cho bạn biết lỗi xảy ra ở dòng nào). Đường ống là tốt để sử dụng tương tác nhưng để lập trình nó có thể là một gánh nặng.

Câu trả lời:


100

Nó sẽ hoạt động chính xác nếu bạn đã magrittrliệt kê trong Depends. Tuy nhiên, điều này không được khuyên . Thay vào đó, bạn để lại magrittrtrong Importsvà thêm dòng sau vào NAMESPACE:

importFrom(magrittr,"%>%")

Tôi khuyên bạn nên đọc phần mở rộng Viết R . Câu hỏi của bạn được trình bày trong các đoạn 1.1.3 và 1.5.1.


1
@alexanderketh Trong trường hợp đó, bạn nên đánh dấu tick màu xanh lá cây bên cạnh câu trả lời để đánh dấu là được chấp nhận. Chào mừng đến với SO!
tonytonov

54
Nếu đang sử dụng roxygen2, bạn có thể thêm #' importFrom magrittr "%>%"để NAMESPACE được điền tự động trong thời gian roxygenize().
Roman Luštrik

38
@ RomanLuštrik, chỉ thiếu @, nên có#' @importFrom magrittr "%>%"
Roah

13
Lưu ý rằng điều này sẽ chỉ cho phép bạn sử dụng %>%nội bộ trong gói của mình. Nếu API của bạn yêu cầu người dùng chuỗi các chức năng bằng cách sử dụng %>%, họ sẽ vẫn phải tải một cách rõ ràng magrittr. Một cách để giải quyết vấn đề này là xuất lại hàm. Đây là một ví dụ về cách làm điều đó.
Ramnath

Đây cũng là những gì mà gói này thực hiện, như đã đề cập ở đây
jiggunjer

32

Một giải pháp bổ sung - sử dụng roxygengói. Nó được triển khai như một phần của devtoolsgói. Sau khi devtoolsđược cài đặt, tính năng gọi devtools::document()sẽ cập nhật NAMESPACEcho bạn. Nó cũng tự động tạo các tệp .Rd với tài liệu, rất tiện lợi.

Tất cả những gì bạn làm là thêm nhận xét đặc biệt ở định dạng #' @import packagenamevào một tệp để nhập tất cả các chức năng từ gói đó hoặc #' @importFrom packagename functionnameđể nhập một chức năng. Bạn có thể có bao nhiêu nhận xét này tùy thích trong tệp của mình, vì vậy bạn có thể có một tập hợp chúng ở đầu mỗi tệp hoặc với mỗi hàm của bạn cần một chức năng bên ngoài.

Sau đó, bạn chạy devtools::document()và nó phân tích mã của bạn để tìm kiếm những nhận xét đó và sau đó nó tạo ra một NAMESPACEtệp thích hợp cho bạn. Dễ dàng.


1
Khi tôi làm điều này, nó sẽ làm rối tung các bình luận oxy sau liên quan đến tệp trợ giúp cho chức năng đầu tiên trong tập lệnh R. Làm cách nào để tách các nhận xét về oxy toàn cầu khỏi các nhận xét trong tệp trợ giúp?
jzadra

2
Tôi thường đặt các nhận xét nhập với từng chức năng riêng lẻ. Bằng cách đó, nếu các chức năng khác trong tệp thay đổi, các lần nhập của bạn vẫn chính xác. Vì vậy, không có định nghĩa toàn cục.
Mike Stanley

32

Bây giờ có một cách dễ dàng hơn để hỗ trợ đường ống trong các gói của bạn. Gói tuyệt vời usethiscó chức năng use_pipe(). Bạn chạy chức năng đó một lần và nó xử lý mọi thứ. Đây là cách use_pipe()hàm được mô tả trong usethistài liệu:

Có cần thiết lập để sử dụng đường ống của magrittr trong nội bộ gói của bạn và để xuất lại nó cho người dùng gói của bạn không:

Thêm magrittr vào "Nhập" trong DESCRIPTION

Tạo R / utils-pipe.R với mẫu roxy cần thiết


Bạn có thêm dòng use_pipe()vào mã mà bạn sử dụng để xây dựng gói không? Ví dụ, tôi chạy: 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). Tôi sẽ chỉ thêm use_pipe()vào đầu?
Josh

1
@Josh bạn sử dụng các usethischức năng một lần khi bạn đang phát triển gói. Các chức năng đó sau đó thêm các phần cần thiết vào hướng dẫn xây dựng và mọi thứ khác.
Andrew Brēza

18

Giả sử rằng bạn đang sử dụng RStudio, devtoolsgói của Hadley và được liệt kê magrittrtrong phần Nhập của DESCRIPTIONtệp, đây là các bước tôi đã thực hiện để %>%hoạt động trong (các) chức năng gói của mình.

Đầu tiên, viết hàm 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()
}

Thứ hai, chạy devtools::document().

Thứ ba, chạy devtools::load_all().

Một tệp như thế này sẽ được tạo trong R/thư mục của bạn và chức năng của bạn sẽ hoạt động như mong đợi.


6
mục đích của @name %>%ở đây là gì?
JelenaČuklina
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.