Tidyeval在自己的函数内部以及管道自身的函数中

时间:2019-04-29 08:25:46

标签: r tidyverse devtools rlang tidyeval

因此,我正在尝试制作一个包装(以下未包含我的roxygen2标头):

我具有此功能:

date_from_text <- function(df, x){
  x <- rlang::enquo(x)
  name <- rlang::quo_name(x)

  df %>%
    dplyr::mutate(!!name := lubridate::ymd_hms(!!x))
}

当datetime列具有正确的类时,我将使用它来提取所有组件。

date_columns <- function(df, x){

  x <- rlang::enquo(x)

  df %>%
      dplyr::mutate(year=lubridate::year(!!x),
           ydag=lubridate::yday(!!x),
           weekday=lubridate::wday(!!x, label=FALSE),
           hour = lubridate::hour(!!x),
           hour_min= hms::as.hms(lubridate::force_tz(!!x)),
           week_num = lubridate::week(!!x),
           month = lubridate::month(!!x),
           date = lubridate::date(!!x))
}

我不打算将date_from_text函数包含在NAMESPACE中,而是希望以某种方式将其包含在date_columns函数中。比如检查时间戳是否具有正确的类,如果没有,则更改该类。然后创建所有日期时间组件。

我不知道如何在另一个函数中调用第一个函数。

测试数据:

df <- structure(list(time = c("2018-01-30 20:08:18", "2018-02-01 21:01:25", 
"2018-01-31 23:25:12", "2018-01-28 23:45:34", "2018-01-31 12:00:55", 
"2018-02-04 09:15:31", "2018-01-27 21:08:02", "2018-02-08 01:50:31", 
"2018-02-01 03:15:43", "2018-02-04 01:04:52"), type = c("A", 
"D", "B", "B", "B", "D", "C", "C", "C", "A")), .Names = c("time", 
"type"), row.names = c(NA, -10L), class = c("tbl_df", "tbl", 
"data.frame"))

更新:所以我现在将date_from_text包含在date_columns

date_columns <- function(df, x){
  x <- rlang::enquo(x)

  out <-  df %>%
    date_from_text(!!x) %>%
      dplyr::mutate(year=lubridate::year(!!x),
           ydag=lubridate::yday(!!x),
           weekday=lubridate::wday(!!x, label=FALSE),
           hour = lubridate::hour(!!x),
           hour_min= hms::as.hms(lubridate::force_tz(!!x)),
           week_num = lubridate::week(!!x),
           month = lubridate::month(!!x),
           date = lubridate::date(!!x))
 out

  }

所以我不明白为什么我必须在!!x内再次使用date_columns?它已经包含在date_from_text中。我正在调用该函数而不创建它...

1 个答案:

答案 0 :(得分:1)

正如在评论和聊天中得出的那样,问题既与包开发和名称空间无关,也与管道无关。问题是如何在可能嵌套的包装函数中使用https://github.com/electron/electron/issues/12895

答案是,用户传递给函数的表达式需要为,就像下面的date_from_text()通过enquo(x)!!x传递的那样。

date_from_text <- function(df, x) {
        x <- rlang::enquo(x)                                  # quote via enquo()
        name <- rlang::quo_name(x) 
        dplyr::mutate(df, !!name := lubridate::ymd_hms(!!x))  # unquote via !!
}

然后,可以像dplyr函数一样将表达式以“交互”模式传递给此类函数:

date_from_text(df, time)
select(df, time)

请记住,函数内部的功能不使用表达式,而是带引号和不带引号的表达式,就像在mutate()中用enquo(x)和{{1}进行调用一样}。

这意味着,在下面的!!x中,呼叫date_from_text()date_from_text()都需要接收mutate()

!!x

除此之外,在包开发中,您可以使用所有函数,无论它们是否为quoted and unquoted(就像我在date_columns <- function(df, x) { x <- rlang::enquo(x) out <- date_from_text(df, !!x) out <- dplyr::mutate(out, year = lubridate::year(!!x)) return(out) } 中对date_from_text()所做的那样)。导出的功能需要记录下来,并可以在安装后通过date_columns()library(pkg)使用,而未导出的功能只能在安装后通过pkg::fun()使用。

我修改了@David的功能,以专注于相关部分