扩展 tibble:让新的 S3 class 坚持下去

Extending tibble: getting the new S3 class to stick

对于ropensci/drake#489, I would like to define a new print method for tibbles of class "drake_plan". I read the guide on extending tibble,这对某些需求很有帮助。但是新的 "drake_plan" S3 class 在 dplyr 操作期间掉落。

#' @title Mark a data frame as a `drake` workflow plan
#' @description Used for pretty printing only (coming soon).
#'   You do not actually have to mark plans as such.
#'   You can keep them as ordinary data frames.
#' @export
#' @keywords internal
#' @param x object to mark as a `drake` plan
#' @param ... other arguments to the method
#' @examples
#' plan <- list(target = "x", command = "get_data()")
#' class(plan)
#' plan <- as_drake_plan(plan)
#' class(plan)
as_drake_plan <- function(x){
  UseMethod("as_drake_plan")
}

as_drake_plan_ <- function(x, ...){
  tibble::new_tibble(x, ..., subclass = "drake_plan")
}

#' @export
`[.drake_plan` <- function(...){
  as_drake_plan_(NextMethod())
}

#' @export
#' @rdname as_drake_plan
as_drake_plan.data.frame <- as_drake_plan_

#' @export
#' @rdname as_drake_plan
as_drake_plan.list <- as_drake_plan_

#' @export
#' @rdname as_drake_plan
as_drake_plan.tbl_df <- as_drake_plan_

library(dplyr)
library(drake)
plan <- drake_plan(
  x = get_data(),
  y = analyze_data(x)
) %>%
  as_drake_plan() %>%
  print
#> # A tibble: 2 x 2
#>   target command        
#> * <chr>  <chr>          
#> 1 x      get_data()     
#> 2 y      analyze_data(x)
class(plan)
#> [1] "drake_plan" "tbl_df"     "tbl"        "data.frame"
filter(plan, target == "x") %>%
  class()
#> [1] "tbl_df"     "tbl"        "data.frame"

除了dplyr函数之外,是否还有其他情况可以从tibbles中移除subclasses?

我刚刚发现这已经记录在 dplyr 开发页面上:https://github.com/tidyverse/dplyr/issues/2532。显然,没有计划尝试保留 tibble 个子类。

tibble 包现在有一个 new_tibble() 构造函数,@landau 也指出了这一点:

https://tibble.tidyverse.org/reference/new_tibble.html

# The nrow argument is always required:
new_tibble(list(a = 1:3, b = 4:6), nrow = 3)
#> # A tibble: 3 x 2
#>       a     b
#>   <int> <int>
#> 1     1     4
#> 2     2     5
#> 3     3     6