tibble/0000755000176200001440000000000013220301602011500 5ustar liggesuserstibble/inst/0000755000176200001440000000000013217741055012475 5ustar liggesuserstibble/inst/doc/0000755000176200001440000000000013217741055013242 5ustar liggesuserstibble/inst/doc/extending.R0000644000176200001440000001671613217741054015364 0ustar liggesusers## ---- eval = FALSE------------------------------------------------------- # usethis::use_package("pillar") ## ------------------------------------------------------------------------ #' @export latlon <- function(lat, lon) { as_latlon(complex(real = lon, imaginary = lat)) } #' @export as_latlon <- function(x) { structure(x, class = "latlon") } #' @export c.latlon <- function(x, ...) { as_latlon(NextMethod()) } #' @export `[.latlon` <- function(x, i) { as_latlon(NextMethod()) } #' @export format.latlon <- function(x, ..., formatter = deg_min) { x_valid <- which(!is.na(x)) lat <- unclass(Im(x[x_valid])) lon <- unclass(Re(x[x_valid])) ret <- rep("", length(x)) ret[x_valid] <- paste( formatter(lat, c("N", "S")), formatter(lon, c("E", "W")) ) format(ret, justify = "right") } deg_min <- function(x, pm) { sign <- sign(x) x <- abs(x) deg <- trunc(x) x <- x - deg min <- round(x * 60) ret <- sprintf("%d°%.2d'%s", deg, min, pm[ifelse(sign >= 0, 1, 2)]) format(ret, justify = "right") } #' @export print.latlon <- function(x, ...) { cat(format(x), sep = "\n") invisible(x) } latlon(32.7102978, -117.1704058) ## ------------------------------------------------------------------------ library(tibble) data <- tibble( venue = "rstudio::conf", year = 2017:2019, loc = latlon( c(28.3411783, 32.7102978, NA), c(-81.5480348, -117.1704058, NA) ), paths = list( loc[1], c(loc[1], loc[2]), loc[2] ) ) data ## ----include=FALSE------------------------------------------------------- import::from(pillar, type_sum) ## ------------------------------------------------------------------------ #' @importFrom pillar type_sum #' @export type_sum.latlon <- function(x) { "geo" } ## ------------------------------------------------------------------------ data ## ----include=FALSE------------------------------------------------------- import::from(pillar, pillar_shaft) ## ------------------------------------------------------------------------ #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "right") } ## ------------------------------------------------------------------------ data ## ------------------------------------------------------------------------ #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "left", na_indent = 5) } data ## ------------------------------------------------------------------------ print(data, width = 35) ## ------------------------------------------------------------------------ #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "right", min_width = 10) } print(data, width = 35) ## ------------------------------------------------------------------------ #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { deg <- format(x, formatter = deg) deg[is.na(x)] <- pillar::style_na("NA") deg_min <- format(x) deg_min[is.na(x)] <- pillar::style_na("NA") pillar::new_pillar_shaft( list(deg = deg, deg_min = deg_min), width = pillar::get_max_extent(deg_min), min_width = pillar::get_max_extent(deg), subclass = "pillar_shaft_latlon" ) } ## ------------------------------------------------------------------------ deg <- function(x, pm) { sign <- sign(x) x <- abs(x) deg <- round(x) ret <- sprintf("%d°%s", deg, pm[ifelse(sign >= 0, 1, 2)]) format(ret, justify = "right") } ## ------------------------------------------------------------------------ #' @export format.pillar_shaft_latlon <- function(x, width, ...) { if (all(crayon::col_nchar(x$deg_min) <= width)) { ornament <- x$deg_min } else { ornament <- x$deg } pillar::new_ornament(ornament) } data print(data, width = 35) ## ------------------------------------------------------------------------ #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x, formatter = deg_min_color) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "left", na_indent = 5) } deg_min_color <- function(x, pm) { sign <- sign(x) x <- abs(x) deg <- trunc(x) x <- x - deg rad <- round(x * 60) ret <- sprintf( "%d%s%.2d%s%s", deg, pillar::style_subtle("°"), rad, pillar::style_subtle("'"), pm[ifelse(sign >= 0, 1, 2)] ) ret[is.na(x)] <- "" format(ret, justify = "right") } data ## ----include=FALSE------------------------------------------------------- import::from(pillar, is_vector_s3) ## ------------------------------------------------------------------------ #' @importFrom pillar is_vector_s3 #' @export is_vector_s3.latlon <- function(x) TRUE data ## ------------------------------------------------------------------------ x <- as.POSIXlt(Sys.time() + c(0, 60, 3600)) str(unclass(x)) ## ------------------------------------------------------------------------ x length(x) str(x) ## ----include=FALSE------------------------------------------------------- import::from(pillar, obj_sum) ## ------------------------------------------------------------------------ #' @importFrom pillar obj_sum #' @export obj_sum.POSIXlt <- function(x) { rep("POSIXlt", length(x)) } ## ------------------------------------------------------------------------ library(testthat) ## ----include = FALSE----------------------------------------------------- unlink("latlon.txt") unlink("latlon-bw.txt") ## ----error = TRUE, warning = TRUE---------------------------------------- test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt" ) }) ## ------------------------------------------------------------------------ test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt" ) }) ## ------------------------------------------------------------------------ readLines("latlon.txt") ## ----error = TRUE, warning = TRUE---------------------------------------- library(testthat) test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt", crayon = FALSE ) }) ## ------------------------------------------------------------------------ test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt", crayon = FALSE ) }) readLines("latlon.txt") ## ------------------------------------------------------------------------ expect_known_latlon_display <- function(x, file_base) { quo <- rlang::quo(pillar::pillar_shaft(x)) pillar::expect_known_display( !! quo, file = paste0(file_base, ".txt") ) pillar::expect_known_display( !! quo, file = paste0(file_base, "-bw.txt"), crayon = FALSE ) } ## ----error = TRUE, warning = TRUE---------------------------------------- test_that("latlon pillar matches known output", { expect_known_latlon_display(data$loc, file_base = "latlon") }) ## ------------------------------------------------------------------------ readLines("latlon.txt") readLines("latlon-bw.txt") ## ----include = FALSE----------------------------------------------------- unlink("latlon.txt") unlink("latlon-bw.txt") tibble/inst/doc/tibble.Rmd0000644000176200001440000001042213204634213015137 0ustar liggesusers--- title: "Tibbles" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Tibbles} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r, echo = FALSE, message = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") options(tibble.print_min = 4L, tibble.print_max = 4L) library(tibble) set.seed(1014) ``` Tibbles are a modern take on data frames. They keep the features that have stood the test of time, and drop the features that used to be convenient but are now frustrating (i.e. converting character vectors to factors). ## Creating `tibble()` is a nice way to create data frames. It encapsulates best practices for data frames: * It never changes an input's type (i.e., no more `stringsAsFactors = FALSE`!). ```{r} tibble(x = letters) ``` This makes it easier to use with list-columns: ```{r} tibble(x = 1:3, y = list(1:5, 1:10, 1:20)) ``` List-columns are most commonly created by `do()`, but they can be useful to create by hand. * It never adjusts the names of variables: ```{r} names(data.frame(`crazy name` = 1)) names(tibble(`crazy name` = 1)) ``` * It evaluates its arguments lazily and sequentially: ```{r} tibble(x = 1:5, y = x ^ 2) ``` * It never uses `row.names()`. The whole point of tidy data is to store variables in a consistent way. So it never stores a variable as special attribute. * It only recycles vectors of length 1. This is because recycling vectors of greater lengths is a frequent source of bugs. ## Coercion To complement `tibble()`, tibble provides `as_tibble()` to coerce objects into tibbles. Generally, `as_tibble()` methods are much simpler than `as.data.frame()` methods, and in fact, it's precisely what `as.data.frame()` does, but it's similar to `do.call(cbind, lapply(x, data.frame))` - i.e. it coerces each component to a data frame and then `cbinds()` them all together. `as_tibble()` has been written with an eye for performance: ```{r} if (requireNamespace("microbenchmark", quiet = TRUE)) { l <- replicate(26, sample(100), simplify = FALSE) names(l) <- letters microbenchmark::microbenchmark( as_tibble(l), as.data.frame(l) ) } ``` The speed of `as.data.frame()` is not usually a bottleneck when used interactively, but can be a problem when combining thousands of messy inputs into one tidy data frame. ## Tibbles vs data frames There are three key differences between tibbles and data frames: printing, subsetting, and recycling rules. ### Printing When you print a tibble, it only shows the first ten rows and all the columns that fit on one screen. It also prints an abbreviated description of the column type: ```{r} tibble(x = 1:1000) ``` You can control the default appearance with options: * `options(tibble.print_max = n, tibble.print_min = m)`: if there are more than `n` rows, print only the first `m` rows. Use `options(tibble.print_max = Inf)` to always show all rows. * `options(tibble.width = Inf)` will always print all columns, regardless of the width of the screen. ### Subsetting Tibbles are quite strict about subsetting. `[` always returns another tibble. Contrast this with a data frame: sometimes `[` returns a data frame and sometimes it just returns a vector: ```{r} df1 <- data.frame(x = 1:3, y = 3:1) class(df1[, 1:2]) class(df1[, 1]) df2 <- tibble(x = 1:3, y = 3:1) class(df2[, 1:2]) class(df2[, 1]) ``` To extract a single column use `[[` or `$`: ```{r} class(df2[[1]]) class(df2$x) ``` Tibbles are also stricter with `$`. Tibbles never do partial matching, and will throw a warning and return `NULL` if the column does not exist: ```{r, error = TRUE} df <- data.frame(abc = 1) df$a df2 <- tibble(abc = 1) df2$a ``` tibbles also ignore the `drop` argument: ```{r} tibble(a = 1:3)[, "a", drop = TRUE] ``` ### Recycling When constructing a tibble, only values of length 1 are recycled. The first column with length different to one determines the number of rows in the tibble, conflicts lead to an error. This also extends to tibbles with *zero* rows, which is sometimes important for programming: ```{r, error = TRUE} tibble(a = 1, b = 1:3) tibble(a = 1:3, b = 1) tibble(a = 1:3, c = 1:2) tibble(a = 1, b = integer()) tibble(a = integer(), b = 1) ``` tibble/inst/doc/tibble.R0000644000176200001440000000346313217741055014634 0ustar liggesusers## ---- echo = FALSE, message = FALSE-------------------------------------- knitr::opts_chunk$set(collapse = TRUE, comment = "#>") options(tibble.print_min = 4L, tibble.print_max = 4L) library(tibble) set.seed(1014) ## ------------------------------------------------------------------------ tibble(x = letters) ## ------------------------------------------------------------------------ tibble(x = 1:3, y = list(1:5, 1:10, 1:20)) ## ------------------------------------------------------------------------ names(data.frame(`crazy name` = 1)) names(tibble(`crazy name` = 1)) ## ------------------------------------------------------------------------ tibble(x = 1:5, y = x ^ 2) ## ------------------------------------------------------------------------ if (requireNamespace("microbenchmark", quiet = TRUE)) { l <- replicate(26, sample(100), simplify = FALSE) names(l) <- letters microbenchmark::microbenchmark( as_tibble(l), as.data.frame(l) ) } ## ------------------------------------------------------------------------ tibble(x = 1:1000) ## ------------------------------------------------------------------------ df1 <- data.frame(x = 1:3, y = 3:1) class(df1[, 1:2]) class(df1[, 1]) df2 <- tibble(x = 1:3, y = 3:1) class(df2[, 1:2]) class(df2[, 1]) ## ------------------------------------------------------------------------ class(df2[[1]]) class(df2$x) ## ---- error = TRUE------------------------------------------------------- df <- data.frame(abc = 1) df$a df2 <- tibble(abc = 1) df2$a ## ------------------------------------------------------------------------ tibble(a = 1:3)[, "a", drop = TRUE] ## ---- error = TRUE------------------------------------------------------- tibble(a = 1, b = 1:3) tibble(a = 1:3, b = 1) tibble(a = 1:3, c = 1:2) tibble(a = 1, b = integer()) tibble(a = integer(), b = 1) tibble/inst/doc/extending.html0000644000176200001440000012241113217741054016115 0ustar liggesusers Extending tibble

Extending tibble

Kirill Müller, Hadley Wickham

2017-12-24

To extend the tibble package for new types of columnar data, you need to understand how printing works. The presentation of a column in a tibble is powered by four S3 generics:

If you have written an S3 or S4 class that can be used as a column, you can override these generics to make sure your data prints well in a tibble. To start, you must import the pillar package that powers the printing of tibbles. Either add pillar to the Imports: section of your DESCRIPTION, or simply call:

usethis::use_package("pillar")

This short vignette assumes a package that implements an S3 class "latlon" and uses roxygen2 to create documentation and the NAMESPACE file. For this vignette to work we need to attach pillar:

Prerequisites

We define a class "latlon" that encodes geographic coordinates in a complex number. For simplicity, the values are printed as degrees and minutes only.

#' @export
latlon <- function(lat, lon) {
  as_latlon(complex(real = lon, imaginary = lat))
}

#' @export
as_latlon <- function(x) {
  structure(x, class = "latlon")
}

#' @export
c.latlon <- function(x, ...) {
  as_latlon(NextMethod())
}

#' @export
`[.latlon` <- function(x, i) {
  as_latlon(NextMethod())
}

#' @export
format.latlon <- function(x, ..., formatter = deg_min) {
  x_valid <- which(!is.na(x))

  lat <- unclass(Im(x[x_valid]))
  lon <- unclass(Re(x[x_valid]))

  ret <- rep("<NA>", length(x))
  ret[x_valid] <- paste(
    formatter(lat, c("N", "S")),
    formatter(lon, c("E", "W"))
  )
  format(ret, justify = "right")
}

deg_min <- function(x, pm) {
  sign <- sign(x)
  x <- abs(x)
  deg <- trunc(x)
  x <- x - deg
  min <- round(x * 60)

  ret <- sprintf("%d°%.2d'%s", deg, min, pm[ifelse(sign >= 0, 1, 2)])
  format(ret, justify = "right")
}

#' @export
print.latlon <- function(x, ...) {
  cat(format(x), sep = "\n")
  invisible(x)
}

latlon(32.7102978, -117.1704058)
## 32°43'N 117°10'W

More methods are needed to make this class fully compatible with data frames, see e.g. the hms package for a more complete example.

Using in a tibble

Columns on this class can be used in a tibble right away, but the output will be less than ideal:

library(tibble)
data <- tibble(
  venue = "rstudio::conf",
  year  = 2017:2019,
  loc   = latlon(
    c(28.3411783, 32.7102978, NA),
    c(-81.5480348, -117.1704058, NA)
  ),
  paths = list(
    loc[1],
    c(loc[1], loc[2]),
    loc[2]
  )
)

data
## # A tibble: 3 x 4
##   venue          year loc                      paths       
##   <chr>         <int> <S3: latlon>             <list>      
## 1 rstudio::conf  2017 -81.5480348+28.3411783i  <S3: latlon>
## 2 rstudio::conf  2018 -117.1704058+32.7102978i <S3: latlon>
## 3 rstudio::conf  2019 <NA>                     <S3: latlon>

(The paths column is a list that contains arbitrary data, in our case latlon vectors. A list column is a powerful way to attach hierarchical or unstructured data to an observation in a data frame.)

The output has three main problems:

  1. The column type of the loc column is displayed as <S3: latlon>. This default formatting works reasonably well for any kind of object, but the generated output may be too wide and waste precious space when displaying the tibble.
  2. The values in the loc column are formatted as complex numbers (the underlying storage), without using the format() method we have defined. This is by design.
  3. The cells in the paths column are also displayed as <S3: latlon>.

In the remainder I’ll show how to fix these problems, and also how to implement rendering that adapts to the available width.

Fixing the data type

To display <geo> as data type, we need to override the type_sum() method. This method should return a string that can be used in a column header. For your own classes, strive for an evocative abbreviation that’s under 6 characters.

#' @importFrom pillar type_sum
#' @export
type_sum.latlon <- function(x) {
  "geo"
}

Because the value shown there doesn’t depend on the data, we just return a constant. (For date-times, the column info will eventually contain information about the timezone, see #53.)

data
## # A tibble: 3 x 4
##   venue          year loc                      paths 
##   <chr>         <int> <geo>                    <list>
## 1 rstudio::conf  2017 -81.5480348+28.3411783i  <geo> 
## 2 rstudio::conf  2018 -117.1704058+32.7102978i <geo> 
## 3 rstudio::conf  2019 <NA>                     <geo>

Rendering the value

To use our format method for rendering, we implement the pillar_shaft() method for our class. (A pillar is mainly a shaft (decorated with an ornament), with a capital above and a base below. Multiple pillars form a colonnade, which can be stacked in multiple tiers. This is the motivation behind the names in our API.)

#' @importFrom pillar pillar_shaft
#' @export
pillar_shaft.latlon <- function(x, ...) {
  out <- format(x)
  out[is.na(x)] <- NA
  pillar::new_pillar_shaft_simple(out, align = "right")
}

The simplest variant calls our format() method, everything else is handled by pillar, in particular by the new_pillar_shaft_simple() helper. Note how the align argument affects the alignment of NA values and of the column name and type.

data
## # A tibble: 3 x 4
##   venue          year              loc paths 
##   <chr>         <int>            <geo> <list>
## 1 rstudio::conf  2017 28°20'N  81°33'W <geo> 
## 2 rstudio::conf  2018 32°43'N 117°10'W <geo> 
## 3 rstudio::conf  2019               NA <geo>

We could also use left alignment and indent only the NA values:

#' @importFrom pillar pillar_shaft
#' @export
pillar_shaft.latlon <- function(x, ...) {
  out <- format(x)
  out[is.na(x)] <- NA
  pillar::new_pillar_shaft_simple(out, align = "left", na_indent = 5)
}

data
## # A tibble: 3 x 4
##   venue          year loc              paths 
##   <chr>         <int> <geo>            <list>
## 1 rstudio::conf  2017 28°20'N  81°33'W <geo> 
## 2 rstudio::conf  2018 32°43'N 117°10'W <geo> 
## 3 rstudio::conf  2019      NA          <geo>

Adaptive rendering

If there is not enough space to render the values, the formatted values are truncated with an ellipsis. This doesn’t currently apply to our class, because we haven’t specified a minimum width for our values:

print(data, width = 35)
## # A tibble: 3 x 4
##   venue      year loc             
##   <chr>     <int> <geo>           
## 1 rstudio:…  2017 28°20'N  81°33'W
## 2 rstudio:…  2018 32°43'N 117°10'W
## 3 rstudio:…  2019      NA         
## # ... with 1 more variable:
## #   paths <list>

If we specify a minimum width when constructing the shaft, the loc column will be truncated:

#' @importFrom pillar pillar_shaft
#' @export
pillar_shaft.latlon <- function(x, ...) {
  out <- format(x)
  out[is.na(x)] <- NA
  pillar::new_pillar_shaft_simple(out, align = "right", min_width = 10)
}

print(data, width = 35)
## # A tibble: 3 x 4
##   venue     year         loc paths
##   <chr>    <int>       <geo> <lis>
## 1 rstudio…  2017 28°20'N  8… <geo>
## 2 rstudio…  2018 32°43'N 11… <geo>
## 3 rstudio…  2019          NA <geo>

This may be useful for character data, but for lat-lon data we may prefer to show full degrees and remove the minutes if the available space is not enough to show accurate values. A more sophisticated implementation of the pillar_shaft() method is required to achieve this:

#' @importFrom pillar pillar_shaft
#' @export
pillar_shaft.latlon <- function(x, ...) {
  deg <- format(x, formatter = deg)
  deg[is.na(x)] <- pillar::style_na("NA")
  deg_min <- format(x)
  deg_min[is.na(x)] <- pillar::style_na("NA")
  pillar::new_pillar_shaft(
    list(deg = deg, deg_min = deg_min),
    width = pillar::get_max_extent(deg_min),
    min_width = pillar::get_max_extent(deg),
    subclass = "pillar_shaft_latlon"
  )
}

Here, pillar_shaft() returns an object of the "pillar_shaft_latlon" class created by the generic new_pillar_shaft() constructor. This object contains the necessary information to render the values, and also minimum and maximum width values. For simplicity, both formattings are pre-rendered, and the minimum and maximum widths are computed from there. Note that we also need to take care of NA values explicitly. (get_max_extent() is a helper that computes the maximum display width occupied by the values in a character vector.)

For completeness, the code that implements the degree-only formatting looks like this:

deg <- function(x, pm) {
  sign <- sign(x)
  x <- abs(x)
  deg <- round(x)

  ret <- sprintf("%d°%s", deg, pm[ifelse(sign >= 0, 1, 2)])
  format(ret, justify = "right")
}

All that’s left to do is to implement a format() method for our new "pillar_shaft_latlon" class. This method will be called with a width argument, which then determines which of the formattings to choose:

#' @export
format.pillar_shaft_latlon <- function(x, width, ...) {
  if (all(crayon::col_nchar(x$deg_min) <= width)) {
    ornament <- x$deg_min
  } else {
    ornament <- x$deg
  }

  pillar::new_ornament(ornament)
}

data
## # A tibble: 3 x 4
##   venue          year loc              paths 
##   <chr>         <int> <geo>            <list>
## 1 rstudio::conf  2017 28°20'N  81°33'W <geo> 
## 2 rstudio::conf  2018 32°43'N 117°10'W <geo> 
## 3 rstudio::conf  2019 NA               <geo>
print(data, width = 35)
## # A tibble: 3 x 4
##   venue     year loc         paths
##   <chr>    <int> <geo>       <lis>
## 1 rstudio…  2017 28°N  82°W  <geo>
## 2 rstudio…  2018 33°N 117°W  <geo>
## 3 rstudio…  2019 NA          <geo>

Adding color

Both new_pillar_shaft_simple() and new_ornament() accept ANSI escape codes for coloring, emphasis, or other ways of highlighting text on terminals that support it. Some formattings are predefined, e.g. style_subtle() displays text in a light gray. For default data types, this style is used for insignificant digits. We’ll be formatting the degree and minute signs in a subtle style, because they serve only as separators. You can also use the crayon package to add custom formattings to your output.

#' @importFrom pillar pillar_shaft
#' @export
pillar_shaft.latlon <- function(x, ...) {
  out <- format(x, formatter = deg_min_color)
  out[is.na(x)] <- NA
  pillar::new_pillar_shaft_simple(out, align = "left", na_indent = 5)
}

deg_min_color <- function(x, pm) {
  sign <- sign(x)
  x <- abs(x)
  deg <- trunc(x)
  x <- x - deg
  rad <- round(x * 60)
  ret <- sprintf(
    "%d%s%.2d%s%s",
    deg,
    pillar::style_subtle("°"),
    rad,
    pillar::style_subtle("'"),
    pm[ifelse(sign >= 0, 1, 2)]
  )
  ret[is.na(x)] <- ""
  format(ret, justify = "right")
}

data
## # A tibble: 3 x 4
##   venue          year loc              paths 
##   <chr>         <int> <geo>            <list>
## 1 rstudio::conf  2017 28°20'N  81°33'W <geo> 
## 2 rstudio::conf  2018 32°43'N 117°10'W <geo> 
## 3 rstudio::conf  2019      NA          <geo>

Currently, ANSI escapes are not rendered in vignettes, so the display here isn’t much different from earlier examples. This may change in the future.

Fixing list columns

To tweak the output in the paths column, we simply need to indicate that our class is an S3 vector:

#' @importFrom pillar is_vector_s3
#' @export
is_vector_s3.latlon <- function(x) TRUE

data
## # A tibble: 3 x 4
##   venue          year loc              paths    
##   <chr>         <int> <geo>            <list>   
## 1 rstudio::conf  2017 28°20'N  81°33'W <geo [1]>
## 2 rstudio::conf  2018 32°43'N 117°10'W <geo [2]>
## 3 rstudio::conf  2019      NA          <geo [1]>

This is picked up by the default implementation of obj_sum(), which then shows the type and the length in brackets. If your object is built on top of an atomic vector the default will be adequate. You, will, however, need to provide an obj_sum() method for your class if your object is vectorised and built on top of a list.

An example of an object of this type in base R is POSIXlt: it is a list with 9 components.

x <- as.POSIXlt(Sys.time() + c(0, 60, 3600)) 
str(unclass(x))
## List of 11
##  $ sec   : num [1:3] 16.3 16.3 16.3
##  $ min   : int [1:3] 5 6 5
##  $ hour  : int [1:3] 16 16 17
##  $ mday  : int [1:3] 24 24 24
##  $ mon   : int [1:3] 11 11 11
##  $ year  : int [1:3] 117 117 117
##  $ wday  : int [1:3] 0 0 0
##  $ yday  : int [1:3] 357 357 357
##  $ isdst : int [1:3] 0 0 0
##  $ zone  : chr [1:3] "CET" "CET" "CET"
##  $ gmtoff: int [1:3] 3600 3600 3600
##  - attr(*, "tzone")= chr [1:3] "" "CET" "CEST"

But it pretends to be a vector with 3 elements:

x
## [1] "2017-12-24 16:05:16 CET" "2017-12-24 16:06:16 CET"
## [3] "2017-12-24 17:05:16 CET"
length(x)
## [1] 3
str(x)
##  POSIXlt[1:3], format: "2017-12-24 16:05:16" "2017-12-24 16:06:16" ...

So we need to define a method that returns a character vector the same length as x:

#' @importFrom pillar obj_sum
#' @export
obj_sum.POSIXlt <- function(x) {
  rep("POSIXlt", length(x))
}

Testing

If you want to test the output of your code, you can compare it with a known state recorded in a text file. For this, pillar offers the expect_known_display() expectation which requires and works best with the testthat package. Make sure that the output is generated only by your package to avoid inconsistencies when external code is updated. Here, this means that you test only the shaft portion of the pillar, and not the entire pillar or even a tibble that contains a column with your data type!

The tests work best with the testthat package:

library(testthat)

The code below will compare the output of pillar_shaft(data$loc) with known output stored in the latlon.txt file. The first run warns because the file doesn’t exist yet.

test_that("latlon pillar matches known output", {
  pillar::expect_known_display(
    pillar_shaft(data$loc),
    file = "latlon.txt"
  )
})

From the second run on, the printing will be compared with the file:

test_that("latlon pillar matches known output", {
  pillar::expect_known_display(
    pillar_shaft(data$loc),
    file = "latlon.txt"
  )
})

However, if we look at the file we’ll notice strange things: The output contains ANSI escapes!

readLines("latlon.txt")
## [1] "28\033[90m°\033[39m20\033[90m'\033[39mN  81\033[90m°\033[39m33\033[90m'\033[39mW"
## [2] "32\033[90m°\033[39m43\033[90m'\033[39mN 117\033[90m°\033[39m10\033[90m'\033[39mW"
## [3] "     \033[43m\033[30mNA\033[39m\033[49m         "

We can turn them off by passing crayon = FALSE to the expectation, but we need to run twice again:

library(testthat)
test_that("latlon pillar matches known output", {
  pillar::expect_known_display(
    pillar_shaft(data$loc),
    file = "latlon.txt",
    crayon = FALSE
  )
})
## Error: Test failed: 'latlon pillar matches known output'
## * `print(eval_tidy(object))` has changed from known value recorded in 'latlon.txt'.
## 3/3 mismatches
## x[1]: "28°20'N  81°33'W"
## y[1]: "28\033[90m°\033[39m20\033[90m'\033[39mN  81\033[90m°\033[39m33\033[90m'\033[39mW"
## 
## x[2]: "32°43'N 117°10'W"
## y[2]: "32\033[90m°\033[39m43\033[90m'\033[39mN 117\033[90m°\033[39m10\033[90m'\033[39mW"
## 
## x[3]: "     NA         "
## y[3]: "     \033[43m\033[30mNA\033[39m\033[49m         "
test_that("latlon pillar matches known output", {
  pillar::expect_known_display(
    pillar_shaft(data$loc),
    file = "latlon.txt",
    crayon = FALSE
  )
})

readLines("latlon.txt")
## [1] "28°20'N  81°33'W" "32°43'N 117°10'W" "     NA         "

You may want to create a series of output files for different scenarios:

For this it is helpful to create your own expectation function. Use the tidy evaluation framework to make sure that construction and printing happens at the right time:

expect_known_latlon_display <- function(x, file_base) {
  quo <- rlang::quo(pillar::pillar_shaft(x))
  pillar::expect_known_display(
    !! quo,
    file = paste0(file_base, ".txt")
  )
  pillar::expect_known_display(
    !! quo,
    file = paste0(file_base, "-bw.txt"),
    crayon = FALSE
  )
}
test_that("latlon pillar matches known output", {
  expect_known_latlon_display(data$loc, file_base = "latlon")
})
## Error: Test failed: 'latlon pillar matches known output'
## * `print(eval_tidy(object))` has changed from known value recorded in 'latlon.txt'.
## 3/3 mismatches
## x[1]: "28\033[90m°\033[39m20\033[90m'\033[39mN  81\033[90m°\033[39m33\033[90m'\033[39mW"
## y[1]: "28°20'N  81°33'W"
## 
## x[2]: "32\033[90m°\033[39m43\033[90m'\033[39mN 117\033[90m°\033[39m10\033[90m'\033[39mW"
## y[2]: "32°43'N 117°10'W"
## 
## x[3]: "     \033[43m\033[30mNA\033[39m\033[49m         "
## y[3]: "     NA         "
readLines("latlon.txt")
## [1] "28\033[90m°\033[39m20\033[90m'\033[39mN  81\033[90m°\033[39m33\033[90m'\033[39mW"
## [2] "32\033[90m°\033[39m43\033[90m'\033[39mN 117\033[90m°\033[39m10\033[90m'\033[39mW"
## [3] "     \033[43m\033[30mNA\033[39m\033[49m         "
readLines("latlon-bw.txt")
## [1] "28°20'N  81°33'W" "32°43'N 117°10'W" "     NA         "

Learn more about the tidyeval framework in the dplyr vignette.

tibble/inst/doc/extending.Rmd0000644000176200001440000003263213217670436015705 0ustar liggesusers--- title: "Extending tibble" author: "Kirill Müller, Hadley Wickham" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Extending tibble} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- To extend the tibble package for new types of columnar data, you need to understand how printing works. The presentation of a column in a tibble is powered by four S3 generics: * `type_sum()` determines what goes into the column header. * `pillar_shaft()` determines what goes into the body of the column. * `is_vector_s3()` and `obj_sum()` are used when rendering list columns. If you have written an S3 or S4 class that can be used as a column, you can override these generics to make sure your data prints well in a tibble. To start, you must import the `pillar` package that powers the printing of tibbles. Either add `pillar` to the `Imports:` section of your `DESCRIPTION`, or simply call: ```{r, eval = FALSE} usethis::use_package("pillar") ``` This short vignette assumes a package that implements an S3 class `"latlon"` and uses `roxygen2` to create documentation and the `NAMESPACE` file. For this vignette to work we need to attach pillar: ## Prerequisites We define a class `"latlon"` that encodes geographic coordinates in a complex number. For simplicity, the values are printed as degrees and minutes only. ```{r} #' @export latlon <- function(lat, lon) { as_latlon(complex(real = lon, imaginary = lat)) } #' @export as_latlon <- function(x) { structure(x, class = "latlon") } #' @export c.latlon <- function(x, ...) { as_latlon(NextMethod()) } #' @export `[.latlon` <- function(x, i) { as_latlon(NextMethod()) } #' @export format.latlon <- function(x, ..., formatter = deg_min) { x_valid <- which(!is.na(x)) lat <- unclass(Im(x[x_valid])) lon <- unclass(Re(x[x_valid])) ret <- rep("", length(x)) ret[x_valid] <- paste( formatter(lat, c("N", "S")), formatter(lon, c("E", "W")) ) format(ret, justify = "right") } deg_min <- function(x, pm) { sign <- sign(x) x <- abs(x) deg <- trunc(x) x <- x - deg min <- round(x * 60) ret <- sprintf("%d°%.2d'%s", deg, min, pm[ifelse(sign >= 0, 1, 2)]) format(ret, justify = "right") } #' @export print.latlon <- function(x, ...) { cat(format(x), sep = "\n") invisible(x) } latlon(32.7102978, -117.1704058) ``` More methods are needed to make this class fully compatible with data frames, see e.g. the [hms](https://github.com/tidyverse/hms/) package for a more complete example. ## Using in a tibble Columns on this class can be used in a tibble right away, but the output will be less than ideal: ```{r} library(tibble) data <- tibble( venue = "rstudio::conf", year = 2017:2019, loc = latlon( c(28.3411783, 32.7102978, NA), c(-81.5480348, -117.1704058, NA) ), paths = list( loc[1], c(loc[1], loc[2]), loc[2] ) ) data ``` (The `paths` column is a list that contains arbitrary data, in our case `latlon` vectors. A list column is a powerful way to attach hierarchical or unstructured data to an observation in a data frame.) The output has three main problems: 1. The column type of the `loc` column is displayed as ``. This default formatting works reasonably well for any kind of object, but the generated output may be too wide and waste precious space when displaying the tibble. 1. The values in the `loc` column are formatted as complex numbers (the underlying storage), without using the `format()` method we have defined. This is by design. 1. The cells in the `paths` column are also displayed as ``. In the remainder I'll show how to fix these problems, and also how to implement rendering that adapts to the available width. ## Fixing the data type To display `` as data type, we need to override the `type_sum()` method. This method should return a string that can be used in a column header. For your own classes, strive for an evocative abbreviation that's under 6 characters. ```{r include=FALSE} import::from(pillar, type_sum) ``` ```{r} #' @importFrom pillar type_sum #' @export type_sum.latlon <- function(x) { "geo" } ``` Because the value shown there doesn't depend on the data, we just return a constant. (For date-times, the column info will eventually contain information about the timezone, see [#53](https://github.com/r-lib/pillar/pull/53).) ```{r} data ``` ## Rendering the value To use our format method for rendering, we implement the `pillar_shaft()` method for our class. (A [*pillar*](https://en.wikipedia.org/wiki/Column#Nomenclature) is mainly a *shaft* (decorated with an *ornament*), with a *capital* above and a *base* below. Multiple pillars form a *colonnade*, which can be stacked in multiple *tiers*. This is the motivation behind the names in our API.) ```{r include=FALSE} import::from(pillar, pillar_shaft) ``` ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "right") } ``` The simplest variant calls our `format()` method, everything else is handled by pillar, in particular by the `new_pillar_shaft_simple()` helper. Note how the `align` argument affects the alignment of NA values and of the column name and type. ```{r} data ``` We could also use left alignment and indent only the `NA` values: ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "left", na_indent = 5) } data ``` ## Adaptive rendering If there is not enough space to render the values, the formatted values are truncated with an ellipsis. This doesn't currently apply to our class, because we haven't specified a minimum width for our values: ```{r} print(data, width = 35) ``` If we specify a minimum width when constructing the shaft, the `loc` column will be truncated: ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "right", min_width = 10) } print(data, width = 35) ``` This may be useful for character data, but for lat-lon data we may prefer to show full degrees and remove the minutes if the available space is not enough to show accurate values. A more sophisticated implementation of the `pillar_shaft()` method is required to achieve this: ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { deg <- format(x, formatter = deg) deg[is.na(x)] <- pillar::style_na("NA") deg_min <- format(x) deg_min[is.na(x)] <- pillar::style_na("NA") pillar::new_pillar_shaft( list(deg = deg, deg_min = deg_min), width = pillar::get_max_extent(deg_min), min_width = pillar::get_max_extent(deg), subclass = "pillar_shaft_latlon" ) } ``` Here, `pillar_shaft()` returns an object of the `"pillar_shaft_latlon"` class created by the generic `new_pillar_shaft()` constructor. This object contains the necessary information to render the values, and also minimum and maximum width values. For simplicity, both formattings are pre-rendered, and the minimum and maximum widths are computed from there. Note that we also need to take care of `NA` values explicitly. (`get_max_extent()` is a helper that computes the maximum display width occupied by the values in a character vector.) For completeness, the code that implements the degree-only formatting looks like this: ```{r} deg <- function(x, pm) { sign <- sign(x) x <- abs(x) deg <- round(x) ret <- sprintf("%d°%s", deg, pm[ifelse(sign >= 0, 1, 2)]) format(ret, justify = "right") } ``` All that's left to do is to implement a `format()` method for our new `"pillar_shaft_latlon"` class. This method will be called with a `width` argument, which then determines which of the formattings to choose: ```{r} #' @export format.pillar_shaft_latlon <- function(x, width, ...) { if (all(crayon::col_nchar(x$deg_min) <= width)) { ornament <- x$deg_min } else { ornament <- x$deg } pillar::new_ornament(ornament) } data print(data, width = 35) ``` ## Adding color Both `new_pillar_shaft_simple()` and `new_ornament()` accept ANSI escape codes for coloring, emphasis, or other ways of highlighting text on terminals that support it. Some formattings are predefined, e.g. `style_subtle()` displays text in a light gray. For default data types, this style is used for insignificant digits. We'll be formatting the degree and minute signs in a subtle style, because they serve only as separators. You can also use the [crayon](https://cran.r-project.org/package=crayon) package to add custom formattings to your output. ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x, formatter = deg_min_color) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "left", na_indent = 5) } deg_min_color <- function(x, pm) { sign <- sign(x) x <- abs(x) deg <- trunc(x) x <- x - deg rad <- round(x * 60) ret <- sprintf( "%d%s%.2d%s%s", deg, pillar::style_subtle("°"), rad, pillar::style_subtle("'"), pm[ifelse(sign >= 0, 1, 2)] ) ret[is.na(x)] <- "" format(ret, justify = "right") } data ``` Currently, ANSI escapes are not rendered in vignettes, so the display here isn't much different from earlier examples. This may change in the future. ## Fixing list columns To tweak the output in the `paths` column, we simply need to indicate that our class is an S3 vector: ```{r include=FALSE} import::from(pillar, is_vector_s3) ``` ```{r} #' @importFrom pillar is_vector_s3 #' @export is_vector_s3.latlon <- function(x) TRUE data ``` This is picked up by the default implementation of `obj_sum()`, which then shows the type and the length in brackets. If your object is built on top of an atomic vector the default will be adequate. You, will, however, need to provide an `obj_sum()` method for your class if your object is vectorised and built on top of a list. An example of an object of this type in base R is `POSIXlt`: it is a list with 9 components. ```{r} x <- as.POSIXlt(Sys.time() + c(0, 60, 3600)) str(unclass(x)) ``` But it pretends to be a vector with 3 elements: ```{r} x length(x) str(x) ``` So we need to define a method that returns a character vector the same length as `x`: ```{r include=FALSE} import::from(pillar, obj_sum) ``` ```{r} #' @importFrom pillar obj_sum #' @export obj_sum.POSIXlt <- function(x) { rep("POSIXlt", length(x)) } ``` ## Testing If you want to test the output of your code, you can compare it with a known state recorded in a text file. For this, pillar offers the `expect_known_display()` expectation which requires and works best with the testthat package. Make sure that the output is generated only by your package to avoid inconsistencies when external code is updated. Here, this means that you test only the shaft portion of the pillar, and not the entire pillar or even a tibble that contains a column with your data type! The tests work best with the testthat package: ```{r} library(testthat) ``` ```{r include = FALSE} unlink("latlon.txt") unlink("latlon-bw.txt") ``` The code below will compare the output of `pillar_shaft(data$loc)` with known output stored in the `latlon.txt` file. The first run warns because the file doesn't exist yet. ```{r error = TRUE, warning = TRUE} test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt" ) }) ``` From the second run on, the printing will be compared with the file: ```{r} test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt" ) }) ``` However, if we look at the file we'll notice strange things: The output contains ANSI escapes! ```{r} readLines("latlon.txt") ``` We can turn them off by passing `crayon = FALSE` to the expectation, but we need to run twice again: ```{r error = TRUE, warning = TRUE} library(testthat) test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt", crayon = FALSE ) }) ``` ```{r} test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt", crayon = FALSE ) }) readLines("latlon.txt") ``` You may want to create a series of output files for different scenarios: - Colored vs. plain (to simplify viewing differences) - With or without special Unicode characters (if your output uses them) - Different widths For this it is helpful to create your own expectation function. Use the tidy evaluation framework to make sure that construction and printing happens at the right time: ```{r} expect_known_latlon_display <- function(x, file_base) { quo <- rlang::quo(pillar::pillar_shaft(x)) pillar::expect_known_display( !! quo, file = paste0(file_base, ".txt") ) pillar::expect_known_display( !! quo, file = paste0(file_base, "-bw.txt"), crayon = FALSE ) } ``` ```{r error = TRUE, warning = TRUE} test_that("latlon pillar matches known output", { expect_known_latlon_display(data$loc, file_base = "latlon") }) ``` ```{r} readLines("latlon.txt") readLines("latlon-bw.txt") ``` Learn more about the tidyeval framework in the [dplyr vignette](http://dplyr.tidyverse.org/articles/programming.html). ```{r include = FALSE} unlink("latlon.txt") unlink("latlon-bw.txt") ``` tibble/inst/doc/tibble.html0000644000176200001440000004777613217741055015416 0ustar liggesusers Tibbles

Tibbles

Tibbles are a modern take on data frames. They keep the features that have stood the test of time, and drop the features that used to be convenient but are now frustrating (i.e. converting character vectors to factors).

Creating

tibble() is a nice way to create data frames. It encapsulates best practices for data frames:

  • It never changes an input’s type (i.e., no more stringsAsFactors = FALSE!).

    tibble(x = letters)
    #> # A tibble: 26 x 1
    #>   x    
    #>   <chr>
    #> 1 a    
    #> 2 b    
    #> 3 c    
    #> 4 d    
    #> # ... with 22 more rows

    This makes it easier to use with list-columns:

    tibble(x = 1:3, y = list(1:5, 1:10, 1:20))
    #> # A tibble: 3 x 2
    #>       x y         
    #>   <int> <list>    
    #> 1     1 <int [5]> 
    #> 2     2 <int [10]>
    #> 3     3 <int [20]>

    List-columns are most commonly created by do(), but they can be useful to create by hand.

  • It never adjusts the names of variables:

    names(data.frame(`crazy name` = 1))
    #> [1] "crazy.name"
    names(tibble(`crazy name` = 1))
    #> [1] "crazy name"
  • It evaluates its arguments lazily and sequentially:

    tibble(x = 1:5, y = x ^ 2)
    #> # A tibble: 5 x 2
    #>       x     y
    #>   <int> <dbl>
    #> 1     1  1.00
    #> 2     2  4.00
    #> 3     3  9.00
    #> 4     4 16.0 
    #> # ... with 1 more row
  • It never uses row.names(). The whole point of tidy data is to store variables in a consistent way. So it never stores a variable as special attribute.

  • It only recycles vectors of length 1. This is because recycling vectors of greater lengths is a frequent source of bugs.

Coercion

To complement tibble(), tibble provides as_tibble() to coerce objects into tibbles. Generally, as_tibble() methods are much simpler than as.data.frame() methods, and in fact, it’s precisely what as.data.frame() does, but it’s similar to do.call(cbind, lapply(x, data.frame)) - i.e. it coerces each component to a data frame and then cbinds() them all together.

as_tibble() has been written with an eye for performance:

if (requireNamespace("microbenchmark", quiet = TRUE)) {
  l <- replicate(26, sample(100), simplify = FALSE)
  names(l) <- letters

  microbenchmark::microbenchmark(
    as_tibble(l),
    as.data.frame(l)
  )
}
#> Loading required namespace: microbenchmark

The speed of as.data.frame() is not usually a bottleneck when used interactively, but can be a problem when combining thousands of messy inputs into one tidy data frame.

Tibbles vs data frames

There are three key differences between tibbles and data frames: printing, subsetting, and recycling rules.

Printing

When you print a tibble, it only shows the first ten rows and all the columns that fit on one screen. It also prints an abbreviated description of the column type:

tibble(x = 1:1000)
#> # A tibble: 1,000 x 1
#>       x
#>   <int>
#> 1     1
#> 2     2
#> 3     3
#> 4     4
#> # ... with 996 more rows

You can control the default appearance with options:

  • options(tibble.print_max = n, tibble.print_min = m): if there are more than n rows, print only the first m rows. Use options(tibble.print_max = Inf) to always show all rows.

  • options(tibble.width = Inf) will always print all columns, regardless of the width of the screen.

Subsetting

Tibbles are quite strict about subsetting. [ always returns another tibble. Contrast this with a data frame: sometimes [ returns a data frame and sometimes it just returns a vector:

df1 <- data.frame(x = 1:3, y = 3:1)
class(df1[, 1:2])
#> [1] "data.frame"
class(df1[, 1])
#> [1] "integer"

df2 <- tibble(x = 1:3, y = 3:1)
class(df2[, 1:2])
#> [1] "tbl_df"     "tbl"        "data.frame"
class(df2[, 1])
#> [1] "tbl_df"     "tbl"        "data.frame"

To extract a single column use [[ or $:

class(df2[[1]])
#> [1] "integer"
class(df2$x)
#> [1] "integer"

Tibbles are also stricter with $. Tibbles never do partial matching, and will throw a warning and return NULL if the column does not exist:

df <- data.frame(abc = 1)
df$a
#> [1] 1

df2 <- tibble(abc = 1)
df2$a
#> Warning: Unknown or uninitialised column: 'a'.
#> NULL

tibbles also ignore the drop argument:

tibble(a = 1:3)[, "a", drop = TRUE]
#> [1] 1 2 3

Recycling

When constructing a tibble, only values of length 1 are recycled. The first column with length different to one determines the number of rows in the tibble, conflicts lead to an error. This also extends to tibbles with zero rows, which is sometimes important for programming:

tibble(a = 1, b = 1:3)
#> # A tibble: 3 x 2
#>       a     b
#>   <dbl> <int>
#> 1  1.00     1
#> 2  1.00     2
#> 3  1.00     3
tibble(a = 1:3, b = 1)
#> # A tibble: 3 x 2
#>       a     b
#>   <int> <dbl>
#> 1     1  1.00
#> 2     2  1.00
#> 3     3  1.00
tibble(a = 1:3, c = 1:2)
#> Error: Column `c` must be length 1 or 3, not 2
tibble(a = 1, b = integer())
#> # A tibble: 0 x 2
#> # ... with 2 variables: a <dbl>, b <int>
tibble(a = integer(), b = 1)
#> # A tibble: 0 x 2
#> # ... with 2 variables: a <int>, b <dbl>
tibble/tests/0000755000176200001440000000000013155735443012667 5ustar liggesuserstibble/tests/testthat.R0000644000176200001440000000005213155735443014647 0ustar liggesuserslibrary("testthat") test_check("tibble") tibble/tests/testthat/0000755000176200001440000000000013220301602014502 5ustar liggesuserstibble/tests/testthat/test-has-name.R0000644000176200001440000000076113204634213017310 0ustar liggesuserscontext("has-name") test_that("basic", { expect_true(has_name(iris, "Species")) expect_false(has_name(mtcars, "gears")) }) test_that("other types", { expect_true(has_name(list(a = 1), "a")) expect_true(has_name(c(a = 1), "a")) }) test_that("vectorized", { expect_equal(has_name(list(a = 1), letters), c(TRUE, rep(FALSE, 25))) }) test_that("NA", { expect_false(has_name(list(a = 1), NA)) }) test_that("unnamed", { expect_false(has_name(1, "a")) expect_true(has_name(1, "")) }) tibble/tests/testthat/test-tribble.R0000644000176200001440000000674513204634213017252 0ustar liggesuserscontext("tribble()") test_that("tribble() constructs 'tibble' as expected", { result <- tribble( ~colA, ~colB, "a", 1, "b", 2 ) compared <- tibble(colA = c("a", "b"), colB = c(1, 2)) expect_equal(result, compared) ## wide wide <- tribble( ~colA, ~colB, ~colC, ~colD, 1, 2, 3, 4, 5, 6, 7, 8 ) wide_expectation <- tibble( colA = c(1, 5), colB = c(2, 6), colC = c(3, 7), colD = c(4, 8) ) expect_equal(wide, wide_expectation) ## long long <- tribble( ~colA, ~colB, 1, 6, 2, 7, 3, 8, 4, 9, 5, 10 ) long_expectation <- tibble( colA = as.numeric(1:5), colB = as.numeric(6:10) ) expect_equal(long, long_expectation) }) test_that("tribble() handles columns with a class (#161)", { sys_date <- Sys.Date() sys_time <- Sys.time() date_time_col <- tribble( ~dt, ~dttm, sys_date, sys_time, as.Date("2003-01-02"), as.POSIXct("2004-04-05 13:45:17", tz = "UTC") ) date_time_col_expectation <- tibble( dt = c(sys_date, as.Date("2003-01-02")), dttm = c(sys_time, as.POSIXct("2004-04-05 13:45:17", tz = "UTC")) ) expect_equal(date_time_col, date_time_col_expectation) }) test_that("tribble() creates lists for non-atomic inputs (#7)", { expect_identical( tribble(~a, ~b, NA, "A", letters, LETTERS[-1L]), tibble(a = list(NA, letters), b = list("A", LETTERS[-1L])) ) expect_identical( tribble(~a, ~b, NA, NULL, 1, 2), tibble(a = c(NA, 1), b = list(NULL, 2)) ) }) test_that("tribble() errs appropriately on bad calls", { # invalid colname syntax expect_error( tribble(a~b), "Expected a column name with a single argument; e.g. `~name`", fixed = TRUE ) # invalid colname syntax expect_error( tribble(~a + b), "Expected a symbol or string denoting a column name, not a call", fixed = TRUE ) # tribble() must be passed colnames expect_error( tribble( "a", "b", 1, 2 ), fixed = TRUE ) # tribble() must produce rectangular structure (no filling) expect_error( tribble( ~a, ~b, ~c, 1, 2, 3, 4, 5 ), fixed = TRUE ) }) test_that("tribble can have list columns", { df <- tribble( ~x, ~y, 1, list(a = 1), 2, list(b = 2) ) expect_equal(df$x, c(1, 2)) expect_equal(df$y, list(list(a = 1), list(b = 2))) }) test_that("tribble creates n-col empty data frame", { df <- tribble(~x, ~y) expect_equal(df, tibble(x = logical(), y = logical())) }) test_that("tribble recognizes quoted non-formula call", { df <- tribble( ~x, ~y, quote(mean(1)), 1 ) expect_equal(df$x, list(quote(mean(1)))) expect_equal(df$y, 1) }) test_that("tribble returns 0x0 tibble when there's no argument", { df <- tribble() expect_equal(df, tibble()) }) # ---- frame_matrix() ---- test_that("frame_matrix constructs a matrix as expected", { result <- frame_matrix( ~col1, ~col2, 10, 3, 5, 2 ) expected <- matrix(c(10, 5, 3, 2), ncol = 2) colnames(expected) <- c("col1", "col2") expect_equal(result, expected) }) test_that("frame_matrix constructs empty matrix as expected", { result <- frame_matrix( ~col1, ~col2 ) expected <- matrix(logical(), ncol = 2) colnames(expected) <- c("col1", "col2") expect_equal(result, expected) }) test_that("frame_matrix cannot have list columns", { expect_error( frame_matrix( ~x, ~y, "a", 1:3, "b", 4:6 ), "Can't use list columns in `frame_matrix()`", fixed = TRUE ) }) tibble/tests/testthat/test-tidy_names.R0000644000176200001440000000364613204634213017760 0ustar liggesuserscontext("tidy_names") test_that("zero-length inputs given character names", { out <- set_tidy_names(character()) expect_equal(names(out), character()) }) test_that("unnamed input gives uniquely named output", { out <- set_tidy_names(1:3) expect_equal(names(out), c("..1", "..2", "..3")) }) test_that("messages by default", { expect_message( set_tidy_names(set_names(1, "")), "New names:\n -> ..1\n", fixed = TRUE ) }) test_that("quiet = TRUE", { expect_message(set_tidy_names(set_names(1, ""), quiet = TRUE), NA) }) test_that("syntactic = TRUE", { out <- set_tidy_names(set_names(1, "a b")) expect_equal(names(out), tidy_names("a b")) }) # tidy_names --------------------------------------------------------------- test_that("zero-length input", { expect_equal(tidy_names(character()), character()) }) test_that("proper names", { expect_equal(tidy_names(letters), letters) }) test_that("dupes", { expect_equal( tidy_names(c("a", "b", "a", "c", "b")), c("a..1", "b..2", "a..3", "c", "b..5") ) }) test_that("empty", { expect_equal(tidy_names(""), "..1") }) test_that("NA", { expect_equal(tidy_names(NA_character_), "..1") }) test_that("corner case", { expect_equal(tidy_names(c("a..2", "a")), c("a..2", "a")) expect_equal(tidy_names(c("a..3", "a", "a")), c("a..1", "a..2", "a..3")) expect_equal(tidy_names(c("a..2", "a", "a")), c("a..1", "a..2", "a..3")) expect_equal(tidy_names(c("a..2", "a..2", "a..2")), c("a..1", "a..2", "a..3")) }) test_that("syntactic", { expect_equal(tidy_names("a b", syntactic = TRUE), make.names("a b")) }) test_that("some syntactic + message (#260)", { expect_equal( tidy_names(c("a b", "c"), syntactic = TRUE), c(make.names("a b"), "c") ) }) test_that("message", { expect_message( tidy_names(""), "New names:\n -> ..1\n", fixed = TRUE ) }) test_that("quiet", { expect_message( tidy_names("", quiet = TRUE), NA ) }) tibble/tests/testthat/helper-encoding.R0000644000176200001440000000242613204634213017705 0ustar liggesusersget_lang_strings <- function() { lang_strings <- c( de = "Gl\u00fcck", cn = "\u5e78\u798f", ru = "\u0441\u0447\u0430\u0441\u0442\u044c\u0435", ko = "\ud589\ubcf5" ) native_lang_strings <- enc2native(lang_strings) same <- (lang_strings == native_lang_strings) list( same = lang_strings[same], different = lang_strings[!same] ) } get_native_lang_string <- function() { lang_strings <- get_lang_strings() if (length(lang_strings$same) == 0) testthat::skip("No native language string available") lang_strings$same[[1L]] } get_alien_lang_string <- function() { lang_strings <- get_lang_strings() if (length(lang_strings$different) == 0) testthat::skip("No alien language string available") lang_strings$different[[1L]] } with_non_utf8_locale <- function(code) { old_locale <- set_non_utf8_locale() on.exit(set_locale(old_locale), add = TRUE) code } set_non_utf8_locale <- function() { if (.Platform$OS.type == "windows") return(NULL) tryCatch( locale <- set_locale("en_US.ISO88591"), warning = function(e) { testthat::skip("Cannot set latin-1 locale") } ) locale } set_locale <- function(locale) { if (is.null(locale)) return(NULL) locale <- Sys.getlocale("LC_CTYPE") Sys.setlocale("LC_CTYPE", locale) locale } tibble/tests/testthat/test-type_sum.R0000644000176200001440000000027113204634213017460 0ustar liggesuserscontext("type_sum") test_that("works with glimpse", { foo <- as_override_type_sum(2011:2013) expect_equal(type_sum(foo), "SC") expect_output(glimpse(tibble(foo)), "foo ") }) tibble/tests/testthat/test-repair_names.R0000644000176200001440000000144313204634213020262 0ustar liggesuserscontext("repair_names") test_that("zero-length inputs given character names", { out <- repair_names(character()) expect_equal(names(out), character()) }) test_that("unnamed input gives uniquely named output", { out <- repair_names(1:3) expect_equal(names(out), c("V1", "V2", "V3")) }) # make_unique ------------------------------------------------------------- test_that("duplicates are de-deduped", { expect_equal(make_unique(c("x", "x")), c("x", "x1")) }) test_that("blanks get prefix + numeric id", { expect_equal(make_unique(c("", "")), c("V1", "V2")) }) test_that("blanks skip existing names", { expect_equal(make_unique(c("", "V1")), c("V2", "V1")) }) test_that("blanks skip names created when de-duping", { expect_equal(make_unique(c("", "V", "V")), c("V2", "V", "V1")) }) tibble/tests/testthat/test-rownames.R0000644000176200001440000000531713204634213017454 0ustar liggesuserscontext("rownames") test_that("has_rownames and remove_rownames", { expect_false(has_rownames(iris)) expect_true(has_rownames(mtcars)) expect_false(has_rownames(remove_rownames(mtcars))) expect_false(has_rownames(remove_rownames(iris))) expect_false(has_rownames(1:10)) }) test_that("setting row names on a tibble raises a warning", { mtcars_tbl <- as_tibble(mtcars) expect_warning(rownames(mtcars_tbl) <- rownames(mtcars), "deprecated") }) test_that("rownames_to_column keeps the tbl classes (#882)", { res <- rownames_to_column(mtcars) expect_false(has_rownames(res)) expect_equal(class(res), class(mtcars)) expect_equal(res$rowname, rownames(mtcars)) expect_error( rownames_to_column(mtcars, "wt"), "Column `wt` already exists", fixed = TRUE ) res1 <- rownames_to_column(as_tibble(mtcars), "Make&Model") expect_false(has_rownames(res1)) expect_equal(class(res1), class(as_tibble(mtcars))) expect_equal(res1$`Make&Model`, rownames(mtcars)) expect_error( rownames_to_column(as_tibble(mtcars), "wt"), "Column `wt` already exists", fixed = TRUE ) }) test_that("rowid_to_column keeps the tbl classes", { res <- rowid_to_column(mtcars) expect_false(has_rownames(res)) expect_equal(class(res), class(mtcars)) expect_equal(res$rowid, seq_len(nrow(mtcars))) expect_error( rowid_to_column(mtcars, "wt"), "Column `wt` already exists", fixed = TRUE ) res1 <- rowid_to_column(as_tibble(mtcars), "row_id") expect_false(has_rownames(res1)) expect_equal(class(res1), class(as_tibble(mtcars))) expect_equal(res1$row_id, seq_len(nrow(mtcars))) expect_error( rowid_to_column(as_tibble(mtcars), "wt"), "Column `wt` already exists", fixed = TRUE ) }) test_that("column_to_rownames returns tbl", { var <- "car" mtcars1 <- as_tibble(mtcars) expect_true(has_rownames(mtcars1)) res0 <- rownames_to_column(mtcars1, var) expect_warning(res <- column_to_rownames(res0, var)) expect_true(has_rownames(res)) expect_equal(class(res), class(mtcars1)) expect_equal(rownames(res), rownames(mtcars1)) expect_equal(res, mtcars1) expect_false(has_name(res, var)) mtcars1$num <- rev(seq_len(nrow(mtcars))) res0 <- rownames_to_column(mtcars1) expect_warning(res <- column_to_rownames(res0, var = "num")) expect_true(has_rownames(res)) expect_equal(rownames(res), as.character(mtcars1$num)) expect_error( column_to_rownames(res), "`df` already has row names", fixed = TRUE ) expect_error( column_to_rownames(rownames_to_column(mtcars1, var), "num2"), "Column `num2` not found", fixed = TRUE ) }) test_that("converting to data frame does not add row names", { expect_false(has_rownames(as.data.frame(as_tibble(iris)))) }) tibble/tests/testthat/test-lst.R0000644000176200001440000000124713204634213016421 0ustar liggesuserscontext("lst") test_that("lst handles named and unnamed NULL arguments", { expect_equivalent(lst(NULL), list("NULL" = NULL)) expect_identical(lst(a = NULL), list(a = NULL)) expect_identical( lst(NULL, b = NULL, 1:3), list("NULL" = NULL, b = NULL, "1:3" = 1:3) ) }) test_that("lst handles internal references", { expect_identical(lst(a = 1, b = a), list(a = 1, b = 1)) expect_identical(lst(a = NULL, b = a), list(a = NULL, b = NULL)) }) test_that("lst supports duplicate names (#291)", { expect_identical(lst(a = 1, a = a + 1, b = a), list(a = 1, a = 2, b = 2)) expect_identical(lst(b = 1, a = b, a = b + 1, b = a), list(b = 1, a = 1, a = 2, b = 2)) }) tibble/tests/testthat/test-add.R0000644000176200001440000002140413204634213016344 0ustar liggesuserscontext("add") # add_row --------------------------------------------------------------- test_that("can add new row", { df_all_new <- add_row(df_all, a = 4, b = 3L) expect_identical(colnames(df_all_new), colnames(df_all)) expect_identical(nrow(df_all_new), nrow(df_all) + 1L) expect_identical(df_all_new$a, c(df_all$a, 4)) expect_identical(df_all_new$b, c(df_all$b, 3L)) expect_identical(df_all_new$c, c(df_all$c, NA)) }) test_that("add_row() keeps class of object", { iris_new <- add_row(iris, Species = "unknown") expect_equal(class(iris), class(iris_new)) iris_new <- add_row(as_tibble(iris), Species = "unknown") expect_equal(class(as_tibble(iris)), class(iris_new)) }) test_that("add_row() keeps class of object when adding in the middle", { iris_new <- add_row(iris, Species = "unknown", .after = 10) expect_equal(class(iris), class(iris_new)) iris_new <- add_row(as_tibble(iris), Species = "unknown") expect_equal(class(as_tibble(iris)), class(iris_new)) }) test_that("add_row() keeps class of object when adding in the beginning", { iris_new <- add_row(iris, Species = "unknown", .after = 0) expect_equal(class(iris), class(iris_new)) iris_new <- add_row(as_tibble(iris), Species = "unknown") expect_equal(class(as_tibble(iris)), class(iris_new)) }) test_that("adds empty row if no arguments", { new_iris_row <- add_row(iris)[nrow(iris) + 1, , drop = TRUE] expect_true(all(is.na(new_iris_row))) }) test_that("error if adding row with unknown variables", { expect_error( add_row(tibble(a = 3), xxyzy = "err"), "Can't add row with new variable `xxyzy`", fixed = TRUE ) expect_error( add_row(tibble(a = 3), b = "err", c = "oops"), "Can't add row with new variables `b`, `c`", fixed = TRUE ) }) test_that("can add multiple rows", { df <- tibble(a = 3L) df_new <- add_row(df, a = 4:5) expect_identical(df_new, tibble(a = 3:5)) }) test_that("can recycle when adding rows", { iris_new <- add_row(iris, Sepal.Length = -1:-2, Species = "unknown") expect_identical(nrow(iris_new), nrow(iris) + 2L) expect_identical(iris_new$Sepal.Length, c(iris$Sepal.Length, -1:-2)) expect_identical( as.character(iris_new$Species), c(as.character(iris$Species), "unknown", "unknown") ) }) test_that("can add as first row via .before = 1", { df <- tibble(a = 3L) df_new <- add_row(df, a = 2L, .before = 1) expect_identical(df_new, tibble(a = 2:3)) }) test_that("can add as first row via .after = 0", { df <- tibble(a = 3L) df_new <- add_row(df, a = 2L, .after = 0) expect_identical(df_new, tibble(a = 2:3)) }) test_that("can add row inbetween", { df <- tibble(a = 1:3) df_new <- add_row(df, a = 4:5, .after = 2) expect_identical(df_new, tibble(a = c(1:2, 4:5, 3L))) }) test_that("can safely add to factor columns everywhere (#296)", { df <- tibble(a = factor(letters[1:3])) expect_identical(add_row(df), tibble(a = factor(c(letters[1:3], NA)))) expect_identical(add_row(df, .before = 1), tibble(a = factor(c(NA, letters[1:3])))) expect_identical(add_row(df, .before = 2), tibble(a = factor(c("a", NA, letters[2:3])))) expect_identical(add_row(df, a = "d"), tibble(a = factor(c(letters[1:4])))) expect_identical(add_row(df, a = "d", .before = 1), tibble(a = factor(c("d", letters[1:3])))) expect_identical(add_row(df, a = "d", .before = 2), tibble(a = factor(c("a", "d", letters[2:3])))) }) test_that("error if both .before and .after are given", { df <- tibble(a = 1:3) expect_error( add_row(df, a = 4:5, .after = 2, .before = 3), "Can't specify both `.before` and `.after`", fixed = TRUE ) }) test_that("missing row names stay missing when adding row", { expect_false(has_rownames(iris)) expect_false(has_rownames(add_row(iris, Species = "unknown", .after = 0))) expect_false(has_rownames(add_row(iris, Species = "unknown", .after = nrow(iris)))) expect_false(has_rownames(add_row(iris, Species = "unknown", .before = 10))) }) test_that("adding to a list column adds a NULL value (#148)", { expect_null(add_row(data_frame(a = as.list(1:3)))$a[[4]]) expect_null(add_row(data_frame(a = as.list(1:3)), .before = 1)$a[[1]]) expect_null(add_row(data_frame(a = as.list(1:3)), .after = 1)$a[[2]]) expect_null(add_row(data_frame(a = as.list(1:3), b = 1:3), b = 4:6)$a[[5]]) }) test_that("add_row() keeps the class of empty columns", { new_tibble <- add_row(df_empty, to_be_added = 5) expect_equal(sapply(df_empty, class), sapply(new_tibble, class)) }) test_that("add_row() fails nicely for grouped data frames (#179)", { expect_error( add_row(dplyr::group_by(iris, Species), Petal.Width = 3), "Can't add rows to grouped data frames", fixed = TRUE ) }) # add_column ------------------------------------------------------------ test_that("can add new column", { df_all_new <- add_column(df_all, j = 1:3, k = 3:1) expect_identical(nrow(df_all_new), nrow(df_all)) expect_identical(df_all_new[seq_along(df_all)], df_all) expect_identical(df_all_new$j, 1:3) expect_identical(df_all_new$k, 3:1) }) test_that("add_column() keeps class of object", { iris_new <- add_column(iris, x = 1:150) expect_equal(class(iris), class(iris_new)) iris_new <- add_column(as_tibble(iris), x = 1:150) expect_equal(class(as_tibble(iris)), class(iris_new)) }) test_that("add_column() keeps class of object when adding in the middle", { iris_new <- add_column(iris, x = 1:150, .after = 3) expect_equal(class(iris), class(iris_new)) iris_new <- add_column(as_tibble(iris), x = 1:150) expect_equal(class(as_tibble(iris)), class(iris_new)) }) test_that("add_column() keeps class of object when adding in the beginning", { iris_new <- add_column(iris, x = 1:150, .after = 0) expect_equal(class(iris), class(iris_new)) iris_new <- add_column(as_tibble(iris), x = 1:150) expect_equal(class(as_tibble(iris)), class(iris_new)) }) test_that("add_column() keeps unchanged if no arguments", { expect_identical(iris, add_column(iris)) }) test_that("error if adding existing columns", { expect_error( add_column(tibble(a = 3), a = 5), "Column `a` already exists", fixed = TRUE ) }) test_that("error if adding wrong number of rows with add_column()", { expect_error( add_column(tibble(a = 3), b = 4:5), "`.data` must have 1 row, not 2", fixed = TRUE ) }) test_that("can add multiple columns", { df <- tibble(a = 1:3) df_new <- add_column(df, b = 4:6, c = 3:1) expect_identical(df_new, tibble(a = 1:3, b = 4:6, c = 3:1)) }) test_that("can recycle when adding columns", { df <- tibble(a = 1:3) df_new <- add_column(df, b = 4, c = 3:1) expect_identical(df_new, tibble(a = 1:3, b = rep(4, 3), c = 3:1)) }) test_that("can recycle when adding a column of length 1", { df <- tibble(a = 1:3) df_new <- add_column(df, b = 4) expect_identical(df_new, tibble(a = 1:3, b = rep(4, 3))) }) test_that("can recyle when adding multiple columns of length 1", { df <- tibble(a = 1:3) df_new <- add_column(df, b = 4, c = 5) expect_identical(df_new, tibble(a = 1:3, b = rep(4, 3), c = rep(5, 3))) }) test_that("can recyle for zero-row data frame (#167)", { df <- tibble(a = 1:3)[0, ] df_new <- add_column(df, b = 4, c = character()) expect_identical(df_new, tibble(a = integer(), b = numeric(), c = character())) }) test_that("can add as first column via .before = 1", { df <- tibble(a = 3L) df_new <- add_column(df, b = 2L, .before = 1) expect_identical(df_new, tibble(b = 2L, a = 3L)) }) test_that("can add as first column via .after = 0", { df <- tibble(a = 3L) df_new <- add_column(df, b = 2L, .after = 0) expect_identical(df_new, tibble(b = 2L, a = 3L)) }) test_that("can add column inbetween", { df <- tibble(a = 1:3, c = 4:6) df_new <- add_column(df, b = -1:1, .after = 1) expect_identical(df_new, tibble(a = 1:3, b = -1:1, c = 4:6)) }) test_that("can add column relative to named column", { df <- tibble(a = 1:3, c = 4:6) df_new <- add_column(df, b = -1:1, .before = "c") expect_identical(df_new, tibble(a = 1:3, b = -1:1, c = 4:6)) }) test_that("error if both .before and .after are given", { df <- tibble(a = 1:3) expect_error( add_column(df, b = 4:6, .after = 2, .before = 3), "Can't specify both `.before` and `.after`", fixed = TRUE ) }) test_that("error if column named by .before or .after not found", { df <- tibble(a = 1:3) expect_error( add_column(df, b = 4:6, .after = "x"), "Column `x` not found", fixed = TRUE ) expect_error( add_column(df, b = 4:6, .before = "x"), "Column `x` not found", fixed = TRUE ) }) test_that("missing row names stay missing when adding column", { expect_false(has_rownames(iris)) expect_false(has_rownames(add_column(iris, x = 1:150, .after = 0))) expect_false(has_rownames(add_column(iris, x = 1:150, .after = ncol(iris)))) expect_false(has_rownames(add_column(iris, x = 1:150, .before = 2))) }) tibble/tests/testthat/output/0000755000176200001440000000000012732040575016062 5ustar liggesuserstibble/tests/testthat/output/glimpse/0000755000176200001440000000000013204634213017513 5ustar liggesuserstibble/tests/testthat/output/glimpse/all-50.txt0000644000176200001440000000044513204634213021251 0ustar liggesusersObservations: 3 Variables: 9 $ a 1.0, 2.5, NA $ b 1, 2, NA $ c TRUE, FALSE, NA $ d "a", "b", NA $ e a, b, NA $ f 2015-12-10, 2015-12-11, NA $ g 2015-12-09 10:51:35, 2015-12-09 10... $ h [1, 2, NA] $ i [[1, <2, 3>], [<4, 5, 6>], [NA]] tibble/tests/testthat/output/glimpse/mtcars-70.txt0000644000176200001440000000142613204634213021774 0ustar liggesusersObservations: 32 Variables: 11 $ mpg 21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8... $ cyl 6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 4... $ disp 160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 146... $ hp 110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, ... $ drat 3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92... $ wt 2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.1... $ qsec 16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20.... $ vs 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1... $ am 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1... $ gear 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4... $ carb 4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1... tibble/tests/testthat/output/glimpse/iris-70.txt0000644000176200001440000000057013204634213021450 0ustar liggesusersObservations: 150 Variables: 5 $ Sepal.Length 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4,... $ Sepal.Width 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9,... $ Petal.Length 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4,... $ Petal.Width 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2,... $ Species setosa, setosa, setosa, setosa, setosa, set... tibble/tests/testthat/output/glimpse/all-35.txt0000644000176200001440000000041013204634213021244 0ustar liggesusersObservations: 3 Variables: 9 $ a 1.0, 2.5, NA $ b 1, 2, NA $ c TRUE, FALSE, NA $ d "a", "b", NA $ e a, b, NA $ f 2015-12-10, 2015-12... $ g 2015-12-09 10:51:35... $ h [1, 2, NA] $ i [[1, <2, 3>], [<4, ... tibble/tests/testthat/output/glimpse/all-70.txt0000644000176200001440000000045413204634213021253 0ustar liggesusersObservations: 3 Variables: 9 $ a 1.0, 2.5, NA $ b 1, 2, NA $ c TRUE, FALSE, NA $ d "a", "b", NA $ e a, b, NA $ f 2015-12-10, 2015-12-11, NA $ g 2015-12-09 10:51:35, 2015-12-09 10:51:36, NA $ h [1, 2, NA] $ i [[1, <2, 3>], [<4, 5, 6>], [NA]] tibble/tests/testthat/output/glimpse/non-syntactic.txt0000644000176200001440000000010513204634213023041 0ustar liggesusersObservations: 1 Variables: 2 $ `mean(x)` 5 $ `var(x)` 3 tibble/tests/testthat/output/glimpse/iris-empty-70.txt0000644000176200001440000000002213202157545022602 0ustar liggesusersObservations: 150 tibble/tests/testthat/output/glimpse/5.txt0000644000176200001440000000000713202157545020423 0ustar liggesusers num 5 tibble/tests/testthat/output/trunc_mat/0000755000176200001440000000000013204634213020047 5ustar liggesuserstibble/tests/testthat/output/trunc_mat/newline.txt0000644000176200001440000000006713204634213022254 0ustar liggesusers# A tibble: 2 x 2 tibble/tests/testthat/output/trunc_mat/all-1-30-2.txt0000644000176200001440000000017113204634213022074 0ustar liggesusers# A tibble: 3 x 9 # ... with 2 more rows, and 5 # more variables: e , # f , ... tibble/tests/testthat/output/trunc_mat/iris-5-30.txt0000644000176200001440000000016313204634213022140 0ustar liggesusers# A tibble: 150 x 5 # ... with 145 more rows, and # 1 more variable: # Species tibble/tests/testthat/output/trunc_mat/POSIXlt-8-60.txt0000644000176200001440000000071613204634213022446 0ustar liggesusers# A tibble: 12 x 2 x y 1 2016-01-01 12:34:57 2016-01-01 12:34:57 2 2016-01-01 12:34:58 2016-01-01 12:34:58 3 2016-01-01 12:34:59 2016-01-01 12:34:59 4 2016-01-01 12:35:00 2016-01-01 12:35:00 5 2016-01-01 12:35:01 2016-01-01 12:35:01 6 2016-01-01 12:35:02 2016-01-01 12:35:02 7 2016-01-01 12:35:03 2016-01-01 12:35:03 8 2016-01-01 12:35:04 2016-01-01 12:35:04 # ... with 4 more rows tibble/tests/testthat/output/trunc_mat/zero_cols-5-30.txt0000644000176200001440000000005513204634213023171 0ustar liggesusers# A tibble: 150 x 0 tibble/tests/testthat/output/trunc_mat/iris-3-5.txt0000644000176200001440000000037613204634213022066 0ustar liggesusers# A # tibble: # 150 # x # 5 # ... # with # 147 # more # rows, # and # 5 # more # variables: # Sepal.Length , # Sepal.Width , # Petal.Length , # Petal.Width , # Species tibble/tests/testthat/output/trunc_mat/iris--70.txt0000644000176200001440000000010613204634213022054 0ustar liggesusers# A tibble: 150 x 5 # ... with 140 more rows tibble/tests/testthat/output/trunc_mat/zero-cols_unk-5-30.txt0000644000176200001440000000012113204634213023756 0ustar liggesusers# A tibble: ?? x 0 # ... with at least 5 rows # total tibble/tests/testthat/output/trunc_mat/all-1-30-0.txt0000644000176200001440000000013413204634213022071 0ustar liggesusers# A tibble: 3 x 9 # ... with 2 more rows, and 5 # more variables tibble/tests/testthat/output/trunc_mat/long_unk-5-30.txt0000644000176200001440000000010113204634213022776 0ustar liggesusers# A tibble: ?? x 1 # ... with more rows tibble/tests/testthat/output/trunc_mat/zero-rows_unk-5-30.txt0000644000176200001440000000026513204634213024021 0ustar liggesusers# A tibble: ?? x 5 # ... with 5 variables: # Sepal.Length , # Sepal.Width , # Petal.Length , # Petal.Width , # Species tibble/tests/testthat/output/trunc_mat/wide-8-60.txt0000644000176200001440000000022413204634213022126 0ustar liggesusers# A tibble: 3 x 2 成交日期 合同录入日期 1 1 4 2 2 5 3 3 6 tibble/tests/testthat/output/trunc_mat/non-syntactic.txt0000644000176200001440000000005313204634213023377 0ustar liggesusers# A tibble: 1 x 2 tibble/tests/testthat/output/trunc_mat/mtcars-8-30.txt0000644000176200001440000000027513204634213022472 0ustar liggesusers# A tibble: 32 x 11 # ... with 24 more rows, and # 7 more variables: # drat , wt , # qsec , vs , # am , gear , # carb tibble/tests/testthat/output/trunc_mat/long-5-30.txt0000644000176200001440000000011313204634213022124 0ustar liggesusers# A tibble: 10,000 x 1 # ... with 9,995 more rows tibble/tests/testthat/output/trunc_mat/iris_unk-10-70.txt0000644000176200001440000000010113204634213023065 0ustar liggesusers# A tibble: ?? x 5 # ... with more rows tibble/tests/testthat/output/trunc_mat/all--300.txt0000644000176200001440000000005313204634213021733 0ustar liggesusers# A tibble: 3 x 9 tibble/tests/testthat/output/trunc_mat/zero_rows--30.txt0000644000176200001440000000013013204634213023130 0ustar liggesusers# A tibble: 0 x 2 # ... with 2 variables: # a , b tibble/tests/testthat/output/trunc_mat/all--30.txt0000644000176200001440000000020513204634213021652 0ustar liggesusers# A tibble: 3 x 9 # ... with 5 more variables: # e , f , # g , h , # i tibble/tests/testthat/test-options.R0000644000176200001440000000462613204634213017316 0ustar liggesuserscontext("options") test_that("tibble option takes preference", { withr::with_options( list( tibble.width = 10, dplyr.width = 20 ), expect_equal(tibble_opt("width"), 10) ) }) test_that("dplyr option is used for compatibility", { withr::with_options( list( tibble.width = NULL, dplyr.width = 20 ), expect_equal(tibble_opt("width"), 20) ) }) test_that("fallback to default option", { withr::with_options( list( tibble.width = NULL, dplyr.width = NULL ), expect_equal(tibble_opt("width"), op.tibble[["tibble.width"]]) ) }) test_that("tibble_width returns user-input width, then tibble.width option, then width option", { test_width <- 42 expect_equal(tibble_width(test_width), test_width) withr::with_options( list(tibble.width = test_width), expect_equal(tibble_width(NULL), test_width) ) withr::with_options( list(width = test_width), expect_equal(tibble_width(NULL), test_width) ) }) test_that("tibble_width prefers tibble.width / dplyr.width over width", { withr::with_options( list(tibble.width = 10, width = 20), expect_equal(tibble_width(NULL), 10) ) withr::with_options( list(dplyr.width = 10, width = 20), expect_equal(tibble_width(NULL), 10) ) }) test_that("tibble_glimpse_width returns user-input width, then tibble.width option, then width option", { test_width <- 42 expect_equal(tibble_glimpse_width(test_width), test_width) withr::with_options( list(tibble.width = test_width), expect_equal(tibble_glimpse_width(NULL), test_width) ) withr::with_options( list(width = test_width), expect_equal(tibble_glimpse_width(NULL), test_width) ) }) test_that("tibble_glimpse_width prefers tibble.width / dplyr.width over width", { withr::with_options( list(tibble.width = 10, width = 20), expect_equal(tibble_glimpse_width(NULL), 10) ) withr::with_options( list(dplyr.width = 10, width = 20), expect_equal(tibble_glimpse_width(NULL), 10) ) }) test_that("tibble_glimpse_width ignores Inf tibble.width", { withr::with_options( list(tibble.width = Inf, width = 20), expect_equal(tibble_glimpse_width(NULL), 20) ) }) test_that("print.tbl ignores max.print option", { iris2 <- as_tibble(iris) expect_output( withr::with_options(list(max.print = 3), print(iris2)), capture_output(print(iris2)), fixed = TRUE ) }) tibble/tests/testthat/test-tbl-df.R0000644000176200001440000002233013204634213016763 0ustar liggesuserscontext("tbl_df") # [ ----------------------------------------------------------------------- test_that("[ never drops", { mtcars2 <- as_tibble(mtcars) expect_is(mtcars2[, 1], "data.frame") expect_is(mtcars2[, 1], "tbl_df") expect_equal(mtcars2[, 1], mtcars2[1]) }) test_that("[ retains class", { mtcars2 <- as_tibble(mtcars) expect_identical(class(mtcars2), class(mtcars2[1:5, ])) expect_identical(class(mtcars2), class(mtcars2[, 1:5])) expect_identical(class(mtcars2), class(mtcars2[1:5, 1:5])) }) test_that("[ and as_tibble commute", { mtcars2 <- as_tibble(mtcars) expect_identical(mtcars2, as_tibble(mtcars)) expect_identical(mtcars2[], remove_rownames(as_tibble(mtcars[]))) expect_identical(mtcars2[1:5, ], remove_rownames(as_tibble(mtcars[1:5, ]))) expect_identical(mtcars2[, 1:5], remove_rownames(as_tibble(mtcars[, 1:5]))) expect_identical(mtcars2[1:5, 1:5], remove_rownames(as_tibble(mtcars[1:5, 1:5]))) expect_identical(mtcars2[1:5], remove_rownames(as_tibble(mtcars[1:5]))) }) test_that("[ with 0 cols creates correct row names (#656)", { zero_row <- as_tibble(iris)[, 0] expect_is(zero_row, "tbl_df") expect_equal(nrow(zero_row), 150) expect_equal(ncol(zero_row), 0) expect_identical(zero_row, as_tibble(iris)[0]) }) test_that("[ with 0 cols returns correct number of rows", { iris_tbl <- as_tibble(iris) nrow_iris <- nrow(iris_tbl) expect_equal(nrow(iris_tbl[0]), nrow_iris) expect_equal(nrow(iris_tbl[, 0]), nrow_iris) expect_equal(nrow(iris_tbl[, 0][1:10, ]), 10) expect_equal(nrow(iris_tbl[0][1:10, ]), 10) expect_equal(nrow(iris_tbl[1:10, ][, 0]), 10) expect_equal(nrow(iris_tbl[1:10, ][0]), 10) expect_equal(nrow(iris_tbl[1:10, 0]), 10) expect_equal(nrow(iris_tbl[, 0][-(1:10), ]), nrow_iris - 10) expect_equal(nrow(iris_tbl[0][-(1:10), ]), nrow_iris - 10) expect_equal(nrow(iris_tbl[-(1:10), ][, 0]), nrow_iris - 10) expect_equal(nrow(iris_tbl[-(1:10), ][0]), nrow_iris - 10) expect_equal(nrow(iris_tbl[-(1:10), 0]), nrow_iris - 10) }) test_that("[.tbl_df is careful about names (#1245)", { z_msg <- "Column `z` not found" foo <- tibble(x = 1:10, y = 1:10) expect_error(foo["z"], z_msg, fixed = TRUE) expect_error(foo[ c("x", "y", "z") ], z_msg, fixed = TRUE) expect_error(foo[, "z"], z_msg, fixed = TRUE) expect_error(foo[, c("x", "y", "z") ], z_msg, fixed = TRUE) expect_error( foo[as.matrix("x")], "Can't use matrix or array for column indexing", fixed = TRUE ) expect_error( foo[array("x", dim = c(1, 1, 1))], "Can't use matrix or array for column indexing", fixed = TRUE ) }) test_that("[.tbl_df is careful about column indexes (#83)", { foo <- tibble(x = 1:10, y = 1:10, z = 1:10) expect_identical(foo[1:3], foo) expect_error( foo[0.5], "Column index must be integer, not 0.5", fixed = TRUE ) expect_error( foo[1:5], "Column indexes must be at most 3 if positive, not 4, 5", fixed = TRUE ) # Message from base R expect_error(foo[-1:1]) expect_error(foo[c(-1, 1)]) expect_error( foo[-4], "Column index must be at least -3 if negative, not -4", fixed = TRUE ) expect_error( foo[c(1:3, NA)], "NA column indexes not supported", fixed = TRUE ) expect_error( foo[as.matrix(1)], "Can't use matrix or array for column indexing", fixed = TRUE ) expect_error( foo[array(1, dim = c(1, 1, 1))], "Can't use matrix or array for column indexing", fixed = TRUE ) }) test_that("[.tbl_df is careful about column flags (#83)", { foo <- tibble(x = 1:10, y = 1:10, z = 1:10) expect_identical(foo[TRUE], foo) expect_identical(foo[c(TRUE, TRUE, TRUE)], foo) expect_identical(foo[FALSE], foo[integer()]) expect_identical(foo[c(FALSE, TRUE, FALSE)], foo[2]) expect_error( foo[c(TRUE, TRUE)], "Length of logical index vector must be 1 or 3 (the number of rows), not 2", fixed = TRUE ) expect_error( foo[c(TRUE, TRUE, FALSE, FALSE)], "Length of logical index vector must be 1 or 3 (the number of rows), not 4", fixed = TRUE ) expect_error( foo[c(TRUE, TRUE, NA)], "NA column indexes not supported", fixed = TRUE ) expect_error( foo[as.matrix(TRUE)], "Can't use matrix or array for column indexing", fixed = TRUE ) expect_error( foo[array(TRUE, dim = c(1, 1, 1))], "Can't use matrix or array for column indexing", fixed = TRUE ) }) test_that("[.tbl_df rejects unknown column indexes (#83)", { foo <- tibble(x = 1:10, y = 1:10, z = 1:10) expect_error( foo[list(1:3)], "Unsupported index type: list", fixed = TRUE ) expect_error( foo[as.list(1:3)], "Unsupported index type: list", fixed = TRUE ) expect_error( foo[factor(1:3)], "Unsupported index type: factor", fixed = TRUE ) expect_error( foo[Sys.Date()], "Unsupported index type: Date", fixed = TRUE ) expect_error( foo[Sys.time()], "Unsupported index type: POSIXct", fixed = TRUE ) }) test_that("[.tbl_df supports character subsetting (#312)", { foo <- tibble(x = 1:10, y = 1:10, z = 1:10) expect_identical(foo[as.character(2:4), ], foo[2:4, ]) expect_identical(foo[as.character(-3:-5), ], foo[-3:-5, ]) expect_identical(foo[as.character(9:12), ], foo[9:12, ]) expect_identical(foo[letters, ], foo[rep_along(letters, NA_integer_), ]) expect_identical(foo["9a", ], foo[NA_integer_, ]) }) test_that("[.tbl_df supports character subsetting if row names are present (#312)", { foo <- as_tibble(mtcars) idx <- function(x) rownames(mtcars)[x] expect_identical(foo[idx(2:4), ], foo[2:4, ]) expect_identical(foo[idx(-3:-5), ], foo[-3:-5, ]) expect_identical(foo[idx(29:34), ], foo[29:34, ]) expect_identical(foo[letters, ], foo[rep_along(letters, NA_integer_), ]) expect_identical(foo["9a", ], foo[NA_integer_, ]) }) test_that("[.tbl_df supports logical subsetting (#318)", { foo <- tibble(x = 1:10, y = 1:10, z = 1:10) expect_identical(foo[c(FALSE, rep(TRUE, 3), rep(F, 6)), ], foo[2:4, ]) expect_identical(foo[TRUE, ], foo) expect_identical(foo[FALSE, ], foo[0L, ]) expect_warning( foo[c(TRUE, FALSE), ], "Length of logical index must be 1 or 10, not 2", fixed = TRUE ) }) test_that("[.tbl_df is no-op if args missing", { expect_identical(df_all[], df_all) }) test_that("[.tbl_df supports drop argument (#311)", { expect_identical(df_all[1, 2, drop = TRUE], df_all[[2]][1]) }) test_that("[.tbl_df ignores drop argument (with warning) without j argument (#307)", { expect_warning(expect_identical(df_all[1, drop = TRUE], df_all[1])) }) # [[ ---------------------------------------------------------------------- test_that("[[.tbl_df ignores exact argument", { foo <- tibble(x = 1:10, y = 1:10) expect_warning(foo[["x"]], NA) expect_warning(foo[["x", exact = FALSE]], "ignored") expect_identical(getElement(foo, "y"), 1:10) }) test_that("can use recursive indexing with [[", { foo <- tibble(x = list(y = 1:3, z = 4:5)) expect_equal(foo[[c(1, 1)]], 1:3) expect_equal(foo[[c("x", "y")]], 1:3) }) test_that("[[ returns NULL if name doesn't exist", { df <- tibble(x = 1) expect_null(df[["y"]]) expect_null(df[[1, "y"]]) }) test_that("can use two-dimensional indexing with [[", { iris2 <- as_tibble(iris) expect_equal(iris2[[1, 2]], iris[[1, 2]]) expect_equal(iris2[[2, 3]], iris[[2, 3]]) }) # $ ----------------------------------------------------------------------- test_that("$ throws warning if name doesn't exist", { df <- tibble(x = 1) expect_warning( expect_null(df$y), "Unknown or uninitialised column: 'y'" ) }) test_that("$ throws different warning if attempting a partial initialization (#199)", { df <- tibble(x = 1) expect_warning(df$y[1] <- 2, "Unknown or uninitialised column: 'y'") }) test_that("$ doesn't do partial matching", { df <- tibble(partial = 1) expect_warning( expect_null(df$p), "Unknown or uninitialised column: 'p'" ) expect_warning( expect_null(df$part), "Unknown or uninitialised column: 'part'" ) expect_error(df$partial, NA) }) # is.tibble --------------------------------------------------------------- test_that("is.tibble", { expect_false(is.tibble(iris)) expect_true(is.tibble(as_tibble(iris))) expect_false(is.tibble(NULL)) expect_false(is.tibble(0)) }) test_that("is_tibble", { expect_identical(is.tibble, is_tibble) }) # new_tibble -------------------------------------------------------------- test_that("new_tibble", { tbl <- new_tibble( data.frame(a = 1:3), attr1 = "value1", attr2 = 2, subclass = "nt" ) # Can't compare directly due to dplyr:::all.equal.tbl_df() expect_identical(class(tbl), c("nt", "tbl_df", "tbl", "data.frame")) expect_equal( unclass(tbl), structure( list(a = 1:3), attr1 = "value1", attr2 = 2, .Names = "a", row.names = .set_row_names(3L) ) ) }) test_that("new_tibble checks", { expect_identical(new_tibble(list()), tibble()) expect_identical(new_tibble(list(a = 1:3, b = 4:6)), tibble(a = 1:3, b = 4:6)) expect_error(new_tibble(list(1)), "names", fixed = TRUE) expect_error(new_tibble(list(a = 1, b = 2:3)), "length", fixed = TRUE) expect_error( new_tibble( structure(list(a = 1, b = 2), row.names = .set_row_names(2)) ), "length", fixed = TRUE ) }) tibble/tests/testthat/test-glimpse.R0000644000176200001440000000421213204634213017252 0ustar liggesuserscontext("Glimpse") test_that("format_v for values", { expect_equal(format_v(1), "1") expect_equal(format_v(1:3), c("1", "2", "3")) expect_equal(format_v(NA), "NA") expect_equal(format_v(TRUE), "TRUE") expect_equal(format_v(logical()), character()) }) test_that("format_v for character", { expect_equal(format_v("1"), paste0('"', "1", '"')) expect_equal(format_v(letters), paste0('"', letters, '"')) expect_equal(format_v(NA_character_), "NA") expect_equal(format_v(character()), character()) }) test_that("format_v for list", { expect_equal(format_v(list(1:3)), "[<1, 2, 3>]") expect_equal(format_v(as.list(1:3)), "[1, 2, 3]") expect_equal(format_v(list(1:3, 4)), "[<1, 2, 3>, 4]") expect_equal(format_v(list(1:3, 4:5)), "[<1, 2, 3>, <4, 5>]") expect_equal(format_v(list()), "[]") expect_equal(format_v(list(list())), "[[]]") expect_equal(format_v(list(character())), "[<>]") expect_equal(format_v(list(1:3, list(4))), "[<1, 2, 3>, [4]]") expect_equal(format_v(list(1:3, list(4:5))), "[<1, 2, 3>, [<4, 5>]]") }) test_that("glimpse output matches known output", { expect_output_file_rel( glimpse(as_tibble(mtcars), width = 70L), "glimpse/mtcars-70.txt" ) expect_output_file_rel( glimpse(as_tibble(iris), width = 70L), "glimpse/iris-70.txt" ) expect_output_file_rel( glimpse(as_tibble(iris[integer()]), width = 70L), "glimpse/iris-empty-70.txt" ) expect_output_file_rel( glimpse(tibble("mean(x)" = 5, "var(x)" = 3), width = 28), "glimpse/non-syntactic.txt" ) expect_output_file_rel( glimpse(as_tibble(df_all), width = 70L), "glimpse/all-70.txt" ) withr::with_options( list(tibble.width = 50), expect_output_file_rel( glimpse(as_tibble(df_all)), "glimpse/all-50.txt" ) ) withr::with_options( list(tibble.width = 35), expect_output_file_rel( glimpse(as_tibble(df_all)), "glimpse/all-35.txt" ) ) expect_output_file_rel( glimpse(5), "glimpse/5.txt" ) }) test_that("glimpse(width = Inf) raises legible error", { expect_error( glimpse(mtcars, width = Inf), "`width` must be finite", fixed = TRUE ) }) tibble/tests/testthat/test-trunc-mat.R0000644000176200001440000000736313204634213017536 0ustar liggesuserscontext("Truncated matrix") test_that("interface of print() identical to trunc_mat()", { print_arg_names <- names(formals(print.tbl)) print_arg_names_without_ellipsis <- setdiff(print_arg_names, "...") trunc_mat_arg_names <- names(formals(trunc_mat)) expect_equal(print_arg_names_without_ellipsis, trunc_mat_arg_names) }) test_that("print() returns output invisibly", { expect_output(ret <- withVisible(print(as_tibble(mtcars)))) expect_false(ret$visible) expect_identical(ret$value, as_tibble(mtcars)) }) test_that("trunc_mat output matches known output", { skip_on_os("windows") expect_output_file_rel( print_without_body(as_tibble(mtcars), n = 8L, width = 30L), "trunc_mat/mtcars-8-30.txt" ) expect_output_file_rel( print_without_body(as_tibble(iris), n = 5L, width = 30L), "trunc_mat/iris-5-30.txt" ) expect_output_file_rel( print_without_body(as_tibble(iris), n = 3L, width = 5L), "trunc_mat/iris-3-5.txt" ) expect_output_file_rel( print_without_body(as_tibble(iris), n = NULL, width = 70L), "trunc_mat/iris--70.txt" ) expect_output_file_rel( print_without_body(as_unknown_rows(iris), n = 10, width = 70L), "trunc_mat/iris_unk-10-70.txt" ) expect_output_file_rel( print_without_body(df_all, n = NULL, width = 30L), "trunc_mat/all--30.txt" ) expect_output_file_rel( print_without_body(df_all, n = NULL, width = 300L), "trunc_mat/all--300.txt" ) expect_output_file_rel( print_without_body(tibble(a = seq.int(10000)), n = 5L, width = 30L), "trunc_mat/long-5-30.txt" ) expect_output_file_rel( print_without_body(tibble(a = character(), b = logical()), width = 30L), "trunc_mat/zero_rows--30.txt" ) expect_output_file_rel( print_without_body(as_tibble(iris)[character()], n = 5L, width = 30L), "trunc_mat/zero_cols-5-30.txt" ) expect_output_file_rel( print_without_body(as_unknown_rows(iris[integer(), ]), n = 5L, width = 30L), "trunc_mat/zero-rows_unk-5-30.txt" ) expect_output_file_rel( print_without_body(as_unknown_rows(iris[, character()]), n = 5L, width = 30L), "trunc_mat/zero-cols_unk-5-30.txt" ) expect_output_file_rel( print_without_body( as_unknown_rows(tibble(a = seq.int(10000))), n = 5L, width = 30L ), "trunc_mat/long_unk-5-30.txt" ) expect_output_file_rel( print_without_body(trunc_mat(df_all, n = 1L, n_extra = 2L, width = 30L)), "trunc_mat/all-1-30-2.txt" ) expect_output_file_rel( print_without_body(trunc_mat(df_all, n = 1L, n_extra = 0L, width = 30L)), "trunc_mat/all-1-30-0.txt" ) expect_output_file_rel( print_without_body(trunc_mat(tibble("mean(x)" = 5, "var(x)" = 3), width = 28)), "trunc_mat/non-syntactic.txt" ) }) test_that("trunc_mat for POSIXlt columns (#86)", { skip_on_os("windows") df <- tibble(x = as.POSIXct("2016-01-01 12:34:56 GMT") + 1:12) df$y <- as.POSIXlt(df$x) expect_output_file_rel( print(as_tibble(df), n = 8L, width = 60L), "trunc_mat/POSIXlt-8-60.txt" ) }) test_that("trunc_mat for wide-character columns (#100)", { skip_on_os("windows") # capture_output_lines() forces native encoding x <- c("\u6210\u4ea4\u65e5\u671f", "\u5408\u540c\u5f55\u5165\u65e5\u671f") df <- setNames(tibble(1:3, 4:6), x) expect_output_file_rel( print(df, n = 8L, width = 60L), "trunc_mat/wide-8-60.txt" ) }) test_that("trunc_mat for wide-character columns in non-UTF-8 locale", { skip_on_os("windows") # capture_output_lines() forces native encoding with_non_utf8_locale({ x <- c("\u6210\u4ea4\u65e5\u671f", "\u5408\u540c\u5f55\u5165\u65e5\u671f") df <- setNames(tibble(1:3, 4:6), x) expect_output_file_rel( print(df, n = 8L, width = 60L), "trunc_mat/wide-8-60.txt" ) }) }) tibble/tests/testthat/test-utils-format.R0000644000176200001440000000157313204634213020247 0ustar liggesuserscontext("utils-format") test_that("pluralise works correctly", { expect_identical(pluralise("[an] index(es)", c("x")), "an index") expect_identical(pluralise("[an] index(es)", c("x", "y")), "indexes") }) test_that("pluralise leaves alone parentheses / square brackets that have spaces inside", { expect_identical( pluralise("[an] invalid index(es) (be careful) [for real]", c("x")), "an invalid index (be careful) [for real]" ) expect_identical( pluralise("[an] invalid index(es) (be careful) [for real]", c("x", "y")), "invalid indexes (be careful) [for real]" ) }) test_that("pluralise_msg works correctly", { expect_identical(pluralise_msg("[an] index(es) ", c("x")), "an index `x`") expect_identical(pluralise_msg("[an] index(es) ", c("x", "y")), "indexes `x`, `y`") expect_identical(pluralise_msg("[an] index(es) ", c(-4, -5)), "indexes -4, -5") }) tibble/tests/testthat/helper-output.R0000644000176200001440000000055413204634213017457 0ustar liggesusersoutput_file <- function(filename) file.path("output", filename) expect_output_file_rel <- function(x, filename) { withr::with_options( list(digits = 4, width = 80), expect_output_file(x, output_file(filename), update = TRUE) ) } expect_output_knit <- function(knit, filename, envir = parent.frame()) { expect_output_file_rel(cat(knit), filename) } tibble/tests/testthat/test-string-to-indices.R0000644000176200001440000000071413204634213021157 0ustar liggesuserscontext("string to indices") test_that("works as expected", { expect_identical(string_to_indices(as.character(1:3)), 1:3) expect_identical(string_to_indices(letters[1:3]), rep(NA_integer_, 3)) expect_identical(string_to_indices(as.character(1:3 + 1e10)), 1:3 + 1e10) expect_identical(string_to_indices(c(as.character(1:3 + 1e10), "x")), c(1:3 + 1e10, NA)) expect_identical(string_to_indices(as.character(c(1:3, 1:3 + 1e10))), c(1:3, 1:3 + 1e10)) }) tibble/tests/testthat/test-enframe.R0000644000176200001440000000167513204634213017241 0ustar liggesuserscontext("enframe") # enframe ----------------------------------------------------------------- test_that("can convert unnamed vector", { expect_identical( enframe(3:1), tibble(name = 1:3, value = 3:1) ) }) test_that("can convert named vector", { expect_identical( enframe(c(a = 2, b = 1)), tibble(name = letters[1:2], value = as.numeric(2:1)) ) }) test_that("can convert zero-length vector", { expect_identical( enframe(logical()), tibble(name = integer(), value = logical()) ) }) test_that("can use custom names", { expect_identical( enframe(letters, name = "index", value = "letter"), tibble( index = seq_along(letters), letter = letters ) ) }) # deframe ----------------------------------------------------------------- test_that("can deframe two-column data frame", { expect_identical( deframe(tibble(name = letters[1:3], value = 3:1)), c(a = 3L, b = 2L, c = 1L) ) }) tibble/tests/testthat/test-data-frame.R0000644000176200001440000002227213204634213017621 0ustar liggesuserscontext("tibble") test_that("tibble returns correct number of rows with all combinatinos", { expect_equal(nrow(tibble(value = 1:10)), 10L) expect_equal(nrow(tibble(value = 1:10, name = "recycle_me")), 10L) expect_equal(nrow(tibble(name = "recycle_me", value = 1:10)), 10L) expect_equal(nrow(tibble(name = "recycle_me", value = 1:10, value2 = 11:20)), 10L) expect_equal(nrow(tibble(value = 1:10, name = "recycle_me", value2 = 11:20)), 10L) }) test_that("can't make tibble containing data.frame or array", { expect_error( tibble(mtcars), "Column `mtcars` must be a 1d atomic vector or a list", fixed = TRUE ) expect_error( tibble(diag(5)), "Column `diag(5)` must be a 1d atomic vector or a list", fixed = TRUE ) expect_error( tibble(mtcars, diag(5)), "Columns `mtcars`, `diag(5)` must be 1d atomic vectors or lists", fixed = TRUE ) }) test_that("dim attribute is stripped of 1D array (#84)", { expect_null(dim(tibble(x = array(1:3))$x)) }) test_that("bogus columns raise an error", { expect_error( as_tibble(list(1)), "Column 1 must be named", fixed = TRUE ) expect_error( tibble(a = NULL), "Column `a` must be a 1d atomic vector or a list", fixed = TRUE ) expect_error( tibble(a = new.env()), "Column `a` must be a 1d atomic vector or a list", fixed = TRUE ) expect_error( tibble(a = quote(a)), "Column `a` must be a 1d atomic vector or a list", fixed = TRUE ) }) test_that("length 1 vectors are recycled", { expect_equal(nrow(tibble(x = 1:10)), 10) expect_equal(nrow(tibble(x = 1:10, y = 1)), 10) expect_error( tibble(x = 1:10, y = 1:2), "Column `y` must be length 1 or 10, not 2", fixed = TRUE ) }) test_that("missing names are imputed from call", { x <- 1:10 df <- tibble(x, y = x) expect_equal(names(df), c("x", "y")) }) test_that("empty input makes 0 x 0 tbl_df", { zero <- tibble() expect_is(zero, "tbl_df") expect_equal(dim(zero), c(0L, 0L)) expect_identical(attr(zero, "names"), character(0L)) }) test_that("SE version", { expect_identical(tibble_(list(a = ~1:10)), tibble(a = 1:10)) }) test_that("names are stripped from vectors", { foo <- tibble(x = c(y = 1, z = 2)) expect_equal(names(foo), "x") expect_null(names(foo$x)) }) test_that("names in list columns are preserved", { foo <- tibble(x = list(y = 1:3, z = 4:5)) expect_equal(names(foo), "x") expect_equal(names(foo$x), c("y", "z")) }) test_that("attributes are preserved", { df <- structure( data.frame(x = 1:10, g1 = rep(1:2, each = 5), g2 = rep(1:5, 2)), meta = "this is important" ) res <- as_tibble(df) expect_identical(attr(res, "meta"), attr(df, "meta")) }) test_that("tibble aliases", { expect_identical(data_frame, tibble) expect_identical(data_frame_, tibble_) }) # as_tibble ----------------------------------------------------------- test_that("columns must be same length", { expect_error( as_tibble(list(x = 1:2, y = 1:3)), "Column `x` must be length 1 or 3, not 2", fixed = TRUE ) expect_error( as_tibble(list(x = 1:2, y = 1:3, z = 1:4)), "Columns `x`, `y` must be length 1 or 4, not 2, 3", fixed = TRUE ) expect_error( as_tibble(list(x = 1:4, y = 1:2, z = 1:2)), "Columns `y`, `z` must be length 1 or 4, not 2, 2", fixed = TRUE ) }) test_that("columns must be named", { l1 <- list(1:10) l2 <- list(x = 1, 2) expect_error( as_tibble(l1), "Column 1 must be named", fixed = TRUE ) expect_error( as_tibble(l2), "Column 2 must be named", fixed = TRUE ) }) test_that("can't coerce list data.frame or array", { expect_error( as_tibble(list(x = mtcars)), "Column `x` must be a 1d atomic vector or a list", fixed = TRUE ) expect_error( as_tibble(list(x = diag(5))), "Column `x` must be a 1d atomic vector or a list", fixed = TRUE ) expect_error( as_tibble(list(x = mtcars, y = diag(5))), "Columns `x`, `y` must be 1d atomic vectors or lists", fixed = TRUE ) }) test_that("empty list() makes 0 x 0 tbl_df", { zero <- as_tibble(list()) expect_is(zero, "tbl_df") expect_equal(dim(zero), c(0L, 0L)) }) test_that("NULL makes 0 x 0 tbl_df", { nnnull <- as_tibble(NULL) expect_is(nnnull, "tbl_df") expect_equal(dim(nnnull), c(0L, 0L)) }) test_that("as_tibble.tbl_df() leaves classes unchanged (#60)", { df <- tibble() expect_equal( class(df), c("tbl_df", "tbl", "data.frame") ) expect_equal( class(structure(df, class = c("my_df", class(df)))), c("my_df", "tbl_df", "tbl", "data.frame") ) }) test_that("Can convert tables to data frame", { mtcars_table <- xtabs(mtcars, formula = ~vs + am + cyl) mtcars_tbl <- as_tibble(mtcars_table) expect_equal(names(mtcars_tbl), c(names(dimnames(mtcars_table)), "n")) mtcars_tbl <- as_tibble(mtcars_table, "Freq") expect_equal(names(mtcars_tbl), c(names(dimnames(mtcars_table)), "Freq")) }) test_that("Can convert atomic vectors to data frame", { expect_equal(as_tibble(1:3), tibble(value = 1:3)) expect_equal(as_tibble(c(TRUE, FALSE, NA)), tibble(value = c(TRUE, FALSE, NA))) expect_equal(as_tibble(1.5:3.5), tibble(value = 1.5:3.5)) expect_equal(as_tibble(letters), tibble(value = letters)) }) test_that("Can convert named atomic vectors to data frame", { expect_equal(as_tibble(setNames(nm = 1:3)), tibble(value = 1:3)) expect_equal(as_tibble(setNames(nm = c(TRUE, FALSE, NA))), tibble(value = c(TRUE, FALSE, NA))) expect_equal(as_tibble(setNames(nm = 1.5:3.5)), tibble(value = 1.5:3.5)) expect_equal(as_tibble(setNames(nm = letters)), tibble(value = letters)) }) test_that("as_tibble() can validate (#278)", { df <- tibble(a = 1, b = 2) names(df) <- c("", NA) expect_error(as_tibble(df), NA) expect_error( as_tibble(df, validate = TRUE), "Columns 1, 2 must be named", fixed = TRUE ) }) test_that("as_tibble() adds empty names if not validating", { invalid_df <- as_tibble(list(3, 4, 5), validate = FALSE) expect_equal(length(invalid_df), 3) expect_equal(nrow(invalid_df), 1) expect_equal(names(invalid_df), rep("", 3)) }) test_that("as_tibble() can convert row names", { df <- data.frame(a = 1:3, b = 2:4, row.names = letters[5:7]) expect_identical( as_tibble(df, rownames = NULL), tibble(a = 1:3, b = 2:4) ) expect_identical( as_tibble(df, rownames = "id"), tibble(id = letters[5:7], a = 1:3, b = 2:4) ) expect_identical(rownames(as_tibble(df)), rownames(df)) expect_identical(unclass(as_tibble(df)), unclass(df)) }) test_that("as_data_frame is an alias of as_tibble", { expect_identical(as_data_frame(NULL), as_tibble(NULL)) }) test_that("as.tibble is an alias of as_tibble", { expect_identical(as.tibble(NULL), as_tibble(NULL)) }) # Validation -------------------------------------------------------------- test_that("2d object isn't a valid column", { expect_error( check_tibble(list(x = mtcars)), "Column `x` must be a 1d atomic vector or a list", fixed = TRUE ) expect_error( check_tibble(list(x = mtcars, y = mtcars)), "Columns `x`, `y` must be 1d atomic vectors or lists", fixed = TRUE ) }) test_that("POSIXlt isn't a valid column", { expect_error( check_tibble(list(x = as.POSIXlt(Sys.time()))), "Column `x` is a date/time and must be stored as POSIXct, not POSIXlt", fixed = TRUE ) expect_error( check_tibble(list(x = as.POSIXlt(Sys.time()), y = as.POSIXlt(Sys.time()))), "Columns `x`, `y` are dates/times and must be stored as POSIXct, not POSIXlt", fixed = TRUE ) }) test_that("NULL isn't a valid column", { expect_error( check_tibble(list(a = NULL)), "Column `a` must be a 1d atomic vector or a list", fixed = TRUE ) expect_error( check_tibble(list(a = NULL, b = NULL)), "Columns `a`, `b` must be 1d atomic vectors or lists", fixed = TRUE ) }) test_that("columns must be named (#1101)", { l <- list(1:10, 1:10) expect_error( check_tibble(l), "Columns 1, 2 must be named", fixed = TRUE ) expect_error( check_tibble(setNames(l, c("x", ""))), "Column 2 must be named", fixed = TRUE ) expect_error( check_tibble(setNames(l, c("x", NA))), "Column 2 must be named", fixed = TRUE ) }) test_that("names must be unique (#820)", { expect_error( check_tibble(list(x = 1, x = 2, y = 3)), "Column `x` must have a unique name", fixed = TRUE ) expect_error( check_tibble(list(x = 1, x = 2, y = 3, y = 4)), "Columns `x`, `y` must have unique names", fixed = TRUE ) }) test_that("mutate() semantics for tibble() (#213)", { expect_equal( tibble(a = 1:2, b = 1, c = b / sum(b)), tibble(a = 1:2, b = c(1, 1), c = c(0.5, 0.5)) ) expect_equal( tibble(b = 1, a = 1:2, c = b / sum(b)), tibble(b = c(1, 1), a = 1:2, c = c(0.5, 0.5)) ) expect_equal( tibble(b = 1, c = b / sum(b), a = 1:2), tibble(b = c(1, 1), c = c(1, 1), a = 1:2) ) }) test_that("types preserved when recycling in tibble() (#284)", { expect_equal( tibble(a = 1:2, b = as.difftime(1, units = "hours")), tibble(a = 1:2, b = as.difftime(c(1, 1), units = "hours")) ) expect_equal( tibble(b = as.difftime(1, units = "hours"), a = 1:2), tibble(b = as.difftime(c(1, 1), units = "hours"), a = 1:2) ) }) tibble/tests/testthat/test-matrix.R0000644000176200001440000000553113204634213017123 0ustar liggesuserscontext("matrix") test_that("correct rows and cols", { x <- matrix(1:6, nrow = 2) out <- as_tibble(x) expect_equal(dim(out), c(2, 3)) }) test_that("preserves col names", { x <- matrix(1:4, nrow = 2) colnames(x) <- c("a", "b") out <- as_tibble(x) expect_equal(names(out), c("a", "b")) }) test_that("creates col names", { x <- matrix(1:4, nrow = 2) out <- as_tibble(x) expect_equal(names(out), c("V1", "V2")) }) test_that("preserves attributes except dim and names", { date <- Sys.Date() + 0:3 dim(date) <- c(2, 2) colnames(date) <- c("a", "b") attr(date, "special") <- 42 out <- as_tibble.matrix(date) expect_null(attributes(out[[1]])$names) expect_equal(attributes(out[[1]])$class, "Date") expect_equal(attributes(out[[2]])$special, 42) }) test_that("properly handles poly class (#110)", { p <- poly(1:6, 3) p_df <- as_tibble(p) expect_equal(names(p_df), colnames(p)) expect_equal(class(p_df[[1L]]), class(p[, 1])) }) test_that("handles atomic vectors", { x <- matrix(TRUE, nrow = 2) out <- as_tibble(x) expect_equal(out[[1]], c(TRUE, TRUE)) x <- matrix(1L, nrow = 2) out <- as_tibble(x) expect_equal(out[[1]], c(1L, 1L)) x <- matrix(1.5, nrow = 2) out <- as_tibble(x) expect_equal(out[[1]], c(1.5, 1.5)) x <- matrix("a", nrow = 2) out <- as_tibble(x) expect_equal(out[[1]], c("a", "a")) x <- matrix(complex(real = 1, imag = 2), nrow = 2) out <- as_tibble(x) expect_equal(out[[1]], as.vector(x)) }) test_that("auto-assigning names", { expect_identical( as_tibble(diag(3L)), as_tibble(as.data.frame(diag(3L))) ) }) test_that("forwarding to as.data.frame() for ts objects (#184)", { mts <- cbind( A = ts(c(1, 1, 2, 2), start = 2016, freq = 4), B = ts(c(11, 11, 12, 13), start = 2016, freq = 4) ) expect_identical(as_tibble(mts), as_tibble(as.data.frame(mts))) }) test_that("converting from matrix removes row names by default", { x <- matrix(1:30, 6, 5, dimnames = list(letters[1:6], LETTERS[1:5])) df <- data.frame(A = 1:6, B = 7:12, C = 13:18, D = 19:24, E = 25:30) out <- as_tibble(x) expect_false(has_rownames(out)) expect_identical(out, as_tibble(df)) }) test_that("converting from matrix keeps row names if argument has them, with rownames = NA", { x <- matrix(1:30, 6, 5, dimnames = list(letters[1:6], LETTERS[1:5])) df <- data.frame(A = 1:6, B = 7:12, C = 13:18, D = 19:24, E = 25:30, row.names = letters[1:6]) out <- as_tibble(x, rownames = NA) expect_identical(rownames(out), rownames(x)) expect_identical(out, as_tibble(df)) }) test_that("converting from matrix supports storing row names in a column", { x <- matrix(1:30, 6, 5, dimnames = list(letters[1:6], LETTERS[1:5])) df <- tibble(id = letters[1:6], A = 1:6, B = 7:12, C = 13:18, D = 19:24, E = 25:30) out <- as_tibble(x, rownames = "id") expect_identical(out, df) }) tibble/tests/testthat/helper-type-sum.R0000644000176200001440000000066313204634213017703 0ustar liggesusersas_override_type_sum <- function(x) { structure(x, class = "override_type_sum") } type_sum.override_type_sum <- function(x, ...) { "SC" } registerS3method("type_sum", "override_type_sum", type_sum.override_type_sum, envir = asNamespace("pillar")) `[.override_type_sum` <- function(x, ...) { as_override_type_sum(NextMethod()) } registerS3method("[", "override_type_sum", `[.override_type_sum`, envir = asNamespace("tibble")) tibble/tests/testthat/helper-unknown-rows.R0000644000176200001440000000054313204634213020604 0ustar liggesusersas_unknown_rows <- function(x) { x <- as_tibble(x) class(x) <- c("unknown_rows", class(x)) x } dim.unknown_rows <- function(x) { c(NA_integer_, length(x)) } registerS3method("dim", "unknown_rows", dim.unknown_rows) head.unknown_rows <- function(x, n) { head(as.data.frame(x), n) } registerS3method("head", "unknown_rows", head.unknown_rows) tibble/tests/testthat/helper-data.R0000644000176200001440000000123713204634213017027 0ustar liggesusers# A data frame with all major types df_all <- tibble( a = c(1, 2.5, NA), b = c(1:2, NA), c = c(T, F, NA), d = c("a", "b", NA), e = factor(c("a", "b", NA)), f = as.Date("2015-12-09") + c(1:2, NA), g = as.POSIXct("2015-12-09 10:51:34 UTC") + c(1:2, NA), h = as.list(c(1:2, NA)), i = list(list(1, 2:3), list(4:6), list(NA)) ) # An empty data frame with all major types df_empty <- tibble( a = integer(0), b = double(0), c = logical(0), d = character(0), e = factor(integer(0)), f = as.Date(character(0)), g = as.POSIXct(character(0)), h = as.list(double(0)), # i = list(list(integer(0)), list(character(0))), to_be_added = double(0) ) tibble/src/0000755000176200001440000000000013217741055012307 5ustar liggesuserstibble/src/coerce.c0000644000176200001440000000261213217741055013714 0ustar liggesusers#include #include #include #include #include #include "tibble.h" static long long string_to_int64(const char* x) { char* px = NULL; long long xi = strtoll(x, &px, 10); if (*px) return LLONG_MIN; if (xi == LLONG_MAX) return LLONG_MIN; return xi; } static SEXP string_to_numeric_indexes(SEXP x, R_xlen_t int_i, SEXP int_out) { const int* int_out_vec = INTEGER(int_out); const R_xlen_t len = Rf_length(x); SEXP out = PROTECT(Rf_allocVector(REALSXP, len)); double* out_vec = REAL(out); for (R_xlen_t i = 0; i < int_i; ++i) { out_vec[i] = (double)int_out_vec[i]; } for (R_xlen_t i = int_i; i < len; ++i) { long long xi = string_to_int64(CHAR(STRING_ELT(x, i))); if (xi == LLONG_MIN) { out_vec[i] = NA_REAL; } else { out_vec[i] = (double)xi; } } UNPROTECT(1); return out; } SEXP tibble_string_to_indices(SEXP x) { const R_xlen_t len = Rf_length(x); SEXP out = PROTECT(Rf_allocVector(INTSXP, len)); int* out_vec = INTEGER(out); for (R_xlen_t i = 0; i < len; ++i) { long long xi = string_to_int64(CHAR(STRING_ELT(x, i))); if (xi == LLONG_MIN) { out_vec[i] = NA_INTEGER; } else if (xi <= INT_MIN || xi > INT_MAX) { out = string_to_numeric_indexes(x, i, out); break; } else { out_vec[i] = (int)xi; } } UNPROTECT(1); return out; } tibble/src/matrixToDataFrame.c0000644000176200001440000001430113217741055016026 0ustar liggesusers#include #include #include #include #include "tibble.h" static SEXP pairlist_shallow_copy(SEXP p) { int nprot = 0; SEXP attr; PROTECT(attr = Rf_cons(CAR(p), R_NilValue)); nprot++; SEXP q = attr; SET_TAG(q, TAG(p)); p = CDR(p); while (!Rf_isNull(p)) { SEXP s; PROTECT(s = Rf_cons(CAR(p), R_NilValue)); nprot++; SETCDR(q, s); q = CDR(q); SET_TAG(q, TAG(p)); p = CDR(p); } UNPROTECT(nprot); return attr ; } static void copy_attributes(SEXP out, SEXP data) { SEXP att = ATTRIB(data); if (!Rf_isNull(att)){ SET_ATTRIB(out, pairlist_shallow_copy(ATTRIB(data))) ; } SET_OBJECT(out, OBJECT(data)); if (IS_S4_OBJECT(data)) { SET_S4_OBJECT(out); } } // same as copy_attributes but without names static void copy_most_attributes(SEXP out, SEXP data) { copy_attributes(out, data); Rf_setAttrib(out, R_NamesSymbol, R_NilValue); } static void get_dim(SEXP x, R_xlen_t *nrowptr, R_xlen_t *ncolptr) { int nprot = 0; SEXP dim; PROTECT(dim = Rf_getAttrib(x, R_DimSymbol)); nprot++; if (dim == R_NilValue || XLENGTH(dim) != 2) { Rf_error("`x` is not a matrix"); } R_xlen_t nrow = 0, ncol = 0; switch (TYPEOF(dim)) { case INTSXP: nrow = (R_xlen_t)INTEGER(dim)[0]; ncol = (R_xlen_t)INTEGER(dim)[1]; break; case REALSXP: nrow = (R_xlen_t)REAL(dim)[0]; ncol = (R_xlen_t)REAL(dim)[1]; break; default: Rf_error("`x` is not a matrix"); break; } if (nrowptr) { *nrowptr = nrow; } if (ncolptr) { *ncolptr = ncol; } UNPROTECT(nprot); } static SEXP get_names(SEXP x, R_xlen_t ncol) { int nprot = 0; SEXP colnames = R_NilValue; // check for column names, use them if present SEXP dimnames; PROTECT(dimnames = Rf_getAttrib(x, R_DimNamesSymbol)); nprot++; if (TYPEOF(dimnames) == VECSXP && XLENGTH(dimnames) == 2) { colnames = VECTOR_ELT(dimnames, 1); if (TYPEOF(colnames) != STRSXP) { colnames = R_NilValue; } } // otherwise, allocate new names if (Rf_isNull(colnames)) { PROTECT(colnames = Rf_allocVector(STRSXP, ncol)); nprot++; // Maximum number of (base 10) digits in a non-negative R_xlen_t. // 1 + floor(log10(2^64 - 1)) = 20 const int XLEN_DIGIT_MAX = 20; char buf[XLEN_DIGIT_MAX + 2]; // V + (number) + NUL for (R_xlen_t i = 0; i < ncol; i++) { sprintf(buf, "V%"PRIu64, (uint64_t)(i + 1)); SET_STRING_ELT(colnames, i, Rf_mkCharCE(buf, CE_UTF8)); } } UNPROTECT(nprot); return colnames; } static SEXP get_rownames(SEXP x, R_xlen_t nrow) { int nprot = 0; SEXP rownames = R_NilValue; // check for row names, use them if present SEXP dimnames; PROTECT(dimnames = Rf_getAttrib(x, R_DimNamesSymbol)); nprot++; if (TYPEOF(dimnames) == VECSXP && XLENGTH(dimnames) == 2) { rownames = VECTOR_ELT(dimnames, 0); if (TYPEOF(rownames) != STRSXP) { rownames = R_NilValue; } } // otherwise, allocate new row names attribute if (Rf_isNull(rownames)) { if (nrow <= INT_MAX) { PROTECT(rownames = Rf_allocVector(INTSXP, 2)); nprot++; INTEGER(rownames)[0] = NA_INTEGER; INTEGER(rownames)[1] = -(int)nrow; } else { PROTECT(rownames = Rf_allocVector(REALSXP, 2)); nprot++; REAL(rownames)[0] = NA_REAL; REAL(rownames)[1] = -(double)nrow; } } UNPROTECT(nprot); return rownames; } // don't use DATAPTR, it's not part of the public API static void *get_data(SEXP x, size_t *widthptr) { size_t width = 0; void *ptr = NULL; switch (TYPEOF(x)) { case LGLSXP: ptr = LOGICAL(x); width = sizeof(int); break; case INTSXP: ptr = INTEGER(x); width = sizeof(int); break; case REALSXP: ptr = REAL(x); width = sizeof(double); break; case CPLXSXP: ptr = COMPLEX(x); width = sizeof(Rcomplex); break; default: Rf_error("`x` has non-atomic type"); break; } if (widthptr) { *widthptr = width; } return ptr; } static void copy_columns_atomic(SEXP out, SEXP x, R_xlen_t nrow, R_xlen_t ncol) { SEXPTYPE type = TYPEOF(x); size_t eltsize; const char *src = get_data(x, &eltsize); size_t colsize = nrow * eltsize; for (R_xlen_t j = 0; j < ncol; j++) { SEXP col = Rf_allocVector(type, nrow); SET_VECTOR_ELT(out, j, col); char *dst = get_data(col, NULL); memcpy(dst, src, colsize); src += colsize; } } static void copy_columns_str(SEXP out, SEXP x, R_xlen_t nrow, R_xlen_t ncol) { R_xlen_t src = 0; for (R_xlen_t j = 0; j < ncol; j++) { SEXP col = Rf_allocVector(STRSXP, nrow); SET_VECTOR_ELT(out, j, col); for (R_xlen_t i = 0; i < nrow; i++) { SEXP elt = STRING_ELT(x, src); SET_STRING_ELT(col, i, elt); src++; } } } static void copy_columns_vec(SEXP out, SEXP x, R_xlen_t nrow, R_xlen_t ncol) { R_xlen_t src = 0; for (R_xlen_t j = 0; j < ncol; j++) { SEXP col = Rf_allocVector(VECSXP, nrow); SET_VECTOR_ELT(out, j, col); for (R_xlen_t i = 0; i < nrow; i++) { SEXP elt = VECTOR_ELT(x, src); SET_VECTOR_ELT(col, i, elt); src++; } } } static void copy_column_attributes(SEXP out, SEXP x, R_xlen_t ncol) { for (R_xlen_t j = 0; j < ncol; j++) { SEXP col = VECTOR_ELT(out, j); copy_most_attributes(col, x); Rf_setAttrib(col, R_DimSymbol, R_NilValue); } } static SEXP get_class(void) { SEXP cls; PROTECT(cls = Rf_allocVector(STRSXP, 1)); SET_STRING_ELT(cls, 0, Rf_mkChar("data.frame")); UNPROTECT(1); return cls; } SEXP tibble_matrixToDataFrame(SEXP x) { int nprot = 0; R_xlen_t nrow = 0, ncol = 0; get_dim(x, &nrow, &ncol); SEXP out; PROTECT(out = Rf_allocVector(VECSXP, ncol)); nprot++; switch (TYPEOF(x)) { case LGLSXP: case INTSXP: case REALSXP: case CPLXSXP: copy_columns_atomic(out, x, nrow, ncol); break; case STRSXP: copy_columns_str(out, x, nrow, ncol); break; case VECSXP: copy_columns_vec(out, x, nrow, ncol); break; default: Rf_error("data type not handled") ; break; } copy_column_attributes(out, x, ncol); Rf_setAttrib(out, R_NamesSymbol, get_names(x, ncol)); Rf_setAttrib(out, R_RowNamesSymbol, get_rownames(x, nrow)); Rf_setAttrib(out, R_ClassSymbol, get_class()); UNPROTECT(nprot); return out; } tibble/src/init.c0000644000176200001440000000100613217741055013413 0ustar liggesusers#include #include "tibble.h" #include // According to the C standard, names starting with underscore are reserved static const R_CallMethodDef CallEntries[] = { {"tibble_matrixToDataFrame", (DL_FUNC) &tibble_matrixToDataFrame, 1}, {"tibble_string_to_indices", (DL_FUNC) &tibble_string_to_indices, 1}, {NULL, NULL, 0} }; void R_init_tibble(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); } tibble/src/tibble.h0000644000176200001440000000026613217741055013725 0ustar liggesusers#ifndef TIBBLE_H #define TIBBLE_H #define R_NO_REMAP #include SEXP tibble_matrixToDataFrame(SEXP xSEXP); SEXP tibble_string_to_indices(SEXP x); #endif /* TIBBLE_H */ tibble/NAMESPACE0000644000176200001440000000427313204634213012736 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("$",tbl_df) S3method("[",tbl_df) S3method("[[",tbl_df) S3method("row.names<-",tbl_df) S3method(as.data.frame,tbl_df) S3method(as_data_frame,"NULL") S3method(as_data_frame,data.frame) S3method(as_data_frame,default) S3method(as_data_frame,list) S3method(as_data_frame,matrix) S3method(as_data_frame,table) S3method(as_data_frame,tbl_df) S3method(as_tibble,"NULL") S3method(as_tibble,data.frame) S3method(as_tibble,default) S3method(as_tibble,list) S3method(as_tibble,matrix) S3method(as_tibble,poly) S3method(as_tibble,table) S3method(as_tibble,tbl_df) S3method(as_tibble,ts) S3method(check_names_before_after,character) S3method(check_names_before_after,default) S3method(check_names_df,character) S3method(check_names_df,default) S3method(check_names_df,logical) S3method(check_names_df,numeric) S3method(format,tbl) S3method(format,tbl_df) S3method(format,trunc_mat) S3method(format_v,character) S3method(format_v,default) S3method(format_v,list) S3method(glimpse,data.frame) S3method(glimpse,default) S3method(glimpse,tbl) S3method(print,tbl) S3method(print,tbl_df) S3method(print,trunc_mat) S3method(quote_n,character) S3method(quote_n,default) S3method(tbl_sum,default) S3method(tbl_sum,tbl) S3method(type_sum,tbl_df) export(add_case) export(add_column) export(add_row) export(as.tibble) export(as_data_frame) export(as_tibble) export(column_to_rownames) export(data_frame) export(data_frame_) export(deframe) export(enframe) export(frame_data) export(frame_matrix) export(glimpse) export(has_name) export(has_rownames) export(is.tibble) export(is_tibble) export(is_vector_s3) export(knit_print.trunc_mat) export(lst) export(lst_) export(new_tibble) export(obj_sum) export(remove_rownames) export(repair_names) export(rowid_to_column) export(rownames_to_column) export(set_tidy_names) export(tbl_sum) export(tibble) export(tibble_) export(tidy_names) export(tribble) export(trunc_mat) export(type_sum) import(rlang) importFrom(methods,setOldClass) importFrom(pillar,is_vector_s3) importFrom(pillar,obj_sum) importFrom(pillar,style_subtle) importFrom(pillar,type_sum) importFrom(utils,head) importFrom(utils,str) importFrom(utils,tail) useDynLib(tibble, .registration = TRUE) tibble/NEWS.md0000644000176200001440000004165213217670766012640 0ustar liggesusers## tibble 1.4.1 (2017-12-24) ### New formatting The new pillar package is now responsible for formatting tibbles. Pillar will try to display as many columns as possible, if necessary truncating or shortening the output. Colored output highlights important information and guides the eye. The vignette in the tibble package describes how to adapt custom data types for optimal display in a tibble. ### New features - Make `add_case()` an alias for `add_row()` (#324, @LaDilettante). - `as_tibble()` gains `rownames` argument (#288, #289). - `as_tibble.matrix()` repairs column names. - Tibbles now support character subsetting (#312). - ``` `[.tbl_df`() ``` supports `drop = TRUE` and omits the warning if `j` is passed. The calls `df[i, j, drop = TRUE]` and `df[i, drop = TRUE]` are now compatible with data frames again (#307, #311). ### Bug fixes - Improved compatibility with remote data sources for `glimpse()` (#328). - Logical indexes are supported, a warning is raised if the length does not match the number of rows or 1 (#318). - Fixed width for word wrapping of the extra information (#301). - Prevent `add_column()` from dropping classes and attributes by removing the use of `cbind()`. Additionally this ensures that `add_column()` can be used with grouped data frames (#303, @DavisVaughan). - `add_column()` to an empty zero-row tibble with a variable of nonzero length now produces a correct error message (#319). ### Internal changes - Reexporting `has_name()` from rlang, instead of forwarding, to avoid warning when importing both rlang and tibble. - Compatible with R 3.1 (#323). - Remove Rcpp dependency (#313, @patperry). # tibble 1.3.4 (2017-08-21) ## Bug fixes - Values of length 1 in a `tibble()` call are recycled prior to evaluating subsequent arguments, improving consistency with `mutate()` (#213). - Recycling of values of length 1 in a `tibble()` call maintains their class (#284). - `add_row()` now always preserves the column data types of the input data frame the same way as `rbind()` does (#296). - `lst()` now again handles duplicate names, the value defined last is used in case of a clash. - Adding columns to zero-row data frames now also works when mixing lengths 1 and 0 in the new columns (#167). - The `validate` argument is now also supported in `as_tibble.tbl_df()`, with default to `FALSE` (#278). It must be passed as named argument, as in `as_tibble(validate = TRUE)`. ## Formatting - `format_v()` now always surrounds lists with `[]` brackets, even if their length is one. This affects `glimpse()` output for list columns (#106). - Factor levels are escaped when printing (#277). - Non-syntactic names are now also escaped in `glimpse()` (#280). - `tibble()` gives a consistent error message in the case of duplicate column names (#291). # tibble 1.3.3 (2017-05-27) ## Bug fixes - Added `format()` and `print()` methods for both `tbl` and `tbl_df` classes, to protect against malformed tibbles that inherit from `"tbl_df"` but not `"tbl"`, as created e.g. by `ungroup()` in dplyr 0.5.0 and earlier (#256, #263). - The column width for non-syntactic columns is computed correctly again (#258). - Printing a tibble doesn't apply quote escaping to list columns. - Fix error in `tidy_names(syntactic = TRUE, quiet = FALSE)` if not all names are fixed (#260, @imanuelcostigan). - Remove unused import declaration for assertthat. # tibble 1.3.1 (2017-05-16) ## Bug fixes - Subsetting zero columns no longer returns wrong number of rows (#241, @echasnovski). ## Interface changes - New `set_tidy_names()` and `tidy_names()`, a simpler version of `repair_names()` which works unchanged for now (#217). - New `rowid_to_column()` that adds a `rowid` column as first column and removes row names (#243, @barnettjacob). - The `all.equal.tbl_df()` method has been removed, calling `all.equal()` now forwards to `base::all.equal.data.frame()`. To compare tibbles ignoring row and column order, please use `dplyr::all_equal()` (#247). ## Formatting - Printing now uses `x` again instead of the Unicode multiplication sign, to avoid encoding issues (#216). - String values are now quoted when printing if they contain non-printable characters or quotes (#253). - The `print()`, `format()`, and `tbl_sum()` methods are now implemented for class `"tbl"` and not for `"tbl_df"`. This allows subclasses to use tibble's formatting facilities. The formatting of the header can be tweaked by implementing `tbl_sum()` for the subclass, which is expected to return a named character vector. The `print.tbl_df()` method is still implemented for compatibility with downstream packages, but only calls `NextMethod()`. - Own printing routine, not relying on `print.data.frame()` anymore. Now providing `format.tbl_df()` and full support for Unicode characters in names and data, also for `glimpse()` (#235). ## Misc - Improve formatting of error messages (#223). - Using `rlang` instead of `lazyeval` (#225, @lionel-), and `rlang` functions (#244). - `tribble()` now handles values that have a class (#237, @NikNakk). - Minor efficiency gains by replacing `any(is.na())` with `anyNA()` (#229, @csgillespie). - The `microbenchmark` package is now used conditionally (#245). - `pkgdown` website. # tibble 1.3.0 (2017-01-10) ## Bug fixes - Time series matrices (objects of class `mts` and `ts`) are now supported in `as_tibble()` (#184). - The `all_equal()` function (called by `all.equal.tbl_df()`) now forwards to `dplyr` and fails with a helpful message if not installed. Data frames with list columns cannot be compared anymore, and differences in the declared class (`data.frame` vs. `tbl_df`) are ignored. The `all.equal.tbl_df()` method gives a warning and forwards to `NextMethod()` if `dplyr` is not installed; call `all.equal(as.data.frame(...), ...)` to avoid the warning. This ensures consistent behavior of this function, regardless if `dplyr` is loaded or not (#198). ## Interface changes - Now requiring R 3.1.0 instead of R 3.1.3 (#189). - Add `as.tibble()` as an alias to `as_tibble()` (#160, @LaDilettante). - New `frame_matrix()`, similar to `frame_data()` but for matrices (#140, #168, @LaDilettante). - New `deframe()` as reverse operation to `enframe()` (#146, #214). - Removed unused dependency on `assertthat`. ## Features ### General - Keep column classes when adding row to empty tibble (#171, #177, @LaDilettante). - Singular and plural variants for error messages that mention a list of objects (#116, #138, @LaDilettante). - `add_column()` can add columns of length 1 (#162, #164, @LaDilettante). ### Input validation - An attempt to read or update a missing column now throws a clearer warning (#199). - An attempt to call `add_row()` for a grouped data frame results in a helpful error message (#179). ### Printing - Render Unicode multiplication sign as `x` if it cannot be represented in the current locale (#192, @ncarchedi). - Backtick `NA` names in printing (#206, #207, @jennybc). - `glimpse()` now uses `type_sum()` also for S3 objects (#185, #186, @holstius). - The `max.print` option is ignored when printing a tibble (#194, #195, @t-kalinowski). ## Documentation - Fix typo in `obj_sum` documentation (#193, @etiennebr). - Reword documentation for `tribble()` (#191, @kwstat). - Now explicitly stating minimum Rcpp version 0.12.3. ## Internal - Using registration of native routines. # tibble 1.2 (2016-08-26) ## Bug fixes - The `tibble.width` option is used for `glimpse()` only if it is finite (#153, @kwstat). - New `as_tibble.poly()` to support conversion of a `poly` object to a tibble (#110). - `add_row()` now correctly handles existing columns of type `list` that are not updated (#148). - `all.equal()` doesn't throw an error anymore if one of the columns is named `na.last`, `decreasing` or `method` (#107, @BillDunlap). ## Interface changes - New `add_column()`, analogously to `add_row()` (#99). - `print.tbl_df()` gains `n_extra` method and will have the same interface as `trunc_mat()` from now on. - `add_row()` and `add_column()` gain `.before` and `.after` arguments which indicate the row (by number) or column (by number or name) before or after which the new data are inserted. Updated or added columns cannot be named `.before` or `.after` (#99). - Rename `frame_data()` to `tribble()`, stands for "transposed tibble". The former is still available as alias (#132, #143). ## Features - `add_row()` now can add multiple rows, with recycling (#142, @jennybc). - Use multiply character `×` instead of `x` when printing dimensions (#126). Output tests had to be disabled for this on Windows. - Back-tick non-semantic column names on output (#131). - Use `dttm` instead of `time` for `POSIXt` values (#133), which is now used for columns of the `difftime` class. - Better output for 0-row results when total number of rows is unknown (e.g., for SQL data sources). ## Documentation - New object summary vignette that shows which methods to define for custom vector classes to be used as tibble columns (#151). - Added more examples for `print.tbl_df()`, now using data from `nycflights13` instead of `Lahman` (#121), with guidance to install `nycflights13` package if necessary (#152). - Minor changes in vignette (#115, @helix123). # tibble 1.1 (2016-07-01) Follow-up release. ## Breaking changes - `tibble()` is no longer an alias for `frame_data()` (#82). - Remove `tbl_df()` (#57). - `$` returns `NULL` if column not found, without partial matching. A warning is given (#109). - `[[` returns `NULL` if column not found (#109). ## Output - Reworked output: More concise summary (begins with hash `#` and contains more text (#95)), removed empty line, showing number of hidden rows and columns (#51). The trailing metadata also begins with hash `#` (#101). Presence of row names is indicated by a star in printed output (#72). - Format `NA` values in character columns as ``, like `print.data.frame()` does (#69). - The number of printed extra cols is now an option (#68, @lionel-). - Computation of column width properly handles wide (e.g., Chinese) characters, tests still fail on Windows (#100). - `glimpse()` shows nesting structure for lists and uses angle brackets for type (#98). - Tibbles with `POSIXlt` columns can be printed now, the text `` is shown as placeholder to encourage usage of `POSIXct` (#86). - `type_sum()` shows only topmost class for S3 objects. ## Error reporting - Strict checking of integer and logical column indexes. For integers, passing a non-integer index or an out-of-bounds index raises an error. For logicals, only vectors of length 1 or `ncol` are supported. Passing a matrix or an array now raises an error in any case (#83). - Warn if setting non-`NULL` row names (#75). - Consistently surround variable names with single quotes in error messages. - Use "Unknown column 'x'" as error message if column not found, like base R (#94). - `stop()` and `warning()` are now always called with `call. = FALSE`. ## Coercion - The `.Dim` attribute is silently stripped from columns that are 1d matrices (#84). - Converting a tibble without row names to a regular data frame does not add explicit row names. - `as_tibble.data.frame()` preserves attributes, and uses `as_tibble.list()` to calling overriden methods which may lead to endless recursion. ## New features - New `has_name()` (#102). - Prefer `tibble()` and `as_tibble()` over `data_frame()` and `as_data_frame()` in code and documentation (#82). - New `is.tibble()` and `is_tibble()` (#79). - New `enframe()` that converts vectors to two-column tibbles (#31, #74). - `obj_sum()` and `type_sum()` show `"tibble"` instead of `"tbl_df"` for tibbles (#82). - `as_tibble.data.frame()` gains `validate` argument (as in `as_tibble.list()`), if `TRUE` the input is validated. - Implement `as_tibble.default()` (#71, hadley/dplyr#1752). - `has_rownames()` supports arguments that are not data frames. ## Bug fixes - Two-dimensional indexing with `[[` works (#58, #63). - Subsetting with empty index (e.g., `x[]`) also removes row names. ## Documentation - Document behavior of `as_tibble.tbl_df()` for subclasses (#60). - Document and test that subsetting removes row names. ## Internal - Don't rely on `knitr` internals for testing (#78). - Fix compatibility with `knitr` 1.13 (#76). - Enhance `knit_print()` tests. - Provide default implementation for `tbl_sum.tbl_sql()` and `tbl_sum.tbl_grouped_df()` to allow `dplyr` release before a `tibble` release. - Explicit tests for `format_v()` (#98). - Test output for `NULL` value of `tbl_sum()`. - Test subsetting in all variants (#62). - Add missing test from dplyr. - Use new `expect_output_file()` from `testthat`. # Version 1.0 (2016-03-21) - Initial CRAN release - Extracted from `dplyr` 0.4.3 - Exported functions: - `tbl_df()` - `as_data_frame()` - `data_frame()`, `data_frame_()` - `frame_data()`, `tibble()` - `glimpse()` - `trunc_mat()`, `knit_print.trunc_mat()` - `type_sum()` - New `lst()` and `lst_()` create lists in the same way that `data_frame()` and `data_frame_()` create data frames (hadley/dplyr#1290). `lst(NULL)` doesn't raise an error (#17, @jennybc), but always uses deparsed expression as name (even for `NULL`). - New `add_row()` makes it easy to add a new row to data frame (hadley/dplyr#1021). - New `rownames_to_column()` and `column_to_rownames()` (#11, @zhilongjia). - New `has_rownames()` and `remove_rownames()` (#44). - New `repair_names()` fixes missing and duplicate names (#10, #15, @r2evans). - New `is_vector_s3()`. - Features - New `as_data_frame.table()` with argument `n` to control name of count column (#22, #23). - Use `tibble` prefix for options (#13, #36). - `glimpse()` now (invisibly) returns its argument (hadley/dplyr#1570). It is now a generic, the default method dispatches to `str()` (hadley/dplyr#1325). The default width is obtained from the `tibble.width` option (#35, #56). - `as_data_frame()` is now an S3 generic with methods for lists (the old `as_data_frame()`), data frames (trivial), matrices (with efficient C++ implementation) (hadley/dplyr#876), and `NULL` (returns a 0-row 0-column data frame) (#17, @jennybc). - Non-scalar input to `frame_data()` and `tibble()` (including lists) creates list-valued columns (#7). These functions return 0-row but n-col data frame if no data. - Bug fixes - `frame_data()` properly constructs rectangular tables (hadley/dplyr#1377, @kevinushey). - Minor modifications - Uses `setOldClass(c("tbl_df", "tbl", "data.frame"))` to help with S4 (hadley/dplyr#969). - `tbl_df()` automatically generates column names (hadley/dplyr#1606). - `tbl_df`s gain `$` and `[[` methods that are ~5x faster than the defaults, never do partial matching (hadley/dplyr#1504), and throw an error if the variable does not exist. `[[.tbl_df()` falls back to regular subsetting when used with anything other than a single string (#29). `base::getElement()` now works with tibbles (#9). - `all_equal()` allows to compare data frames ignoring row and column order, and optionally ignoring minor differences in type (e.g. int vs. double) (hadley/dplyr#821). Used by `all.equal()` for tibbles. (This package contains a pure R implementation of `all_equal()`, the `dplyr` code has identical behavior but is written in C++ and thus faster.) - The internals of `data_frame()` and `as_data_frame()` have been aligned, so `as_data_frame()` will now automatically recycle length-1 vectors. Both functions give more informative error messages if you are attempting to create an invalid data frame. You can no longer create a data frame with duplicated names (hadley/dplyr#820). Both functions now check that you don't have any `POSIXlt` columns, and tell you to use `POSIXct` if you do (hadley/dplyr#813). `data_frame(NULL)` raises error "must be a 1d atomic vector or list". - `trunc_mat()` and `print.tbl_df()` are considerably faster if you have very wide data frames. They will now also only list the first 100 additional variables not already on screen - control this with the new `n_extra` parameter to `print()` (hadley/dplyr#1161). The type of list columns is printed correctly (hadley/dplyr#1379). The `width` argument is used also for 0-row or 0-column data frames (#18). - When used in list-columns, S4 objects only print the class name rather than the full class hierarchy (#33). - Add test that `[.tbl_df()` does not change class (#41, @jennybc). Improve `[.tbl_df()` error message. - Documentation - Update README, with edits (#52, @bhive01) and enhancements (#54, @jennybc). - `vignette("tibble")` describes the difference between tbl_dfs and regular data frames (hadley/dplyr#1468). - Code quality - Test using new-style Travis-CI and AppVeyor. Full test coverage (#24, #53). Regression tests load known output from file (#49). - Renamed `obj_type()` to `obj_sum()`, improvements, better integration with `type_sum()`. - Internal cleanup. tibble/R/0000755000176200001440000000000013217667721011730 5ustar liggesuserstibble/R/strrep.R0000644000176200001440000000023013204634213013347 0ustar liggesusersif (getRversion() < "3.3.0") { strrep <- function(x, times) { map_chr( times, function(n) paste(rep(x, n), collapse = "") ) } } tibble/R/type-sum.r0000644000176200001440000000207113205250205013654 0ustar liggesusers#' Provide a succinct summary of an object #' #' `tbl_sum()` gives a brief textual description of a table-like object, #' which should include the dimensions, the data source, and possible grouping #' (for `dplyr`). The default implementation forwards to [pillar::obj_sum()]. #' @seealso [pillar::type_sum()], [pillar::is_vector_s3()] #' @param x Object to summarise #' @export tbl_sum <- function(x) UseMethod("tbl_sum", x) #' @export tbl_sum.default <- function(x) obj_sum(x) #' @export tbl_sum.tbl <- function(x) { c("A tibble" = dim_desc(x)) } dim_desc <- function(x) { dim <- dim(x) %||% length(x) format_dim <- map_chr(dim, big_mark) format_dim[is.na(dim)] <- "??" paste0(format_dim, collapse = spaces_around(mult_sign())) } size_sum <- function(x) { if (!is_vector_s3(x)) return("") paste0(" [", dim_desc(x), "]") } #' @importFrom pillar obj_sum #' @export pillar::obj_sum #' @importFrom pillar type_sum #' @export pillar::type_sum #' @export type_sum.tbl_df <- function(x) "tibble" #' @importFrom pillar is_vector_s3 #' @export pillar::is_vector_s3 tibble/R/check-names.R0000644000176200001440000000367013204634213014221 0ustar liggesuserscheck_names_df <- function(j, ...) UseMethod("check_names_df") #' @export check_names_df.default <- function(j, ...) { stopc("Unsupported index type: ", class(j)[[1L]]) } #' @export check_names_df.character <- function(j, x) { check_names_before_after.character(j, names(x)) } #' @export check_names_df.numeric <- function(j, x) { check_needs_no_dim(j) if (anyNA(j)) { stopc("NA column indexes not supported") } non_integer <- (j != trunc(j)) if (any(non_integer)) { stopc(pluralise_msg("Column index(es) must be integer, not ", j[non_integer])) } neg_too_small <- (j < -length(x)) if (any(neg_too_small)) { stopc(pluralise_msg( paste0("Column index(es) must be at least ", -length(x), " if negative, not "), j[neg_too_small] )) } pos_too_large <- (j > length(x)) if (any(pos_too_large)) { stopc(pluralise_msg( paste0("Column index(es) must be at most ", length(x), " if positive, not "), j[pos_too_large] )) } seq_along(x)[j] } #' @export check_names_df.logical <- function(j, x) { check_needs_no_dim(j) if (!(length(j) %in% c(1L, length(x)))) { stopc( "Length of logical index vector must be 1 or ", length(x), " (the number of rows), not ", length(j) ) } if (anyNA(j)) { stopc("NA column indexes not supported") } seq_along(x)[j] } check_needs_no_dim <- function(j) { if (needs_dim(j)) { stopc("Can't use matrix or array for column indexing") } } # check_names_before_after ------------------------------------------------ check_names_before_after <- function(j, ...) UseMethod("check_names_before_after") #' @export check_names_before_after.default <- function(j, ...) { j } #' @export check_names_before_after.character <- function(j, names) { check_needs_no_dim(j) pos <- safe_match(j, names) if (anyNA(pos)) { unknown_names <- j[is.na(pos)] stopc(pluralise_msg("Column(s) ", unknown_names), " not found") } pos } tibble/R/has-name.R0000644000176200001440000000003313204634213013522 0ustar liggesusers#' @export rlang::has_name tibble/R/enframe.R0000644000176200001440000000170013204634213013450 0ustar liggesusers#' Converting atomic vectors to data frames, and vice versa #' #' `enframe()` converts named atomic vectors or lists to two-column #' data frames. #' For unnamed vectors, the natural sequence is used as name column. #' #' @param x An atomic vector (for `enframe()`) or a data frame (for `deframe()`) #' @param name,value Names of the columns that store the names and values #' #' @return A [tibble] #' @export #' #' @examples #' enframe(1:3) #' enframe(c(a = 5, b = 7)) enframe <- function(x, name = "name", value = "value") { if (is_null(names(x))) { df <- tibble(seq_along(x), x) } else { df <- tibble(names(x), unname(x)) } names(df) <- c(name, value) df } #' @rdname enframe #' @description #' `deframe()` converts two-column data frames to a named vector or list, #' using the first column as name and the second column as value. #' @export deframe <- function(x) { value <- x[[2L]] name <- x[[1L]] names(value) <- name value } tibble/R/new.R0000644000176200001440000000571413204634213012635 0ustar liggesusers#' Constructor #' #' Creates a subclass of a tibble. #' This function is mostly useful for package authors that implement subclasses #' of a tibble, like \pkg{sf} or \pkg{tibbletime}. #' #' @param x A tibble-like object #' @param ... Passed on to [structure()] #' @param nrow The number of rows, guessed from the data by default #' @param subclass Subclasses to assign to the new object, default: none #' @export #' @examples #' new_tibble(list(a = 1:3, b = 4:6)) #' #' # One particular situation where the nrow argument is essential: #' new_tibble(list(), nrow = 150, subclass = "my_tibble") #' #' # It's safest to always pass it along: #' new_tibble(list(a = 1:3, b = 4:6), nrow = 3) #' #' \dontrun{ #' # All columns must be the same length: #' new_tibble(list(a = 1:3, b = 4.6)) #' #' # The length must be consistent with the nrow argument if available: #' new_tibble(list(a = 1:3, b = 4:6), nrow = 2) #' } new_tibble <- function(x, ..., nrow = NULL, subclass = NULL) { #' @details #' `x` must be a named (or empty) list, but the names are not currently #' checked for correctness. stopifnot(is.list(x)) if (length(x) == 0) names(x) <- character() stopifnot(has_nonnull_names(x)) #' @details #' The `...` argument allows adding more attributes to the subclass. x <- update_tibble_attrs(x, ...) #' @details #' The `row.names` attribute will be computed from the `nrow` argument, #' overriding any existing attribute of this name in `x` or in the `...` #' arguments. #' If `nrow` is `NULL`, the number of rows will be guessed from the data. if (is.null(nrow)) nrow <- guess_nrow(x) attr(x, "row.names") <- .set_row_names(nrow) #' The `new_tibble()` constructor makes sure that the `row.names` attribute #' is consistent with the data before returning. validate_nrow(x) #' @details #' The `class` attribute of the returned object always consists of #' `c("tbl_df", "tbl", "data.frame")`. If the `subclass` argument is set, #' it will be prepended to that list of classes. class(x) <- c(subclass, "tbl_df", "tbl", "data.frame") x } update_tibble_attrs <- function(x, ...) { # Can't use structure() here because it breaks the row.names attribute attribs <- list(...) # reduce2() is not in the purrr compat layer nested_attribs <- map2(names(attribs), attribs, function(name, value) set_names(list(value), name)) x <- reduce( .init = x, nested_attribs, function(x, attr) { if (!is.null(attr[[1]])) { attr(x, names(attr)) <- attr[[1]] } x } ) x } guess_nrow <- function(x) { if (!is.null(.row_names_info(x, 0L))) .row_names_info(x, 2L) else if (length(x) == 0) 0L else NROW(x[[1L]]) } validate_nrow <- function(x) { # Validate column lengths, don't recycle lengths <- map_int(x, NROW) first <- .row_names_info(x, 2L) bad_len <- lengths != first if (any(bad_len)) { invalid_df_msg( paste0("must be length ", first, ", not "), x, bad_len, lengths[bad_len] ) } invisible(x) } tibble/R/exports.R0000644000176200001440000000024713204634213013544 0ustar liggesusersmatrixToDataFrame <- function(x) { .Call(`tibble_matrixToDataFrame`, x) } string_to_indices <- function(x) { .Call(`tibble_string_to_indices`, as.character(x)) } tibble/R/utils-format.r0000644000176200001440000002040713204634213014526 0ustar liggesusers#' Tools for describing matrices #' #' @param x Object to show. #' @param n Number of rows to show. If `NULL`, the default, will print #' all rows if less than option `tibble.print_max`. Otherwise, will #' print `tibble.print_min` rows. #' @param width Width of text output to generate. This defaults to NULL, which #' means use `getOption("tibble.width")` or (if also NULL) #' `getOption("width")`; the latter displays only the columns that #' fit on one screen. You can also set `options(tibble.width = Inf)` to #' override this default and always print all columns. #' @param n_extra Number of extra columns to print abbreviated information for, #' if the width is too small for the entire tibble. If `NULL`, the #' default, will print information about at most `tibble.max_extra_cols` #' extra columns. #' @seealso \link{tibble-package} #' @keywords internal #' @examples #' trunc_mat(mtcars) #' #' print(as_tibble(mtcars)) #' print(as_tibble(mtcars), n = 1) #' print(as_tibble(mtcars), n = 3) #' print(as_tibble(mtcars), n = 100) #' #' if (!requireNamespace("nycflights13", quietly = TRUE)) #' stop("Please install the nycflights13 package to run the rest of this example") #' #' print(nycflights13::flights, n_extra = 2) #' print(nycflights13::flights, width = Inf) #' @name formatting NULL #' @export #' @rdname formatting trunc_mat <- function(x, n = NULL, width = NULL, n_extra = NULL) { rows <- nrow(x) if (is_null(n)) { if (is.na(rows) || rows > tibble_opt("print_max")) { n <- tibble_opt("print_min") } else { n <- rows } } n_extra <- n_extra %||% tibble_opt("max_extra_cols") df <- as.data.frame(head(x, n)) shrunk <- shrink_mat(df, rows, n, star = has_rownames(x)) trunc_info <- list( width = width, rows_total = rows, rows_min = nrow(df), n_extra = n_extra, summary = tbl_sum(x) ) structure( c(shrunk, trunc_info), class = c(paste0("trunc_mat_", class(x)), "trunc_mat") ) } shrink_mat <- function(df, rows, n, star) { df <- remove_rownames(df) if (is.na(rows)) { needs_dots <- (nrow(df) >= n) } else { needs_dots <- (rows > n) } if (needs_dots) { rows_missing <- rows - n } else { rows_missing <- 0L } mcf <- pillar::colonnade( df, has_row_id = if (star) "*" else TRUE, needs_dots = needs_dots ) list(mcf = mcf, rows_missing = rows_missing) } #' @importFrom pillar style_subtle #' @export format.trunc_mat <- function(x, width = NULL, ...) { if (is.null(width)) { width <- x$width } named_header <- format_header(x) if (all(names2(named_header) == "")) { header <- named_header } else { header <- paste0( justify( paste0(names2(named_header), ":"), right = FALSE, space = "\u00a0" ), # We add a space after the NBSP inserted by justify() # so that wrapping occurs at the right location for very narrow outputs " ", named_header ) } comment <- format_comment(header, width = width) squeezed <- pillar::squeeze(x$mcf, width = width) mcf <- format_body(squeezed) footer <- format_comment(pre_dots(format_footer(x, squeezed)), width = width) c(style_subtle(comment), mcf, style_subtle(footer)) } # Needs to be defined in package code: r-lib/pkgload#85 print_without_body <- function(x, ...) { mockr::with_mock( format_body = function(x, ...) { paste0("") }, print(x, ...) ) } #' @export print.trunc_mat <- function(x, ...) { cat_line(format(x, ...)) invisible(x) } format_header <- function(x) { x$summary } format_body <- function(x) { format(x) } format_footer <- function(x, squeezed_colonnade) { extra_rows <- format_footer_rows(x) extra_cols <- format_footer_cols(x, pillar::extra_cols(squeezed_colonnade)) extra <- c(extra_rows, extra_cols) if (length(extra) >= 1) { extra[[1]] <- paste0("with ", extra[[1]]) extra[-1] <- map_chr(extra[-1], function(ex) paste0("and ", ex)) collapse(extra) } else { character() } } format_footer_rows <- function(x) { if (length(x$mcf) != 0) { if (is.na(x$rows_missing)) { "more rows" } else if (x$rows_missing > 0) { paste0(big_mark(x$rows_missing), pluralise_n(" more row(s)", x$rows_missing)) } } else if (is.na(x$rows_total) && x$rows_min > 0) { paste0("at least ", big_mark(x$rows_min), pluralise_n(" row(s) total", x$rows_min)) } } format_footer_cols <- function(x, extra_cols) { if (length(extra_cols) == 0) return(NULL) vars <- format_extra_vars(extra_cols, x$n_extra) paste0( big_mark(length(extra_cols)), " ", if (!identical(x$rows_total, 0L) && x$rows_min > 0) "more ", pluralise("variable(s)", extra_cols), vars ) } format_extra_vars <- function(extra_cols, n_extra) { if (n_extra > 0) { if (n_extra < length(extra_cols)) { extra_cols <- c(extra_cols[seq_len(n_extra)], "...") } paste0(": ", collapse(extra_cols)) } else { "" } } format_comment <- function(x, width) { if (length(x) == 0L) return(character()) map_chr(x, wrap, prefix = "# ", width = min(width, getOption("width"))) } pre_dots <- function(x) { if (length(x) > 0) { paste0("... ", x) } else { character() } } justify <- function(x, right = TRUE, space = " ") { if (length(x) == 0L) return(character()) width <- nchar_width(x) max_width <- max(width) spaces_template <- paste(rep(space, max_width), collapse = "") spaces <- map_chr(max_width - width, substr, x = spaces_template, start = 1L) if (right) { paste0(spaces, x) } else { paste0(x, spaces) } } #' knit_print method for trunc mat #' @keywords internal #' @export knit_print.trunc_mat <- function(x, options) { header <- format_header(x) if (length(header) > 0L) { header[names2(header) != ""] <- paste0(names2(header), ": ", header) summary <- header } else { summary <- character() } squeezed <- pillar::squeeze(x$mcf, x$width) kable <- format_knitr_body(squeezed) extra <- format_footer(x, squeezed) if (length(extra) > 0) { extra <- wrap("(", collapse(extra), ")", width = x$width) } else { extra <- "\n" } res <- paste(c("", "", summary, "", kable, "", extra), collapse = "\n") knitr::asis_output(crayon::strip_style(res), cacheable = TRUE) } format_knitr_body <- function(x) { knitr::knit_print(x) } format_factor <- function(x) { format_character(as.character(x)) } format_character <- function(x) { res <- quote_escaped(x) res[is.na(x)] <- "" res } quote_escaped <- function(x) { res <- encodeString(x, quote = '"') plain <- which(res == paste0('"', x, '"')) res[plain] <- x[plain] res } # function for the thousand separator, # returns "," unless it's used for the decimal point, in which case returns "." big_mark <- function(x, ...) { mark <- if (identical(getOption("OutDec"), ",")) "." else "," formatC(x, big.mark = mark, ...) } tibble_width <- function(width) { if (!is_null(width)) return(width) width <- tibble_opt("width") if (!is_null(width)) return(width) getOption("width") } tibble_glimpse_width <- function(width) { if (!is_null(width)) return(width) width <- tibble_opt("width") if (!is_null(width) && is.finite(width)) return(width) getOption("width") } pluralise_msg <- function(message, objects) { paste0(pluralise(message, objects), format_n(objects)) } pluralise <- function(message, objects) { pluralise_n(message, length(objects)) } pluralise_n <- function(message, n) { stopifnot(n >= 0) if (n == 1) { # strip [, unless there is space in between message <- gsub("\\[([^\\] ]+)\\]", "\\1", message, perl = TRUE) # remove ( and its content, unless there is space in between message <- gsub("\\([^\\) ]+\\)", "", message, perl = TRUE) } else { # strip (, unless there is space in between message <- gsub("\\(([^\\) ]+)\\)", "\\1", message, perl = TRUE) # remove [ and its content, unless there is space in between message <- gsub("\\[[^\\] ]+\\]\\s*", "", message, perl = TRUE) } message } mult_sign <- function() { "x" } spaces_around <- function(x) { paste0(" ", x, " ") } format_n <- function(x) collapse(quote_n(x)) quote_n <- function(x) UseMethod("quote_n") #' @export quote_n.default <- function(x) as.character(x) #' @export quote_n.character <- function(x) tick(x) collapse <- function(x) paste(x, collapse = ", ") tibble/R/tribble.R0000644000176200001440000001047413204634213013466 0ustar liggesusers#' Row-wise tibble creation #' #' Create [tibble]s using an easier to read row-by-row layout. #' This is useful for small tables of data where readability is #' important. Please see \link{tibble-package} for a general introduction. #' #' `frame_data()` is an older name for `tribble()`. It will eventually #' be phased out. #' #' @param ... Arguments specifying the structure of a `tibble`. #' Variable names should be formulas, and may only appear before the data. #' @return A [tibble]. #' @export #' @examples #' tribble( #' ~colA, ~colB, #' "a", 1, #' "b", 2, #' "c", 3 #' ) #' #' # tribble will create a list column if the value in any cell is #' # not a scalar #' tribble( #' ~x, ~y, #' "a", 1:3, #' "b", 4:6 #' ) tribble <- function(...) { data <- extract_frame_data_from_dots(...) turn_frame_data_into_tibble(data$frame_names, data$frame_rest) } #' @export #' @rdname tribble #' @usage NULL frame_data <- tribble #' Row-wise matrix creation #' #' Create matrices laying out the data in rows, similar to #' `matrix(..., byrow = TRUE)`, with a nicer-to-read syntax. #' This is useful for small matrices, e.g. covariance matrices, where readability #' is important. The syntax is inspired by [tribble()]. #' #' @param ... Arguments specifying the structure of a `frame_matrix`. #' Column names should be formulas, and may only appear before the data. #' @return A [matrix]. #' @export #' @examples #' frame_matrix( #' ~col1, ~col2, #' 1, 3, #' 5, 2 #' ) frame_matrix <- function(...) { data <- extract_frame_data_from_dots(...) turn_frame_data_into_frame_matrix(data$frame_names, data$frame_rest) } extract_frame_data_from_dots <- function(...) { dots <- list(...) # Extract the names. frame_names <- extract_frame_names_from_dots(dots) # Extract the data if (length(frame_names) == 0 && length(dots) != 0) { stopc("Expected at least one column name; e.g. `~name`") } frame_rest <- dots[-seq_along(frame_names)] if (length(frame_rest) == 0L) { # Can't decide on type in absence of data -- use logical which is # coercible to all types frame_rest <- logical() } validate_rectangular_shape(frame_names, frame_rest) list(frame_names = frame_names, frame_rest = frame_rest) } extract_frame_names_from_dots <- function(dots) { frame_names <- character() for (i in seq_along(dots)) { el <- dots[[i]] if (!is.call(el)) break if (!identical(el[[1]], as.name("~"))) break if (length(el) != 2) { stopc("Expected a column name with a single argument; e.g. `~name`") } candidate <- el[[2]] if (!(is.symbol(candidate) || is.character(candidate))) { stopc( "Expected a symbol or string denoting a column name, not ", friendly_type(type_of(candidate)) ) } frame_names <- c(frame_names, as.character(el[[2]])) } frame_names } validate_rectangular_shape <- function(frame_names, frame_rest) { if (length(frame_names) == 0 && length(frame_rest) == 0) return() # Figure out the associated number of rows and number of columns, # and validate that the supplied formula produces a rectangular # structure. if (length(frame_rest) %% length(frame_names) != 0) { stopc( sprintf( "invalid specification: had %s elements and %s columns", length(frame_rest), length(frame_names) ) ) } } turn_frame_data_into_tibble <- function(names, rest) { frame_mat <- matrix(rest, ncol = length(names), byrow = TRUE) frame_col <- turn_matrix_into_column_list(frame_mat) # Create a tbl_df and return it names(frame_col) <- names as_tibble(frame_col) } turn_matrix_into_column_list <- function(frame_mat) { frame_col <- vector("list", length = ncol(frame_mat)) # if a frame_mat's col is a list column, keep it unchanged (does not unlist) for (i in seq_len(ncol(frame_mat))) { col <- frame_mat[, i] if (some(col, needs_list_col) || !inherits(col, "list")) { frame_col[[i]] <- col } else { frame_col[[i]] <- invoke(c, col) } } return(frame_col) } turn_frame_data_into_frame_matrix <- function(names, rest) { if (some(rest, needs_list_col)) { stopc("Can't use list columns in `frame_matrix()`") } frame_ncol <- length(names) frame_mat <- matrix(unlist(rest), ncol = frame_ncol, byrow = TRUE) colnames(frame_mat) <- names frame_mat } tibble/R/glimpse.R0000644000176200001440000000555113204634213013503 0ustar liggesusers#' Get a glimpse of your data. #' #' This is like a transposed version of print: columns run down the page, #' and data runs across. This makes it possible to see every column in #' a data frame. It's a little like [str()] applied to a data frame #' but it tries to show you as much data as possible. (And it always shows #' the underlying data, even when applied to a remote data source.) #' #' @section S3 methods: #' `glimpse` is an S3 generic with a customised method for `tbl`s and #' `data.frames`, and a default method that calls [str()]. #' #' @param x An object to glimpse at. #' @param width Width of output: defaults to the setting of the option #' `tibble.width` (if finite) or the width of the console. #' @param ... Other arguments passed on to individual methods. #' @return x original x is (invisibly) returned, allowing `glimpse()` to be #' used within a data pipe line. #' @export #' @examples #' glimpse(mtcars) #' #' if (!requireNamespace("nycflights13", quietly = TRUE)) #' stop("Please install the nycflights13 package to run the rest of this example") #' #' glimpse(nycflights13::flights) glimpse <- function(x, width = NULL, ...) { UseMethod("glimpse") } #' @export glimpse.tbl <- function(x, width = NULL, ...) { width <- tibble_glimpse_width(width) if (!is.finite(width)) { stopc("`width` must be finite") } cat_line("Observations: ", big_mark(nrow(x))) if (ncol(x) == 0) return(invisible()) cat_line("Variables: ", big_mark(ncol(x))) # this is an overestimate, but shouldn't be too expensive. # every type needs at least three characters: "x, " rows <- as.integer(width / 3) df <- as.data.frame(head(x, rows)) var_types <- map_chr(df, type_sum) ticked_names <- tick_non_syntactic(names(df)) var_names <- paste0("$ ", justify(ticked_names, right = FALSE), " <", var_types, "> ") data_width <- width - nchar(var_names) - 2 formatted <- map_chr(df, function(x) collapse(format_v(x))) truncated <- str_trunc(formatted, data_width) cat_line(var_names, truncated) invisible(x) } #' @export glimpse.data.frame <- glimpse.tbl #' @export #' @importFrom utils str glimpse.default <- function(x, width = NULL, max.level = 3, ...) { str(x, width = tibble_width(width), max.level = max.level, ...) invisible(x) } str_trunc <- function(x, max_width) { width <- nchar(x) for (i in seq_along(x)) { if (width[i] <= max_width[i]) next x[i] <- paste0(substr(x[i], 1, max_width[i] - 3), "...") } x } format_v <- function(x) UseMethod("format_v") #' @export format_v.default <- function(x) format(x, trim = TRUE, justify = "none") #' @export format_v.list <- function(x) { out <- map(x, format_v) atomic <- map_int(out, length) == 1L out <- map_chr(out, collapse) out[!atomic] <- paste0("<", out[!atomic], ">") paste0("[", collapse(out), "]") } #' @export format_v.character <- function(x) encodeString(x, quote = '"') tibble/R/utils.r0000644000176200001440000000253113204634213013236 0ustar liggesusers has_dim <- function(x) { length(dim(x)) > 0L || has_nonnull_names(x) } needs_dim <- function(x) { length(dim(x)) > 1L } has_null_names <- function(x) { is.null(names(x)) } has_nonnull_names <- function(x) { !has_null_names(x) } set_class <- `class<-` is_1d <- function(x) { # dimension check is for matrices and data.frames is_vector(x) && !needs_dim(x) } strip_dim <- function(x) { # Careful update only if necessary, to avoid copying which is checked by # the "copying" test in dplyr if (is_atomic(x) && has_dim(x)) { dim(x) <- NULL } x } needs_list_col <- function(x) { is_list(x) || length(x) != 1L } # Work around bug in R 3.3.0 safe_match <- function(x, table) { # nocov start if (getRversion() == "3.3.0") { match(x, table, incomparables = character()) } else { match(x, table) } # nocov end } stopc <- function(...) { abort(paste0(...)) } warningc <- function(...) { warn(paste0(...)) } nchar_width <- function(x) { nchar(x, type = "width") } cat_line <- function(...) { cat(paste0(..., "\n"), sep = "") } is_syntactic <- function(x) { ret <- make.names(x) == x ret[is.na(x)] <- FALSE ret } tick_non_syntactic <- function(x) { needs_ticks <- !is_syntactic(x) x[needs_ticks] <- tick(x[needs_ticks]) x } tick <- function(x) { x[is.na(x)] <- "NA" encodeString(x, quote = "`") } tibble/R/rownames.R0000644000176200001440000000522313204634213013672 0ustar liggesusers#' Tools for working with row names #' #' While a tibble can have row names (e.g., when converting from a regular data #' frame), they are removed when subsetting with the `[` operator. #' A warning will be raised when attempting to assign non-`NULL` row names #' to a tibble. #' Generally, it is best to avoid row names, because they are basically a #' character column with different semantics to every other column. These #' functions allow to you detect if a data frame has row names #' (`has_rownames()`), remove them (`remove_rownames()`), or convert #' them back-and-forth between an explicit column (`rownames_to_column()` #' and `column_to_rownames()`). #' Also included is `rowid_to_column()` which #' adds a column at the start of the dataframe of ascending sequential row #' ids starting at 1. Note that this will remove any existing row names. #' #' In the printed output, the presence of row names is indicated by a star just #' above the row numbers. #' #' @param df A data frame #' @param var Name of column to use for rownames. #' @examples #' has_rownames(mtcars) #' has_rownames(iris) #' has_rownames(remove_rownames(mtcars)) #' #' head(rownames_to_column(mtcars)) #' #' mtcars_tbl <- as_tibble(rownames_to_column(mtcars)) #' mtcars_tbl #' column_to_rownames(as.data.frame(mtcars_tbl)) #' @name rownames NULL #' @export #' @rdname rownames has_rownames <- function(df) { .row_names_info(df) > 0L } #' @export #' @rdname rownames remove_rownames <- function(df) { stopifnot(is.data.frame(df)) rownames(df) <- NULL df } #' @export #' @rdname rownames rownames_to_column <- function(df, var = "rowname") { stopifnot(is.data.frame(df)) if (has_name(df, var)) { stopc("Column `", var, "` already exists") } new_df <- add_column(df, !! var := rownames(df), .before = 1) remove_rownames(new_df) } #' @export #' @rdname rownames rowid_to_column <- function(df, var = "rowid") { stopifnot(is.data.frame(df)) if (has_name(df, var)) { stopc("Column `", var, "` already exists") } new_df <- add_column(df, !! var := seq_len(nrow(df)), .before = 1) remove_rownames(new_df) } #' @rdname rownames #' @export column_to_rownames <- function(df, var = "rowname") { stopifnot(is.data.frame(df)) if (has_rownames(df)) { stopc("`df` already has row names") } if (!has_name(df, var)) { stopc("Column `num2` not found") } rownames(df) <- df[[var]] df[[var]] <- NULL df } #' @export `row.names<-.tbl_df` <- function(x, value) { if (!is_null(value)) { warningc("Setting row names on a tibble is deprecated.") } NextMethod() } raw_rownames <- function(x) { .row_names_info(x, 0L) %||% .set_row_names(.row_names_info(x, 2L)) } tibble/R/tibble.R0000644000176200001440000000716413204634213013306 0ustar liggesusers#' Build a data frame or list. #' #' @description #' `tibble()` is a trimmed down version of [data.frame()] that: #' #' * Never coerces inputs (i.e. strings stay as strings!). #' * Never adds `row.names`. #' * Never munges column names. #' * Only recycles length 1 inputs. #' * Evaluates its arguments lazily and in order. #' * Adds `tbl_df` class to output. #' * Automatically adds column names. #' #' #' @param ... A set of name-value pairs. Arguments are evaluated sequentially, #' so you can refer to previously created variables. These arguments are #' processed with [rlang::quos()] and support unquote via `!!` and #' unquote-splice via `!!!`. #' @param xs A list of unevaluated expressions created with `~`, #' [quote()], or (deprecated) [lazyeval::lazy()]. #' @seealso [as_tibble()] to turn an existing list into #' a data frame. #' @export #' @examples #' a <- 1:5 #' tibble(a, b = a * 2) #' tibble(a, b = a * 2, c = 1) #' tibble(x = runif(10), y = x * 2) #' #' lst(n = 5, x = runif(n)) #' #' # tibble never coerces its inputs #' str(tibble(letters)) #' str(tibble(x = list(diag(1), diag(2)))) #' #' # or munges column names #' tibble(`a + b` = 1:5) #' #' # You can splice-unquote a list of quotes and formulas #' tibble(!!! list(x = rlang::quo(1:10), y = quote(x * 2))) #' #' # data frames can only contain 1d atomic vectors and lists #' # and can not contain POSIXlt #' \dontrun{ #' tibble(x = tibble(1, 2, 3)) #' tibble(y = strptime("2000/01/01", "%x")) #' } tibble <- function(...) { xs <- quos(..., .named = TRUE) as_tibble(lst_quos(xs, expand = TRUE)) } #' @export #' @rdname tibble tibble_ <- function(xs) { xs <- compat_lazy_dots(xs, caller_env()) tibble(!!! xs) } #' @export #' @rdname tibble #' @usage NULL data_frame <- tibble #' @export #' @rdname tibble #' @usage NULL data_frame_ <- tibble_ #' Test if the object is a tibble. #' #' @param x An object #' @return `TRUE` if the object inherits from the `tbl_df` class. #' @export is.tibble <- function(x) { "tbl_df" %in% class(x) } #' @rdname is.tibble #' @export is_tibble <- is.tibble # Validity checks -------------------------------------------------------------- check_tibble <- function(x) { # Names names_x <- names2(x) bad_name <- is.na(names_x) | names_x == "" if (any(bad_name)) { invalid_df("must be named", x, which(bad_name)) } dups <- duplicated(names_x) if (any(dups)) { invalid_df("must have [a] unique name(s)", x, dups) } # Types is_1d <- map_lgl(x, is_1d) if (any(!is_1d)) { invalid_df("must be [a] 1d atomic vector(s) or [a] list(s)", x, !is_1d) } x[] <- map(x, strip_dim) posixlt <- map_lgl(x, inherits, "POSIXlt") if (any(posixlt)) { invalid_df("[is](are) [a] date(s)/time(s) and must be stored as POSIXct, not POSIXlt", x, posixlt) } x } recycle_columns <- function(x) { if (length(x) == 0) { return(x) } # Validate column lengths, allow recycling lengths <- map_int(x, NROW) max <- max(c(lengths[lengths != 1L], 0L)) bad_len <- lengths != 1L & lengths != max if (any(bad_len)) { invalid_df_msg( paste0("must be length 1 or ", max, ", not "), x, bad_len, lengths[bad_len] ) } short <- lengths == 1 if (max > 1L && any(short)) { x[short] <- map(x[short], rep, max) } x } invalid_df <- function(problem, df, vars) { if (is.logical(vars)) { vars <- names(df)[vars] } stopc( pluralise_msg("Column(s) ", vars), " ", pluralise(problem, vars) ) } invalid_df_msg <- function(problem, df, vars, extra) { if (is.logical(vars)) { vars <- names(df)[vars] } stopc( pluralise_msg("Column(s) ", vars), " ", pluralise_msg(problem, extra) ) } tibble/R/as_tibble.R0000644000176200001440000001121313204634213013757 0ustar liggesusers#' Coerce lists and matrices to data frames. #' #' [as.data.frame()] is effectively a thin wrapper around `data.frame`, #' and hence is rather slow (because it calls [data.frame()] on each element #' before [cbind]ing together). `as_tibble` is a new S3 generic #' with more efficient methods for matrices and data frames. #' #' This is an S3 generic. tibble includes methods for data frames (adds tbl_df #' classes), tibbles (returns unchanged input), lists, matrices, and tables. #' Other types are first coerced via `as.data.frame()` with #' `stringsAsFactors = FALSE`. #' #' `as_data_frame` and `as.tibble` are aliases. #' #' @param x A list. Each element of the list must have the same length. #' @param ... Other arguments passed on to individual methods. #' @param validate When `TRUE`, verifies that the input is a valid data #' frame (i.e. all columns are named, and are 1d vectors or lists). You may #' want to suppress this when you know that you already have a valid data #' frame and you want to save some time, or to explicitly enable it #' if you have a tibble that you want to re-check. #' @param rownames If `NULL`, remove row names (default for matrices, may become #' default for data frames in the future). If `NA`, keep row names (current #' default for data frames). Otherwise, the name of the new column that will #' contain the existing row names. #' @export #' @examples #' l <- list(x = 1:500, y = runif(500), z = 500:1) #' df <- as_tibble(l) #' #' m <- matrix(rnorm(50), ncol = 5) #' colnames(m) <- c("a", "b", "c", "d", "e") #' df <- as_tibble(m) #' #' # as_tibble is considerably simpler than as.data.frame #' # making it more suitable for use when you have things that are #' # lists #' \dontrun{ #' if (requireNamespace("microbenchmark", quiet = TRUE)) { #' l2 <- replicate(26, sample(letters), simplify = FALSE) #' names(l2) <- letters #' microbenchmark::microbenchmark( #' as_tibble(l2, validate = FALSE), #' as_tibble(l2), #' as.data.frame(l2) #' ) #' } #' #' if (requireNamespace("microbenchmark", quiet = TRUE)) { #' m <- matrix(runif(26 * 100), ncol = 26) #' colnames(m) <- letters #' microbenchmark::microbenchmark( #' as_tibble(m), #' as.data.frame(m) #' ) #' } #' } as_tibble <- function(x, ...) { UseMethod("as_tibble") } #' @export #' @rdname as_tibble as_tibble.tbl_df <- function(x, ..., validate = FALSE, rownames = NULL) { if (validate) return(NextMethod()) x } #' @export #' @rdname as_tibble as_tibble.data.frame <- function(x, validate = TRUE, ..., rownames = NA) { old_rownames <- raw_rownames(x) result <- list_to_tibble(x, validate) if (is.null(rownames)) { result } else if (is.na(rownames)) { attr(result, "row.names") <- old_rownames result } else { add_column(result, !! rownames := old_rownames, .before = 1L) } } #' @export #' @rdname as_tibble as_tibble.list <- function(x, validate = TRUE, ...) { if (length(x) == 0) { list_to_tibble(repair_names(list()), validate = FALSE) } else { list_to_tibble(x, validate) } } list_to_tibble <- function(x, validate) { # this is to avoid any method dispatch that may happen when processing x x <- unclass(x) if (validate) { x <- check_tibble(x) } else if (has_null_names(x)) { x <- set_names(x, rep_along(x, "")) } x <- recycle_columns(x) new_tibble(x) } #' @export #' @rdname as_tibble as_tibble.matrix <- function(x, ..., rownames = NULL) { as_tibble(repair_names(matrixToDataFrame(x)), ..., rownames = rownames) } #' @export as_tibble.poly <- function(x, ...) { as_tibble(unclass(x)) } #' @export as_tibble.ts <- function(x, ...) { as_tibble(as.data.frame(x, ...)) } #' @export #' @param n Name for count column, default: `"n"`. #' @rdname as_tibble as_tibble.table <- function(x, n = "n", ...) { as_tibble(as.data.frame(x, responseName = n, stringsAsFactors = FALSE)) } #' @export #' @rdname as_tibble as_tibble.NULL <- function(x, ...) { as_tibble(list()) } #' @export #' @rdname as_tibble as_tibble.default <- function(x, ...) { value <- x as_tibble(as.data.frame(value, stringsAsFactors = FALSE, ...)) } #' @export #' @rdname as_tibble #' @usage NULL as.tibble <- function(x, ...) { UseMethod("as_tibble") } #' @export #' @rdname as_tibble #' @usage NULL as_data_frame <- function(x, ...) { UseMethod("as_data_frame") } #' @export as_data_frame.tbl_df <- as_tibble.tbl_df #' @export as_data_frame.data.frame <- as_tibble.data.frame #' @export as_data_frame.list <- as_tibble.list #' @export as_data_frame.matrix <- as_tibble.matrix #' @export as_data_frame.table <- as_tibble.table #' @export as_data_frame.NULL <- as_tibble.NULL #' @export as_data_frame.default <- as_tibble.default tibble/R/tibble-pkg.R0000644000176200001440000000372413204634213014063 0ustar liggesusers#' @useDynLib tibble, .registration = TRUE #' @importFrom utils head tail #' @import rlang #' @aliases NULL #' @details The S3 class `tbl_df` wraps a local data frame. The main #' advantage to using a `tbl_df` over a regular data frame is the printing: #' tbl objects only print a few rows and all the columns that fit on one screen, #' describing the rest of it as text. #' #' @section Methods: #' #' `tbl_df` implements four important base methods: #' #' \describe{ #' \item{print}{By default only prints the first 10 rows (at most 20), and the #' columns that fit on screen; see [print.tbl()]} #' \item{\code{[}}{Never simplifies (drops), so always returns data.frame} #' \item{\code{[[}, `$`}{Calls [.subset2()] directly, #' so is considerably faster. Returns `NULL` if column does not exist, #' `$` warns.} #' } #' @section Important functions: #' [tibble()] and [tribble()] for construction, #' [as_tibble()] for coercion, #' and [print.tbl()] and [glimpse()] for display. "_PACKAGE" #' @name tibble-package #' @section Package options: #' Display options for `tbl_df`, used by [trunc_mat()] and #' (indirectly) by [print.tbl()]. #' \describe{ (op.tibble <- list( #' \item{`tibble.print_max`}{Row number threshold: Maximum number of rows #' printed. Set to `Inf` to always print all rows. Default: 20.} tibble.print_max = 20L, #' \item{`tibble.print_min`}{Number of rows printed if row number #' threshold is exceeded. Default: 10.} tibble.print_min = 10L, #' \item{`tibble.width`}{Output width. Default: `NULL` (use #' `width` option).} tibble.width = NULL, #' \item{`tibble.max_extra_cols`}{Number of extra columns #' printed in reduced form. Default: 100.} tibble.max_extra_cols = 100L #' } )) tibble_opt <- function(x) { x_tibble <- paste0("tibble.", x) res <- getOption(x_tibble) if (!is.null(res)) return(res) x_dplyr <- paste0("dplyr.", x) res <- getOption(x_dplyr) if (!is.null(res)) return(res) op.tibble[[x_tibble]] } tibble/R/lst.R0000644000176200001440000000314413217670635012655 0ustar liggesusers#' @include tibble.R #' #' @description `lst()` is similar to [list()], but like `tibble()`, it #' evaluates its arguments lazily and in order, and automatically adds names. #' #' @export #' @examples #' lst(n = 5, x = runif(n)) #' #' # You can splice-unquote a list of quotes and formulas #' lst(!!! list(n = rlang::quo(2 + 3), y = quote(runif(n)))) #' #' @export #' @rdname tibble lst <- function(...) { xs <- quos(..., .named = 500L) lst_quos(xs) } lst_quos <- function(xs, expand = FALSE) { n <- length(xs) if (n == 0) { return(list()) } # Evaluate each column in turn col_names <- names2(xs) output <- list_len(n) names(output) <- character(n) for (i in seq_len(n)) { unique_output <- output[!duplicated(names(output)[seq_len(i)], fromLast = TRUE)] res <- eval_tidy(xs[[i]], unique_output) if (!is_null(res)) { output[[i]] <- res if (expand) output <- expand_lst(output, i) } names(output)[i] <- col_names[[i]] } output } expand_lst <- function(output, i) { idx_to_fix <- integer() if (i > 1L) { if (length(output[[i]]) == 1L && length(output[[1L]]) != 1L) { idx_to_fix <- i idx_boilerplate <- 1L } else if (length(output[[i]]) != 1L && all(map(output[seq2(1L, i - 1L)], length) == 1L)) { idx_to_fix <- seq2(1L, i - 1L) idx_boilerplate <- i } } if (length(idx_to_fix) > 0L) { ones <- rep(1L, length(output[[idx_boilerplate]])) output[idx_to_fix] <- map(output[idx_to_fix], `[`, ones) } output } #' @export #' @rdname tibble lst_ <- function(xs) { xs <- compat_lazy_dots(xs, caller_env()) lst(!!! xs) } tibble/R/wrap.R0000644000176200001440000000224413204634213013010 0ustar liggesusersNBSP <- "\U00A0" wrap <- function(..., indent = 0, prefix = "", width) { x <- paste0(..., collapse = "") wrapped <- strwrap2(x, width - nchar_width(prefix), indent) wrapped <- paste0(prefix, wrapped) wrapped <- gsub(NBSP, " ", wrapped) paste0(wrapped, collapse = "\n") } strwrap2 <- function(x, width, indent) { col_strwrap(x, width = max(width, 0), indent = indent, exdent = indent + 2) } col_strwrap <- function(x, width, indent, exdent) { space_rx <- "[[:space:]]+" words <- crayon::col_strsplit(x, space_rx, perl = TRUE)[[1L]] words_bw <- strsplit(crayon::strip_style(x), space_rx, perl = TRUE)[[1L]] stopifnot(length(words) == length(words_bw)) # strrep() requires R 3.3.0 dots <- strrep(".", nchar_width(words_bw)) wrapped_dots <- strwrap( paste(dots, collapse = " "), width = width, indent = indent, exdent = exdent, prefix = "", simplify = TRUE, initial = "" ) wrapped_dots_string <- paste(wrapped_dots, collapse = "\n") space <- strsplit(wrapped_dots_string, "[.]+")[[1L]] wrapped_styled_string <- paste0(c("", words), c(space, ""), collapse = "") strsplit(wrapped_styled_string, "\n", fixed = TRUE)[[1L]] } tibble/R/compat-lazyeval.R0000644000176200001440000000371513204634213015153 0ustar liggesusers# nocov - compat-lazyeval (last updated: rlang 0.0.0.9018) # This file serves as a reference for compatibility functions for lazyeval. # Please find the most recent version in rlang's repository. warn_underscored <- function() { return(NULL) warn(paste( "The underscored versions are deprecated in favour of", "tidy evaluation idioms. Please see the documentation", "for `quo()` in rlang" )) } warn_text_se <- function() { return(NULL) warn("Text parsing is deprecated, please supply an expression or formula") } compat_lazy <- function(lazy, env = caller_env(), warn = TRUE) { if (warn) warn_underscored() if (missing(lazy)) { return(quo()) } coerce_type( lazy, "quosure", formula = as_quosure(lazy, env), symbol = , language = new_quosure(lazy, env), string = , character = { if (warn) warn_text_se() parse_quosure(lazy[[1]], env) }, logical = , integer = , double = { if (length(lazy) > 1) { warn("Truncating vector to length 1") lazy <- lazy[[1]] } new_quosure(lazy, env) }, list = coerce_class( lazy, "quosure", lazy = new_quosure(lazy$expr, lazy$env) ) ) } compat_lazy_dots <- function(dots, env, ..., .named = FALSE) { if (missing(dots)) { dots <- list() } if (inherits(dots, "lazy")) { dots <- list(dots) } else { dots <- unclass(dots) } dots <- c(dots, list(...)) warn <- TRUE for (i in seq_along(dots)) { dots[[i]] <- compat_lazy(dots[[i]], env, warn) warn <- FALSE } named <- have_name(dots) if (.named && any(!named)) { nms <- map_chr(dots[!named], f_text) names(dots)[!named] <- nms } names(dots) <- names2(dots) dots } compat_as_lazy <- function(quo) { structure(class = "lazy", list( expr = f_rhs(quo), env = f_env(quo) )) } compat_as_lazy_dots <- function(...) { structure(class = "lazy_dots", map(quos(...), compat_as_lazy)) } # nocov end tibble/R/compat-purrr.R0000644000176200001440000000723313204634213014475 0ustar liggesusers# nocov - compat-purrr (last updated: rlang 0.0.0.9007) # This file serves as a reference for compatibility functions for # purrr. They are not drop-in replacements but allow a similar style # of programming. This is useful in cases where purrr is too heavy a # package to depend on. Please find the most recent version in rlang's # repository. map <- function(.x, .f, ...) { lapply(.x, .f, ...) } map_mold <- function(.x, .f, .mold, ...) { out <- vapply(.x, .f, .mold, ..., USE.NAMES = FALSE) rlang::set_names(out, names(.x)) } map_lgl <- function(.x, .f, ...) { map_mold(.x, .f, logical(1), ...) } map_int <- function(.x, .f, ...) { map_mold(.x, .f, integer(1), ...) } map_dbl <- function(.x, .f, ...) { map_mold(.x, .f, double(1), ...) } map_chr <- function(.x, .f, ...) { map_mold(.x, .f, character(1), ...) } map_cpl <- function(.x, .f, ...) { map_mold(.x, .f, complex(1), ...) } pluck <- function(.x, .f) { map(.x, `[[`, .f) } pluck_lgl <- function(.x, .f) { map_lgl(.x, `[[`, .f) } pluck_int <- function(.x, .f) { map_int(.x, `[[`, .f) } pluck_dbl <- function(.x, .f) { map_dbl(.x, `[[`, .f) } pluck_chr <- function(.x, .f) { map_chr(.x, `[[`, .f) } pluck_cpl <- function(.x, .f) { map_cpl(.x, `[[`, .f) } map2 <- function(.x, .y, .f, ...) { Map(.f, .x, .y, ...) } map2_lgl <- function(.x, .y, .f, ...) { as.vector(map2(.x, .y, .f, ...), "logical") } map2_int <- function(.x, .y, .f, ...) { as.vector(map2(.x, .y, .f, ...), "integer") } map2_dbl <- function(.x, .y, .f, ...) { as.vector(map2(.x, .y, .f, ...), "double") } map2_chr <- function(.x, .y, .f, ...) { as.vector(map2(.x, .y, .f, ...), "character") } map2_cpl <- function(.x, .y, .f, ...) { as.vector(map2(.x, .y, .f, ...), "complex") } args_recycle <- function(args) { lengths <- map_int(args, length) n <- max(lengths) stopifnot(all(lengths == 1L | lengths == n)) to_recycle <- lengths == 1L args[to_recycle] <- map(args[to_recycle], function(x) rep.int(x, n)) args } pmap <- function(.l, .f, ...) { args <- args_recycle(.l) do.call("mapply", c( FUN = list(quote(.f)), args, MoreArgs = quote(list(...)), SIMPLIFY = FALSE, USE.NAMES = FALSE )) } probe <- function(.x, .p, ...) { if (is_logical(.p)) { stopifnot(length(.p) == length(.x)) .p } else { map_lgl(.x, .p, ...) } } keep <- function(.x, .f, ...) { .x[probe(.x, .f, ...)] } discard <- function(.x, .p, ...) { sel <- probe(.x, .p, ...) .x[is.na(sel) | !sel] } map_if <- function(.x, .p, .f, ...) { matches <- probe(.x, .p) .x[matches] <- map(.x[matches], .f, ...) .x } compact <- function(.x) { Filter(length, .x) } transpose <- function(.l) { inner_names <- names(.l[[1]]) if (is.null(inner_names)) { fields <- seq_along(.l[[1]]) } else { fields <- set_names(inner_names) } map(fields, function(i) { map(.l, .subset2, i) }) } every <- function(.x, .p, ...) { for (i in seq_along(.x)) { if (!rlang::is_true(.p(.x[[i]], ...))) return(FALSE) } TRUE } some <- function(.x, .p, ...) { for (i in seq_along(.x)) { if (rlang::is_true(.p(.x[[i]], ...))) return(TRUE) } FALSE } negate <- function(.p) { function(...) !.p(...) } reduce <- function(.x, .f, ..., .init) { f <- function(x, y) .f(x, y, ...) Reduce(f, .x, init = .init) } reduce_right <- function(.x, .f, ..., .init) { f <- function(x, y) .f(y, x, ...) Reduce(f, .x, init = .init, right = TRUE) } accumulate <- function(.x, .f, ..., .init) { f <- function(x, y) .f(x, y, ...) Reduce(f, .x, init = .init, accumulate = TRUE) } accumulate_right <- function(.x, .f, ..., .init) { f <- function(x, y) .f(y, x, ...) Reduce(f, .x, init = .init, right = TRUE, accumulate = TRUE) } # nocov end tibble/R/repair-names.R0000644000176200001440000000662613204634213014432 0ustar liggesusers#' Repair object names. #' #' `tidy_names()` ensures its input has non-missing and #' unique names (duplicated names get a suffix of the format `..#` #' where `#` is the position in the vector). #' Valid names are left unchanged, with the exception that existing suffixes #' are reorganized. #' @param x A named vector. #' @param syntactic Should all names be made syntactically valid via [make.names()]? #' @param quiet If `TRUE` suppresses output from this function #' @return `x` with valid names. #' @examples #' # Works for lists and vectors, too: #' set_tidy_names(3:5) #' set_tidy_names(list(3, 4, 5)) #' #' # Clean data frames are left unchanged: #' set_tidy_names(mtcars) #' #' # By default, all rename operations are printed to the console: #' tbl <- as_tibble(structure(list(3, 4, 5), class = "data.frame"), #' validate = FALSE) #' set_tidy_names(tbl) #' #' # Optionally, names can be made syntactic: #' tidy_names("a b", syntactic = TRUE) #' @export #' @rdname tidy_names set_tidy_names <- function(x, syntactic = FALSE, quiet = FALSE) { new_names <- tidy_names(names2(x), syntactic, quiet) set_names(x, new_names) } #' @description #' `tidy_names()` is the workhorse behind `set_tidy_names()`, it treats the #' argument as a string to be used to name a data frame or a vector. #' @param name A character vector representing names. #' @export tidy_names <- function(name, syntactic = FALSE, quiet = FALSE) { name[is.na(name)] <- "" orig_name <- name name <- make_syntactic(name, syntactic) name <- append_pos(name) describe_tidying(orig_name, name, quiet) name } make_syntactic <- function(name, syntactic) { if (!syntactic) return(name) blank <- name == "" fix_syntactic <- (name != "") & !is_syntactic(name) name[fix_syntactic] <- make.names(name[fix_syntactic]) name } append_pos <- function(name) { need_append_pos <- duplicated(name) | duplicated(name, fromLast = TRUE) | name == "" if (any(need_append_pos)) { rx <- "[.][.][1-9][0-9]*$" has_suffix <- grepl(rx, name) name[has_suffix] <- gsub(rx, "", name[has_suffix]) need_append_pos <- need_append_pos | has_suffix } need_append_pos <- which(need_append_pos) name[need_append_pos] <- paste0(name[need_append_pos], "..", need_append_pos) name } describe_tidying <- function(orig_name, name, quiet) { stopifnot(length(orig_name) == length(name)) if (quiet) return() new_names <- name != orig_name if (any(new_names)) { message( "New names:\n", paste0(orig_name[new_names], " -> ", name[new_names], collapse = "\n") ) } } #' @rdname tidy_names #' @description #' `repair_names()` is an older version with different renaming heuristics, #' kept for backward compatibility. New code should prefer `tidy_names()`. #' #' @param prefix A string, the prefix to use for new column names. #' @param sep A string inserted between the column name and de-duplicating #' number. #' @export repair_names <- function(x, prefix = "V", sep = "") { if (length(x) == 0) { names(x) <- character() return(x) } new_names <- make_unique(names2(x), prefix = prefix, sep = sep) set_names(x, new_names) } make_unique <- function(x, prefix = "V", sep = "") { blank <- x == "" # Ensure existing names are unique x[!blank] <- make.unique(x[!blank], sep = sep) # Replace blank names new_vars <- setdiff(paste(prefix, seq_along(x), sep = sep), x) x[blank] <- new_vars[seq_len(sum(blank))] x } tibble/R/add.R0000644000176200001440000001116713204634213012573 0ustar liggesusers#' Add rows to a data frame #' #' This is a convenient way to add one or more rows of data to an existing data #' frame. See [tribble()] for an easy way to create an complete #' data frame row-by-row. #' #' `add_case()` is an alias of `add_row()`. #' #' @param .data Data frame to append to. #' @param ... Name-value pairs, passed on to [tibble()]. Only columns that exist #' in `.data` can be used, unset columns will get an `NA` value. #' @param .before,.after One-based row index where to add the new rows, #' default: after last row. #' @family addition #' @examples #' # add_row --------------------------------- #' df <- tibble(x = 1:3, y = 3:1) #' #' add_row(df, x = 4, y = 0) #' #' # You can specify where to add the new rows #' add_row(df, x = 4, y = 0, .before = 2) #' #' # You can supply vectors, to add multiple rows (this isn't #' # recommended because it's a bit hard to read) #' add_row(df, x = 4:5, y = 0:-1) #' #' # Absent variables get missing values #' add_row(df, x = 4) #' #' # You can't create new variables #' \dontrun{ #' add_row(df, z = 10) #' } #' @export add_row <- function(.data, ..., .before = NULL, .after = NULL) { if (inherits(.data, "grouped_df")) { stop("Can't add rows to grouped data frames", call. = FALSE) } df <- tibble(...) attr(df, "row.names") <- .set_row_names(max(1L, nrow(df))) extra_vars <- setdiff(names(df), names(.data)) if (length(extra_vars) > 0) { stopc(pluralise_msg("Can't add row with new variable(s) ", extra_vars)) } missing_vars <- setdiff(names(.data), names(df)) df[missing_vars] <- map(.data[missing_vars], na_value) df <- df[names(.data)] pos <- pos_from_before_after(.before, .after, nrow(.data)) out <- rbind_at(.data, df, pos) set_class(remove_rownames(out), class(.data)) } #' @export #' @rdname add_row #' @usage NULL add_case <- add_row na_value <- function(boilerplate) { if (is.list(boilerplate)) { list(NULL) } else { NA } } rbind_at <- function(old, new, pos) { if (nrow(old) == 0) { old <- old[1, ] out <- rbind(old, new)[-1, ] } else { out <- rbind(old, new) if (pos < nrow(old)) { pos <- max(pos, 0L) idx <- c( seq2(1L, pos), seq2(nrow(old) + 1L, nrow(old) + nrow(new)), seq2(pos + 1L, nrow(old)) ) out <- out[idx, ] } } out } #' Add columns to a data frame #' #' This is a convenient way to add one or more columns to an existing data #' frame. #' #' @param .data Data frame to append to. #' @param ... Name-value pairs, passed on to [tibble()]. All values must have #' one element for each row in the data frame, or be of length 1. #' @param .before,.after One-based column index or column name where to add the #' new columns, default: after last column. #' @family addition #' @examples #' # add_column --------------------------------- #' df <- tibble(x = 1:3, y = 3:1) #' #' add_column(df, z = -1:1, w = 0) #' #' # You can't overwrite existing columns #' \dontrun{ #' add_column(df, x = 4:6) #' } #' # You can't create new observations #' \dontrun{ #' add_column(df, z = 1:5) #' } #' @export add_column <- function(.data, ..., .before = NULL, .after = NULL) { df <- tibble(...) if (ncol(df) == 0L) { return(.data) } if (nrow(df) != nrow(.data)) { if (nrow(df) == 1) { df <- df[rep(1L, nrow(.data)), ] } else { stopc( "`.data` must have ", nrow(.data), pluralise_n(" row(s)", nrow(.data)), ", not ", nrow(df) ) } } extra_vars <- intersect(names(df), names(.data)) if (length(extra_vars) > 0) { stopc( pluralise_msg("Column(s) ", extra_vars), pluralise(" already exist[s]", extra_vars) ) } pos <- pos_from_before_after_names(.before, .after, colnames(.data)) end_pos <- ncol(.data) + seq_len(ncol(df)) indexes_before <- rlang::seq2(1L, pos) indexes_after <- rlang::seq2(pos + 1L, ncol(.data)) indexes <- c(indexes_before, end_pos, indexes_after) .data[end_pos] <- df .data[indexes] } # helpers ----------------------------------------------------------------- pos_from_before_after_names <- function(before, after, names) { before <- check_names_before_after(before, names) after <- check_names_before_after(after, names) pos_from_before_after(before, after, length(names)) } pos_from_before_after <- function(before, after, len) { if (is_null(before)) { if (is_null(after)) { len } else { limit_pos_range(after, len) } } else { if (is_null(after)) { limit_pos_range(before - 1L, len) } else { stopc("Can't specify both `.before` and `.after`") } } } limit_pos_range <- function(pos, len) { max(c(0L, min(c(len, pos)))) } tibble/R/tbl-df.r0000644000176200001440000000503213204634213013245 0ustar liggesusers#' @importFrom methods setOldClass setOldClass(c("tbl_df", "tbl", "data.frame")) # Standard data frame methods -------------------------------------------------- #' @export as.data.frame.tbl_df <- function(x, row.names = NULL, optional = FALSE, ...) { class(x) <- "data.frame" x } #' @rdname formatting #' @export format.tbl <- function(x, ..., n = NULL, width = NULL, n_extra = NULL) { mat <- trunc_mat(x, n = n, width = width, n_extra = n_extra) format(mat) } #' @rdname formatting #' @export format.tbl_df <- format.tbl #' @rdname formatting #' @export print.tbl <- function(x, ..., n = NULL, width = NULL, n_extra = NULL) { cat_line(format(x, ..., n = n, width = width, n_extra = n_extra)) invisible(x) } #' @rdname formatting #' @export print.tbl_df <- print.tbl #' @export `[[.tbl_df` <- function(x, i, j, ..., exact = TRUE) { if (missing(j)) { colname <- i } else { colname <- j } if (!exact) { warningc("exact ignored") } NextMethod() } #' @export `$.tbl_df` <- function(x, i) { if (is.character(i) && !has_name(x, i)) { warningc("Unknown or uninitialised column: '", i, "'.") } .subset2(x, i) } #' @export `[.tbl_df` <- function(x, i, j, drop = FALSE) { nr <- nrow(x) # Ignore drop as an argument n_real_args <- nargs() - !missing(drop) # Escape early if nargs() == 2L; ie, column subsetting if (n_real_args <= 2L) { if (!missing(drop)) warningc("drop ignored") if (!missing(i)) { i <- check_names_df(i, x) result <- .subset(x, i) } else { result <- x } attr(result, "row.names") <- .set_row_names(nr) return(as_tibble.data.frame(result, validate = FALSE)) } # First, subset columns if (!missing(j)) { j <- check_names_df(j, x) result <- .subset(x, j) } else { result <- x } # Next, subset rows if (!missing(i)) { if (is.logical(i) && !(length(i) %in% c(1, nrow(x)))) { warningc( "Length of logical index must be 1", if (nrow(x) != 1) paste0(" or ", nrow(x)), ", not ", length(i) ) } if (length(result) == 0) { nr <- length(attr(x, "row.names")[i]) } else { if (is.character(i)) { if (has_rownames(x)) { i <- match(i, rownames(x)) } else { i <- string_to_indices(i) } } result <- map(result, `[`, i) nr <- length(result[[1]]) } } attr(result, "row.names") <- .set_row_names(nr) if (drop && length(result) == 1L) { result[[1L]] } else { as_tibble.data.frame(result, validate = FALSE) } } tibble/vignettes/0000755000176200001440000000000013217741055013530 5ustar liggesuserstibble/vignettes/tibble.Rmd0000644000176200001440000001042213204634213015425 0ustar liggesusers--- title: "Tibbles" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Tibbles} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r, echo = FALSE, message = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") options(tibble.print_min = 4L, tibble.print_max = 4L) library(tibble) set.seed(1014) ``` Tibbles are a modern take on data frames. They keep the features that have stood the test of time, and drop the features that used to be convenient but are now frustrating (i.e. converting character vectors to factors). ## Creating `tibble()` is a nice way to create data frames. It encapsulates best practices for data frames: * It never changes an input's type (i.e., no more `stringsAsFactors = FALSE`!). ```{r} tibble(x = letters) ``` This makes it easier to use with list-columns: ```{r} tibble(x = 1:3, y = list(1:5, 1:10, 1:20)) ``` List-columns are most commonly created by `do()`, but they can be useful to create by hand. * It never adjusts the names of variables: ```{r} names(data.frame(`crazy name` = 1)) names(tibble(`crazy name` = 1)) ``` * It evaluates its arguments lazily and sequentially: ```{r} tibble(x = 1:5, y = x ^ 2) ``` * It never uses `row.names()`. The whole point of tidy data is to store variables in a consistent way. So it never stores a variable as special attribute. * It only recycles vectors of length 1. This is because recycling vectors of greater lengths is a frequent source of bugs. ## Coercion To complement `tibble()`, tibble provides `as_tibble()` to coerce objects into tibbles. Generally, `as_tibble()` methods are much simpler than `as.data.frame()` methods, and in fact, it's precisely what `as.data.frame()` does, but it's similar to `do.call(cbind, lapply(x, data.frame))` - i.e. it coerces each component to a data frame and then `cbinds()` them all together. `as_tibble()` has been written with an eye for performance: ```{r} if (requireNamespace("microbenchmark", quiet = TRUE)) { l <- replicate(26, sample(100), simplify = FALSE) names(l) <- letters microbenchmark::microbenchmark( as_tibble(l), as.data.frame(l) ) } ``` The speed of `as.data.frame()` is not usually a bottleneck when used interactively, but can be a problem when combining thousands of messy inputs into one tidy data frame. ## Tibbles vs data frames There are three key differences between tibbles and data frames: printing, subsetting, and recycling rules. ### Printing When you print a tibble, it only shows the first ten rows and all the columns that fit on one screen. It also prints an abbreviated description of the column type: ```{r} tibble(x = 1:1000) ``` You can control the default appearance with options: * `options(tibble.print_max = n, tibble.print_min = m)`: if there are more than `n` rows, print only the first `m` rows. Use `options(tibble.print_max = Inf)` to always show all rows. * `options(tibble.width = Inf)` will always print all columns, regardless of the width of the screen. ### Subsetting Tibbles are quite strict about subsetting. `[` always returns another tibble. Contrast this with a data frame: sometimes `[` returns a data frame and sometimes it just returns a vector: ```{r} df1 <- data.frame(x = 1:3, y = 3:1) class(df1[, 1:2]) class(df1[, 1]) df2 <- tibble(x = 1:3, y = 3:1) class(df2[, 1:2]) class(df2[, 1]) ``` To extract a single column use `[[` or `$`: ```{r} class(df2[[1]]) class(df2$x) ``` Tibbles are also stricter with `$`. Tibbles never do partial matching, and will throw a warning and return `NULL` if the column does not exist: ```{r, error = TRUE} df <- data.frame(abc = 1) df$a df2 <- tibble(abc = 1) df2$a ``` tibbles also ignore the `drop` argument: ```{r} tibble(a = 1:3)[, "a", drop = TRUE] ``` ### Recycling When constructing a tibble, only values of length 1 are recycled. The first column with length different to one determines the number of rows in the tibble, conflicts lead to an error. This also extends to tibbles with *zero* rows, which is sometimes important for programming: ```{r, error = TRUE} tibble(a = 1, b = 1:3) tibble(a = 1:3, b = 1) tibble(a = 1:3, c = 1:2) tibble(a = 1, b = integer()) tibble(a = integer(), b = 1) ``` tibble/vignettes/extending.Rmd0000644000176200001440000003263213217670436016173 0ustar liggesusers--- title: "Extending tibble" author: "Kirill Müller, Hadley Wickham" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Extending tibble} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- To extend the tibble package for new types of columnar data, you need to understand how printing works. The presentation of a column in a tibble is powered by four S3 generics: * `type_sum()` determines what goes into the column header. * `pillar_shaft()` determines what goes into the body of the column. * `is_vector_s3()` and `obj_sum()` are used when rendering list columns. If you have written an S3 or S4 class that can be used as a column, you can override these generics to make sure your data prints well in a tibble. To start, you must import the `pillar` package that powers the printing of tibbles. Either add `pillar` to the `Imports:` section of your `DESCRIPTION`, or simply call: ```{r, eval = FALSE} usethis::use_package("pillar") ``` This short vignette assumes a package that implements an S3 class `"latlon"` and uses `roxygen2` to create documentation and the `NAMESPACE` file. For this vignette to work we need to attach pillar: ## Prerequisites We define a class `"latlon"` that encodes geographic coordinates in a complex number. For simplicity, the values are printed as degrees and minutes only. ```{r} #' @export latlon <- function(lat, lon) { as_latlon(complex(real = lon, imaginary = lat)) } #' @export as_latlon <- function(x) { structure(x, class = "latlon") } #' @export c.latlon <- function(x, ...) { as_latlon(NextMethod()) } #' @export `[.latlon` <- function(x, i) { as_latlon(NextMethod()) } #' @export format.latlon <- function(x, ..., formatter = deg_min) { x_valid <- which(!is.na(x)) lat <- unclass(Im(x[x_valid])) lon <- unclass(Re(x[x_valid])) ret <- rep("", length(x)) ret[x_valid] <- paste( formatter(lat, c("N", "S")), formatter(lon, c("E", "W")) ) format(ret, justify = "right") } deg_min <- function(x, pm) { sign <- sign(x) x <- abs(x) deg <- trunc(x) x <- x - deg min <- round(x * 60) ret <- sprintf("%d°%.2d'%s", deg, min, pm[ifelse(sign >= 0, 1, 2)]) format(ret, justify = "right") } #' @export print.latlon <- function(x, ...) { cat(format(x), sep = "\n") invisible(x) } latlon(32.7102978, -117.1704058) ``` More methods are needed to make this class fully compatible with data frames, see e.g. the [hms](https://github.com/tidyverse/hms/) package for a more complete example. ## Using in a tibble Columns on this class can be used in a tibble right away, but the output will be less than ideal: ```{r} library(tibble) data <- tibble( venue = "rstudio::conf", year = 2017:2019, loc = latlon( c(28.3411783, 32.7102978, NA), c(-81.5480348, -117.1704058, NA) ), paths = list( loc[1], c(loc[1], loc[2]), loc[2] ) ) data ``` (The `paths` column is a list that contains arbitrary data, in our case `latlon` vectors. A list column is a powerful way to attach hierarchical or unstructured data to an observation in a data frame.) The output has three main problems: 1. The column type of the `loc` column is displayed as ``. This default formatting works reasonably well for any kind of object, but the generated output may be too wide and waste precious space when displaying the tibble. 1. The values in the `loc` column are formatted as complex numbers (the underlying storage), without using the `format()` method we have defined. This is by design. 1. The cells in the `paths` column are also displayed as ``. In the remainder I'll show how to fix these problems, and also how to implement rendering that adapts to the available width. ## Fixing the data type To display `` as data type, we need to override the `type_sum()` method. This method should return a string that can be used in a column header. For your own classes, strive for an evocative abbreviation that's under 6 characters. ```{r include=FALSE} import::from(pillar, type_sum) ``` ```{r} #' @importFrom pillar type_sum #' @export type_sum.latlon <- function(x) { "geo" } ``` Because the value shown there doesn't depend on the data, we just return a constant. (For date-times, the column info will eventually contain information about the timezone, see [#53](https://github.com/r-lib/pillar/pull/53).) ```{r} data ``` ## Rendering the value To use our format method for rendering, we implement the `pillar_shaft()` method for our class. (A [*pillar*](https://en.wikipedia.org/wiki/Column#Nomenclature) is mainly a *shaft* (decorated with an *ornament*), with a *capital* above and a *base* below. Multiple pillars form a *colonnade*, which can be stacked in multiple *tiers*. This is the motivation behind the names in our API.) ```{r include=FALSE} import::from(pillar, pillar_shaft) ``` ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "right") } ``` The simplest variant calls our `format()` method, everything else is handled by pillar, in particular by the `new_pillar_shaft_simple()` helper. Note how the `align` argument affects the alignment of NA values and of the column name and type. ```{r} data ``` We could also use left alignment and indent only the `NA` values: ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "left", na_indent = 5) } data ``` ## Adaptive rendering If there is not enough space to render the values, the formatted values are truncated with an ellipsis. This doesn't currently apply to our class, because we haven't specified a minimum width for our values: ```{r} print(data, width = 35) ``` If we specify a minimum width when constructing the shaft, the `loc` column will be truncated: ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "right", min_width = 10) } print(data, width = 35) ``` This may be useful for character data, but for lat-lon data we may prefer to show full degrees and remove the minutes if the available space is not enough to show accurate values. A more sophisticated implementation of the `pillar_shaft()` method is required to achieve this: ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { deg <- format(x, formatter = deg) deg[is.na(x)] <- pillar::style_na("NA") deg_min <- format(x) deg_min[is.na(x)] <- pillar::style_na("NA") pillar::new_pillar_shaft( list(deg = deg, deg_min = deg_min), width = pillar::get_max_extent(deg_min), min_width = pillar::get_max_extent(deg), subclass = "pillar_shaft_latlon" ) } ``` Here, `pillar_shaft()` returns an object of the `"pillar_shaft_latlon"` class created by the generic `new_pillar_shaft()` constructor. This object contains the necessary information to render the values, and also minimum and maximum width values. For simplicity, both formattings are pre-rendered, and the minimum and maximum widths are computed from there. Note that we also need to take care of `NA` values explicitly. (`get_max_extent()` is a helper that computes the maximum display width occupied by the values in a character vector.) For completeness, the code that implements the degree-only formatting looks like this: ```{r} deg <- function(x, pm) { sign <- sign(x) x <- abs(x) deg <- round(x) ret <- sprintf("%d°%s", deg, pm[ifelse(sign >= 0, 1, 2)]) format(ret, justify = "right") } ``` All that's left to do is to implement a `format()` method for our new `"pillar_shaft_latlon"` class. This method will be called with a `width` argument, which then determines which of the formattings to choose: ```{r} #' @export format.pillar_shaft_latlon <- function(x, width, ...) { if (all(crayon::col_nchar(x$deg_min) <= width)) { ornament <- x$deg_min } else { ornament <- x$deg } pillar::new_ornament(ornament) } data print(data, width = 35) ``` ## Adding color Both `new_pillar_shaft_simple()` and `new_ornament()` accept ANSI escape codes for coloring, emphasis, or other ways of highlighting text on terminals that support it. Some formattings are predefined, e.g. `style_subtle()` displays text in a light gray. For default data types, this style is used for insignificant digits. We'll be formatting the degree and minute signs in a subtle style, because they serve only as separators. You can also use the [crayon](https://cran.r-project.org/package=crayon) package to add custom formattings to your output. ```{r} #' @importFrom pillar pillar_shaft #' @export pillar_shaft.latlon <- function(x, ...) { out <- format(x, formatter = deg_min_color) out[is.na(x)] <- NA pillar::new_pillar_shaft_simple(out, align = "left", na_indent = 5) } deg_min_color <- function(x, pm) { sign <- sign(x) x <- abs(x) deg <- trunc(x) x <- x - deg rad <- round(x * 60) ret <- sprintf( "%d%s%.2d%s%s", deg, pillar::style_subtle("°"), rad, pillar::style_subtle("'"), pm[ifelse(sign >= 0, 1, 2)] ) ret[is.na(x)] <- "" format(ret, justify = "right") } data ``` Currently, ANSI escapes are not rendered in vignettes, so the display here isn't much different from earlier examples. This may change in the future. ## Fixing list columns To tweak the output in the `paths` column, we simply need to indicate that our class is an S3 vector: ```{r include=FALSE} import::from(pillar, is_vector_s3) ``` ```{r} #' @importFrom pillar is_vector_s3 #' @export is_vector_s3.latlon <- function(x) TRUE data ``` This is picked up by the default implementation of `obj_sum()`, which then shows the type and the length in brackets. If your object is built on top of an atomic vector the default will be adequate. You, will, however, need to provide an `obj_sum()` method for your class if your object is vectorised and built on top of a list. An example of an object of this type in base R is `POSIXlt`: it is a list with 9 components. ```{r} x <- as.POSIXlt(Sys.time() + c(0, 60, 3600)) str(unclass(x)) ``` But it pretends to be a vector with 3 elements: ```{r} x length(x) str(x) ``` So we need to define a method that returns a character vector the same length as `x`: ```{r include=FALSE} import::from(pillar, obj_sum) ``` ```{r} #' @importFrom pillar obj_sum #' @export obj_sum.POSIXlt <- function(x) { rep("POSIXlt", length(x)) } ``` ## Testing If you want to test the output of your code, you can compare it with a known state recorded in a text file. For this, pillar offers the `expect_known_display()` expectation which requires and works best with the testthat package. Make sure that the output is generated only by your package to avoid inconsistencies when external code is updated. Here, this means that you test only the shaft portion of the pillar, and not the entire pillar or even a tibble that contains a column with your data type! The tests work best with the testthat package: ```{r} library(testthat) ``` ```{r include = FALSE} unlink("latlon.txt") unlink("latlon-bw.txt") ``` The code below will compare the output of `pillar_shaft(data$loc)` with known output stored in the `latlon.txt` file. The first run warns because the file doesn't exist yet. ```{r error = TRUE, warning = TRUE} test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt" ) }) ``` From the second run on, the printing will be compared with the file: ```{r} test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt" ) }) ``` However, if we look at the file we'll notice strange things: The output contains ANSI escapes! ```{r} readLines("latlon.txt") ``` We can turn them off by passing `crayon = FALSE` to the expectation, but we need to run twice again: ```{r error = TRUE, warning = TRUE} library(testthat) test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt", crayon = FALSE ) }) ``` ```{r} test_that("latlon pillar matches known output", { pillar::expect_known_display( pillar_shaft(data$loc), file = "latlon.txt", crayon = FALSE ) }) readLines("latlon.txt") ``` You may want to create a series of output files for different scenarios: - Colored vs. plain (to simplify viewing differences) - With or without special Unicode characters (if your output uses them) - Different widths For this it is helpful to create your own expectation function. Use the tidy evaluation framework to make sure that construction and printing happens at the right time: ```{r} expect_known_latlon_display <- function(x, file_base) { quo <- rlang::quo(pillar::pillar_shaft(x)) pillar::expect_known_display( !! quo, file = paste0(file_base, ".txt") ) pillar::expect_known_display( !! quo, file = paste0(file_base, "-bw.txt"), crayon = FALSE ) } ``` ```{r error = TRUE, warning = TRUE} test_that("latlon pillar matches known output", { expect_known_latlon_display(data$loc, file_base = "latlon") }) ``` ```{r} readLines("latlon.txt") readLines("latlon-bw.txt") ``` Learn more about the tidyeval framework in the [dplyr vignette](http://dplyr.tidyverse.org/articles/programming.html). ```{r include = FALSE} unlink("latlon.txt") unlink("latlon-bw.txt") ``` tibble/README.md0000644000176200001440000000707013217740717013007 0ustar liggesusers tibble ======================================================= [![Build Status](https://travis-ci.org/tidyverse/tibble.svg?branch=master)](https://travis-ci.org/tidyverse/tibble) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/tidyverse/tibble?branch=master&svg=true)](https://ci.appveyor.com/project/tidyverse/tibble) [![codecov](https://codecov.io/gh/tidyverse/tibble/branch/master/graph/badge.svg)](https://codecov.io/gh/tidyverse/tibble) [![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/tibble)](https://cran.r-project.org/package=tibble) Overview -------- A **tibble**, or `tbl_df`, is a modern reimagining of the data.frame, keeping what time has proven to be effective, and throwing out what is not. Tibbles are data.frames that are lazy and surly: they do less (i.e. they don't change variable names or types, and don't do partial matching) and complain more (e.g. when a variable does not exist). This forces you to confront problems earlier, typically leading to cleaner, more expressive code. Tibbles also have an enhanced `print method()` which makes them easier to use with large datasets containing complex objects. If you are new to tibbles, the best place to start is the [tibbles](http://r4ds.had.co.nz/tibbles.html) in R for data science. Installation ------------ ``` r # The easiest way to get tibble is to install the whole tidyverse: install.packages("tidyverse") # Alternatively, install just tibble: install.packages("tibble") # Or the the development version from GitHub: # install.packages("devtools") devtools::install_github("tidyverse/tibble") ``` Usage ----- Create a tibble from an existing object with `as_tibble()`: ``` r library(tibble) as_tibble(iris) #> # A tibble: 150 x 5 #> Sepal.Length Sepal.Width Petal.Length Petal.Width Species #> #> 1 5.10 3.50 1.40 0.200 setosa #> 2 4.90 3.00 1.40 0.200 setosa #> 3 4.70 3.20 1.30 0.200 setosa #> 4 4.60 3.10 1.50 0.200 setosa #> 5 5.00 3.60 1.40 0.200 setosa #> 6 5.40 3.90 1.70 0.400 setosa #> 7 4.60 3.40 1.40 0.300 setosa #> 8 5.00 3.40 1.50 0.200 setosa #> 9 4.40 2.90 1.40 0.200 setosa #> 10 4.90 3.10 1.50 0.100 setosa #> # ... with 140 more rows ``` This will work for reasonable inputs that are already data.frames, lists, matrices, or tables. You can also create a new tibble from column vectors with `tibble()`: ``` r tibble(x = 1:5, y = 1, z = x ^ 2 + y) #> # A tibble: 5 x 3 #> x y z #> #> 1 1 1.00 2.00 #> 2 2 1.00 5.00 #> 3 3 1.00 10.0 #> 4 4 1.00 17.0 #> 5 5 1.00 26.0 ``` `tibble()` does much less than `data.frame()`: it never changes the type of the inputs (e.g. it never converts strings to factors!), it never changes the names of variables, it only recycles inputs of length 1, and it never creates `row.names()`. You can read more about these features in the vignette, `vignette("tibble")`. You can define a tibble row-by-row with `tribble()`: ``` r tribble( ~x, ~y, ~z, "a", 2, 3.6, "b", 1, 8.5 ) #> # A tibble: 2 x 3 #> x y z #> #> 1 a 2.00 3.60 #> 2 b 1.00 8.50 ``` tibble/MD50000644000176200001440000001461013220301602012012 0ustar liggesusers475075c2019d0612daef6fe99826a93f *DESCRIPTION 4ac396cdf32c44b3d07b7d6c9fd388d0 *LICENSE 8e1879dde05bccfc4327fefa2633e319 *NAMESPACE f467595fb9ab1f517e6f17818a2737ab *NEWS.md 726fad19da31c2bb32d5fcd24ed69d9a *R/add.R 5ace44b515600dc0edf83570e4613fe4 *R/as_tibble.R 7393a70b19423ca73d42080de9c65329 *R/check-names.R e469430e598973caaac61676b9847961 *R/compat-lazyeval.R 1f93a1dc9780598f4c7fed9392807141 *R/compat-purrr.R 12c4bde1fc2edb4c52a7d7b68126f86f *R/enframe.R c3664e961a84ee80efec74d9a8f262d4 *R/exports.R 8cc5c15003d245ba38a230762e658e72 *R/glimpse.R f20e02292e4da20b9cbf33f0e66aa00d *R/has-name.R cc3b554bd187677da6499f6f415511cf *R/lst.R edf974b55e0b639a57f39d201dc147d0 *R/new.R a2bd5f781856fc0de739f19c125e5c1e *R/repair-names.R c52afcd6b7c482b1c293350ca509ce85 *R/rownames.R 6f8287098a5b24195016e34b4ef5dae3 *R/strrep.R b9a36b2793e7867c0bdcb1ae090a4c78 *R/tbl-df.r 9d2942e389d19bcc680a7b4385244d9d *R/tibble-pkg.R 8eaa8a35c2d345adafb614641fe8495d *R/tibble.R 278d47fbb00be2c4d84b90182050d8f4 *R/tribble.R 2a7ef0c2a59591462139297631f94c56 *R/type-sum.r 2a8d74682dd1ac2ee0d236c9258ca405 *R/utils-format.r 09983134f467786246c0866c51911d18 *R/utils.r 35ba0d19f315096f3d4ae9da64f336b8 *R/wrap.R fa391b2c680320d26b67af9f1e7eee46 *README.md 127af007d548fb5c49c78246a1afaf13 *build/vignette.rds ded7adf160f0b8a19305bf6b4807748e *inst/doc/extending.R e4d2cfc1114090950739ab0085ce0f26 *inst/doc/extending.Rmd 283e8d15433f5bc081482f11417cc26d *inst/doc/extending.html 992bc39bcc5ec455d14952ffc78d6ff4 *inst/doc/tibble.R d827ea23f552c20d92d909dcd7553739 *inst/doc/tibble.Rmd 1f2637f8f1e1f672baa2f8f094dbf050 *inst/doc/tibble.html 2a7c7c7406ea6fd87b1909f5f072b579 *man/add_column.Rd ee429e8d8e373b84f74d18ba7665e60f *man/add_row.Rd c723596ded0a7603c6834c54bf30185d *man/as_tibble.Rd 82535c19f20b1ee61c989c8e0281defc *man/enframe.Rd 2db3b0e7250ce7abb3301a26a21c743c *man/figures/logo.png fcd2dd753af00d377debcc422b8d4f9f *man/formatting.Rd 3efaffe329351a031a41474e7b33741a *man/frame_matrix.Rd 82bffdcb2a0088519454bbe19809a262 *man/glimpse.Rd 2af16d0272f4af1391935be9c53ea222 *man/is.tibble.Rd 998d02902cd2a2d13d7d1b77b32255ea *man/knit_print.trunc_mat.Rd e143dcb75215fc6fd773c55f4a6ad3e9 *man/new_tibble.Rd 7f5493a4899f8bd32f046daaf5396e54 *man/reexports.Rd bf8bed5b51d59158c30065d072ff3fb5 *man/rownames.Rd fe803e7785468f0147c1d86ce475fd9a *man/tbl_sum.Rd a88f6b5a83adaa05eec15e6633507c0c *man/tibble-package.Rd 74f857c7ebd34ecb3689d5d066dd8e19 *man/tibble.Rd 409540a95ce0eae1d41b3d0f53944ea2 *man/tidy_names.Rd a44537d4bfea7809475eab29d6e80206 *man/tribble.Rd ab636b77551c5a14042179ef87c5486c *src/coerce.c 36c03da56d146ea2acdd05f8130b3376 *src/init.c 1166dcc1eb814e9d479630e5b34e06ca *src/matrixToDataFrame.c 2d2fbf22f7df5a70358e52450b9196d2 *src/tibble.h 934bcde5b57357bf4ec7ac5793041f17 *tests/testthat.R 7842e41ea1b0ee61b0e26f1cca696794 *tests/testthat/helper-data.R e84fdfe6f028d32ba75cb12b73079802 *tests/testthat/helper-encoding.R 0c35c6e293789f7128aad40b1b5b5f80 *tests/testthat/helper-output.R e0b199eee82d8f18d61ee192ed10d197 *tests/testthat/helper-type-sum.R 2c7f8255e425a1c9f0bd768438e75e14 *tests/testthat/helper-unknown-rows.R c72ceac37b3a6f8ce601e7c692c0b757 *tests/testthat/output/glimpse/5.txt 59e332f7548b4667eedff8617438e2e4 *tests/testthat/output/glimpse/all-35.txt 123d31e1a2489dab3bac4711e3c97758 *tests/testthat/output/glimpse/all-50.txt f383d85ec899fcfcd22ce71bc2e296f9 *tests/testthat/output/glimpse/all-70.txt 82df862794444dc5d7a3eb4cdc83e981 *tests/testthat/output/glimpse/iris-70.txt 0d74f615866191dd8527f360e3394ae8 *tests/testthat/output/glimpse/iris-empty-70.txt 7a3f9a2883c851cf26f735fe6363e1fb *tests/testthat/output/glimpse/mtcars-70.txt 7abb3cfcde3d7fa037ea8bbbcc142272 *tests/testthat/output/glimpse/non-syntactic.txt 5250e39b390533cf5a6911c5fd4cfa81 *tests/testthat/output/trunc_mat/POSIXlt-8-60.txt 44a85fea8bcc4e372a01a05ebbe8e28a *tests/testthat/output/trunc_mat/all--30.txt 896d242bb8a12144917f2421cbd76f3d *tests/testthat/output/trunc_mat/all--300.txt 4d30a67e0739b6bc7ee8d54e5d7e4274 *tests/testthat/output/trunc_mat/all-1-30-0.txt 683ba12a2c404e507944407e954b5f99 *tests/testthat/output/trunc_mat/all-1-30-2.txt da9238447e36241dccca255c3693cbdf *tests/testthat/output/trunc_mat/iris--70.txt 88b68e9aae1202ec361c4149aa64ad2b *tests/testthat/output/trunc_mat/iris-3-5.txt 948e7f820b1b97ed37a77d0ac05965c3 *tests/testthat/output/trunc_mat/iris-5-30.txt c54464c3dc8ecdb191f72d1c8a65ebaf *tests/testthat/output/trunc_mat/iris_unk-10-70.txt f1ada279013f70e8b256d00bca6e8a73 *tests/testthat/output/trunc_mat/long-5-30.txt 809615054e42b3cf0cd58ddbf87fa61c *tests/testthat/output/trunc_mat/long_unk-5-30.txt 6ddea66bda2835159dc2e1546cc4c18c *tests/testthat/output/trunc_mat/mtcars-8-30.txt f69d4356ae7c5ef995723221ff4834d8 *tests/testthat/output/trunc_mat/newline.txt a6b5b1c957495bbc38a387e3f8b9d62b *tests/testthat/output/trunc_mat/non-syntactic.txt 4527375972a709a4db3e896bf444a18e *tests/testthat/output/trunc_mat/wide-8-60.txt 923247111da156cc24f9a12188d700f5 *tests/testthat/output/trunc_mat/zero-cols_unk-5-30.txt 466da8b8fef91ee98fb6d916cf9dc63f *tests/testthat/output/trunc_mat/zero-rows_unk-5-30.txt b4557fe57c9221fe381939fc6cfb570d *tests/testthat/output/trunc_mat/zero_cols-5-30.txt 30e39584b40ded7b8f45bff2c56f02f3 *tests/testthat/output/trunc_mat/zero_rows--30.txt 961e849374ad454019a376aead95c8d4 *tests/testthat/test-add.R 6a4b676caccfb2f519997cf08b599e74 *tests/testthat/test-data-frame.R 80a0283930852c3ad22bf4359718d207 *tests/testthat/test-enframe.R 61a516ac943fde18e4ab8391a69e6f04 *tests/testthat/test-glimpse.R 65296c0e4c36d4d8e94c3516086b5ed1 *tests/testthat/test-has-name.R d3461033057a5f00a8a1ef58ef7f0302 *tests/testthat/test-lst.R 7ba4d9921b35075da770bbaa50a93ff9 *tests/testthat/test-matrix.R 1ac09eb169a03e5aa126e1a0bee72250 *tests/testthat/test-options.R 257131d73135fdceaef99cb9fbcb758c *tests/testthat/test-repair_names.R 5721206d4b58044e5505ce8f589cb546 *tests/testthat/test-rownames.R 05e02b762e4ae5f71f13ee64d4cd5845 *tests/testthat/test-string-to-indices.R bbc2886830d9c035214f16745037dca5 *tests/testthat/test-tbl-df.R be9d5b4ce2b894b94330f0ecc6849b60 *tests/testthat/test-tidy_names.R 440db24addc4cc4c45930aa040ae5596 *tests/testthat/test-tribble.R 76c1a30d3cd825572fadc08f49ccb79e *tests/testthat/test-trunc-mat.R 24859ead9ba31215eddee63a7eb656b6 *tests/testthat/test-type_sum.R da328f79bc7a73d2b0de95fd5afcda06 *tests/testthat/test-utils-format.R e4d2cfc1114090950739ab0085ce0f26 *vignettes/extending.Rmd d827ea23f552c20d92d909dcd7553739 *vignettes/tibble.Rmd tibble/build/0000755000176200001440000000000013217741055012617 5ustar liggesuserstibble/build/vignette.rds0000644000176200001440000000033213217741055015154 0ustar liggesusersuM0F  xNlmM1yrp(- ڙo6018c/l=XyE&YTe?~Hn%kVo\/rHU2P":$$ЈfSRS&VD (#}U !P= f8Fל4HA'#)tibble/DESCRIPTION0000644000176200001440000000271113220301602013207 0ustar liggesusersPackage: tibble Encoding: UTF-8 Version: 1.4.1 Title: Simple Data Frames Description: Provides a 'tbl_df' class (the 'tibble') that provides stricter checking and better formatting than the traditional data frame. Authors@R: c( person("Kirill", "Müller", , "krlmlr+r@mailbox.org", c("aut", "cre")), person("Hadley", "Wickham", , "hadley@rstudio.com", "aut"), person("Romain", "Francois", , "romain@r-enthusiasts.com", "ctb"), person("RStudio", role = "cph") ) URL: http://tibble.tidyverse.org/, https://github.com/tidyverse/tibble BugReports: https://github.com/tidyverse/tibble/issues Depends: R (>= 3.1.0) Imports: crayon, methods, pillar, rlang, utils Suggests: covr, dplyr, import, knitr (>= 1.5.32), microbenchmark, mockr, nycflights13, testthat, rmarkdown, withr LazyData: yes License: MIT + file LICENSE RoxygenNote: 6.0.1 VignetteBuilder: knitr Collate: 'add.R' 'as_tibble.R' 'check-names.R' 'compat-lazyeval.R' 'compat-purrr.R' 'enframe.R' 'exports.R' 'glimpse.R' 'has-name.R' 'tibble.R' 'lst.R' 'new.R' 'repair-names.R' 'rownames.R' 'strrep.R' 'tbl-df.r' 'tibble-pkg.R' 'tribble.R' 'type-sum.r' 'utils-format.r' 'utils.r' 'wrap.R' NeedsCompilation: yes Packaged: 2017-12-24 15:05:17 UTC; muelleki Author: Kirill Müller [aut, cre], Hadley Wickham [aut], Romain Francois [ctb], RStudio [cph] Maintainer: Kirill Müller Repository: CRAN Date/Publication: 2017-12-25 23:02:26 UTC tibble/man/0000755000176200001440000000000013204634213012264 5ustar liggesuserstibble/man/add_column.Rd0000644000176200001440000000171513204634213014664 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/add.R \name{add_column} \alias{add_column} \title{Add columns to a data frame} \usage{ add_column(.data, ..., .before = NULL, .after = NULL) } \arguments{ \item{.data}{Data frame to append to.} \item{...}{Name-value pairs, passed on to \code{\link[=tibble]{tibble()}}. All values must have one element for each row in the data frame, or be of length 1.} \item{.before, .after}{One-based column index or column name where to add the new columns, default: after last column.} } \description{ This is a convenient way to add one or more columns to an existing data frame. } \examples{ # add_column --------------------------------- df <- tibble(x = 1:3, y = 3:1) add_column(df, z = -1:1, w = 0) # You can't overwrite existing columns \dontrun{ add_column(df, x = 4:6) } # You can't create new observations \dontrun{ add_column(df, z = 1:5) } } \seealso{ Other addition: \code{\link{add_row}} } tibble/man/figures/0000755000176200001440000000000013204634213013730 5ustar liggesuserstibble/man/figures/logo.png0000644000176200001440000006500013204634213015377 0ustar liggesusersPNG  IHDRxb]esRGB pHYs  iTXtXML:com.adobe.xmp Adobe ImageReady 1 ).=@IDATxܽ gYΙ}LMKRhKBi WYEZEEYU\EE tt-ݷ4M2r=t -Rx3;pg)SaaL1W'xb颋.ZYg檪}iTrݻwȧ|֮][;:~X~XRGN bA @jAr-5.+懳k @lMXԳ7V y^M>/<{_~HZZ,ׁҗ~ff\ܵ\&ԀTUkUTOqmmm/|T;*bEzVӟnNJX8Sqc,bf*sz D?B4w: D@f gq,A8%q;w5+ɩ"VΝK}Á:Rcc}\hSLE3e\K/ƌP7@$гsftr\b߇ıȝ[LG}#iµzݖjY əD?4\)0^[WO:v,1R mxx<=g( O*Y-%&FTSCC]B|x\JԫW?߼m۶g?7\r%aѺXOYU:F@.YwF$.RcMpPڳ{_"PyYJKk;fRm] M%WlgaD&<_b"Oz*")^ugA wщp׾ֳ33ph:olTۀEqk'2]U9@J7u(v~./߾+n.M_ ᭧Lz! 1 ,\ !yPxQ_LCS43x !Te\vfxu ɲZiWWaH<6aѕjtey?SQ??eDtEVg\ |+nϹ1t"g"7L jR U] V6`)545yi)-E'ظzߵ=pH?ӷ!7m߾}}}U@{#X=;>>^"w,^< \"[A#:8wW\|2d.r8ZXO䑋oZ w Hk@jM(A*yuYUw+RGuԏ u2Zs';7<y۵z G~`F@dU-?ʋuill. ͦk"SnE@ QHU2 zSmMuIiúm4,崥-[ۑDi"t29{'N%W-  WF d a=;8[xOxIppC҆0bH~盩 O'xT:mү\YBkjk'RKk}^۔:;[R-[$/jKcOiC w69$yREiiWZ(_h_rilt*y`:^9544<=AӒ3-Y^6-T%#_x4WLMM}N:'NO!BKaVb"UjzΫSo7:y|1+zVp[{K猒b3-p_5馛A6577ow Zi[hhD4ýoWSԳ蘌7֫^=s|{KHt3v{ XӒ܉l߾#|?H'[DՅ jd:|h~Vc@=p/ȝ_"oh1%gRKԷ]%wS___ ~ZȐ ׊\&$D(Jv-uwoH5Ws973LĪ1MMϤyBDnh~@WX Kf]fil`]d0CBdR?ux ۉ/z&c#SZ>b@)ǟNw>旦6#b'>rR0<ܙlA"@g CptgH%Hv=,bib*$&7d~Ipi^.^ܤ+ ԛ&0Ts~u\֯m @>+(N "+׳] wcռrQe[m~ijmmbPVG?s^Y^g:k |u'7DFr+\H(;6\6DFssuZxrm-nz}\.3ӒQEzvi@gWLQseLUi{mxtc~ Z7bM*xZ/MSlٞX2ЬGBc 'Ğ0$9sd= `U-s%~u;ӕc#sk?||v{]!-Dyu\› ^HZIԱ|Z wZǴdNU\ˣ0 HƇ&@tD 2'eAm`R@cZ`Rݞ,$2i!`p֮+.@LCXNdPt4r^vtnj.qxT " hXh9 MXITlk׷v5O&c玅&+#\a?z:m[HX {*I"K 9 Y>+QONK`3i<ấ=T V~8wTH #0fҞSkG#T z0B;*rS 7hL]/z뢅mX Cty( f1m uA8v R*xuC'?ŝگ߀eYA"Kو;&61H% 3u#"7GP{iAbNo߾z C1_Qo0}G%].aN1W:1<&Bl-P n 3C|a~خyP,}܃X̻H;s.mH bYT:o7]NzX?ۖ`f CDHֶ V.-0uE9g= N^S)M<P; }QbUNbLMboIVq(977x>T~U*ys}&%pR-Ҭ{zՋP&# I9Ȱ]:8-(o :;%ؐё n`f)m]7q"3E|gJ1 9c6vzo @frھ$/Rv&޴gEDPJ'qƖ絿6竒׼ #}s_0-ڽ Ok̮~2*RƸ|Ѥs9gȼKp12)hTcC}>F)9GQ(s"NGU ˋD)Ua] $U]JW=0TٳZ|x:RFP 7ީc~5癤"u'izpo9@J=[cgO! eА FT:1Ŵ* OT G#6b6p|.$ .2&EWFQhn7/,``-w 0ifI] [n-˳CӒr~V܉0KXA0n3q\Elud$VȢpF]XD"j}g}orcB:NO0>7>za)-fWO~~*|ǚ'7`*m(Lr }&O~~27{M Q_slz0!2?:*}Ͼs"=tpXRzxٰ1y_؞I46Tk1~ R",!ApQ{A@tGgs \1\VpYMNL r)&J] 1;Ef( /ƚ(ő>9S Z3j2{VT5v #qwM ץMt:Sg[\^Jti Et5+^pzC)".-Vhu1gRvSg\ AM/Phn0板Иv4#")'edEn6QoB.zz=0[VlqȝMpr xkF-7,"k/=7Z!=G *tޡ806u:ִDhF#m%FMVGH έ;ו%mJժucug])gDa,]%UcESc/w]j{4зp7>n8]K-Z|"Ypo]Lt1O;0dRzIu1!HQ]̦\:js)v3wkkIkkKp-U鞻M̸q`Qť5T3M+ {NB)s;,k$Y6L) h#ә "lK9}ϱx@~PaBN;P,<)n;eUc> dfI-BrRzͧ<^ Y].fDcXS.mjXXr@|*}F_= 奓J)[ hC $< Rx[RN +1fk4-ptK +p ⦢WѣaꂙitV2 00vMtl#Ód;*5K0^F!8r,HfI'sDK3 +'{7g's+~pL2KU/Mm-E% ,nö[@br|OW?6to{_DZ)zq6mټ6=u{l ~ ^HlQQR--e'l(( g͚X][GIp Cvb9*NEI _x`F*p,LI'֥, !kY.K, D󦭭uihl)ǚRxb֧ ,R: v @O6Dԣ55>[#*MOkjnܡ$|JnJy&Z<ĊMu{xaS 4ƛ/FD`M.Ü GQ]Ǘg0&R6d-Aİ a@g엛S VTK^ & N*jc -cutW„\,Ʌ  Q2Kkkӝߙ ݉襣X_q6]q;/WS:鼗ϤZ:<ۑ8+oF4Ԥ}>ƕ. 4.8qJu8ꖓ'+Z5!ߣ3Zr%G>mD?F_Ȑ3 kURV`v3rjt~"z|t(tF )-NC.:$0RzRT}$ 11rIC̗fGUy q;[2F)ssM`.TSr`R}̽U[HI8>vbcc9\WPu7(W0vSƫ .$,("e.V`:'CMSvAAƤ$21XBI"++V},M؁8BʣXխz^+7}{ohO'?bf_K9}* +*ĩC$fiJXJy,qj1 I8tw5Eؿq\t|O cD:>9 #u)洦[{#_t%D@I?\D;ה+Vw)esB]^ ~V6FtׄM-4TjniPkv cWU`!)Pd=/a~d8#`3ي?D0Oذqb*'N EI(x4+K]Z 5Eqx;EI}Ft?_Rδ΅Ԍ;.v=tva&ٻ2'ET\Na$/uitex]>WUS2io$mp{tyQvr-k~VyXGwRH3OCb3[L? c~_f!"z &-# FS)pp$[-pͱ 31D?".k^+2G<8#(Ny)g O.rQY^oɓ+G93vne Reu1ΧD$MtЍ-\X6pQ !)n8C#e\ۙz$Հ"g6R\J 8;fWB̕o&',+U9w.>A$Ho /bF[ogebȩJ? %mU@b g;g]X"MXhy+ E?3 ӋH~? DH{vO)v>R0PqQ=CjvuGHWx [an%& >b6dh^V`)F D>@Sut8Qy-/tt5Z*߀XJg?'Oաˌ>f66`]u!j$F|^U:9ՄYL5٭PYoZH%y4/q|ӓL86* 2WX\܋[iI0~^Jop ©KGo]8w :LX+G"L,켶 :QH9m۶ 1=̶yd"J;p֮:cPSӰƜTek`((>%#v::^JΆԳـtm P?[J'p pab, ܏} |Nb)tR,ޏ~Ɉǘ3緌v_N =6~YbM~)߶E>Mum97BLd*~.roEyLLa9^?Eo CT&i5<!BD`>k4s&<ȔhcdKɥ`MtR q&P|bڲm=! ~O`a#,T]w:{ i ;avv9.O}[Rw)?gkMX"R.ɡϋPԄp)e^f$Zwdȣ^m f|p_J WC$D[w \ɥ=  +p@palS9(j˲A 2&% MXL`5ŵ>/ƢwZŇLfwӘG+l]n]!e| iFTHxm^Kdݐ]3}ف0aMc>^HuӔn,#O*wnִmǶMCQ6mZb6F hcWh<5KΞͅUhFZLtX %P*Fa;bp-"T_uh5ʀFlWINU4p 8^lMgB 53]6MkY] XSyG!+vk KtW4͸1&\f_Mh amAfy7@on>i4pW$/]'R#)F)ab1Z+6ܒ Jd:ʃl gv74jy6,O`x`M3ybblL+R56uv[&TEC@oCC Vαo?W1Het,:1Ǩg?%ҋ)}&SܤQAHka$%)L-+5`Q{FXvѼHU a*s+Z:@23{D\{Б:"]쨥\5mf9JP1rI;qC{Nw޶Ad/KZVa'dNY5.PI!pH3@* rxn/ ZND)6\F@ϫCVk;^p}۶>u{DYnAֿ=Ϩ7WlD85\ePJ55XTR2Wu_r aJ4ɪFENdH"R$5V; ,N$R3K -vR52dNs {㴟JRoF45 ͟/81c$F[Bچe.|˄ b_Hʗ?t91f)a3e,cLB\m9WyCi ~+rsl?q%/.`\(BXǜ"UDRu8\튺NgAk ~XDn$LKcHyzDʐ5,BsY$k=y;1K^ep&>A 0 O܇l u j*or\oI@Uۭöwd3 )sڶCAPlb|T"k %GCLb vcy#8D4쌕D(ĂE% >E:ctb+6&^`5Av|_lƪجiÆuiQG+(^vNij2 T(cΤ]#F tT'1;\xޠ^(oYh|O;~=faparIC#1b·赯'܃PA](ٶ$sYke3{(Rjtδs F'Q#kIf o*G8I={f`Sop9 7:l#4w|g<ྴ +vtp~Y91~!2<Ե]PhK:^u xQÄ>Kff@u+^96vʝwGqDգ2L ͦLni:^;= to|X@/,/۰iMekppT:WC2F>ڨ"$@2SI"M~[bbexƽNM߿{nczkbn.uU ҭ0 ҆;SmϦ0AJ.ސf{?lޞLxzKyNfl3>[Y(l4 CHxqEVu|<~#,#=l1[žNk[M^XD]s "k[`Jw!3G0Q^Z5RU3g+Q#'5s+QT飩#4TyPTENfnaQȽ^_7t Y~dL:ݐe1H:-nT]G%aSgwiP<-.2n}U{]ݔ8s+w"eQZ|#R=An\Em u\FOW3JlLqoqj ZZ6?G `#'M(usI'PWG4:\Rz @}L7uHk"Ȳz!VrψgLU?ޕ:c\2e!YO۹<;!]&W^$,[^|qp4+b$d <~q8 0 4"z8*r$U(uTPa- Dmb}8KUAA-MYMulX9b9i5:FsXjr6UBhaKMAP`[ wZO_\3}.Nkqk"[C ;N0HZJHVKj3J)欍~Y#>ptE ;-HC,SR֋owBC9!˻[KeΦ2ͳZ1#[f-UW{]ip-+^U"Ni0*cx;tv !@D"ߑ=Ӳ>ƍGC=RKz'9Tcp-ױ£;?9ECŏ]#,~jp/9UĻHxd'mgUMm$K09ɪ薹d=ac3r G<0Ȯ0.X@>m i_?un_ RǁbR1ŎKe=*s;rD:sZ|(&0#( cQ+q["6 lWV"X;/,8$y,33h<ݦTB~FR>_ʫp Qx?e 1(w)*U >Ƀ@H<˺Rj #AʙS鏮hgze$UF^xd*IRQZ8b{F6oܖl؃I< @jXiɯ~Tn%pQS=G\ *,Ha qTm$3%Lʬc\8KѸRUah>=WuR@[$!CZU725Ϛk̄JkYBɋ#UőI/"7r5rmtL)r> KCA aӡ uV5e p_1:atJ7=oH7Dy@FڨS%KjNT[~M?1͎)7i,0l}]R]!ܳO&jp %i D>xeWZv] -W$Z_QNɒ(yw޻ҩ<3]r'z'UVt ƓIS}d'wF]!PLVuHd g-lKT&b0nio~}*`$[SpXn]zs+GOl{F!Wl峞> 6l?9mtWqϝeۮX]3 o^=;}}ǧk5 h C<6{O=ᴆI}ϾՊ/+~T b TαZS_Wc [jT,)\AmMoʳΤfryJP2䉄~:]~ܾss_^rAel~=m]/w6*!q1үt{oJk>'/fSY>*/3E*(X:CT">͔PܶZAinK/=s{g]="YTi/Xn>,`+htPBfcTyb$|uZ]}͝ZSq-WH(PS@n=V/҉GD^y:ڐ!?zZq' *Ԫq;9eorS"D8mM(HX8.k2ξ]!C(tOL]tw60_9E<;{eW@8O٩[$e1~w"0nbگ³"Vs߂Rh/VP7& E%$~퍻 d.W&.D5|@2WCtwph9j(vKRg1D Lr^ٓ ľA,AA9u6[D%{Y5lt 忐I6צ@JHPb|[iއ#ae-4.>;E!+f*1NKSu; oVVUXZ-7hb^@ّ`s 9١L.V{:-\1_ uWC(rq G&针rٌ6֘xC#e ``r tJ\ifd9yoעeU}ަ>BCϸFW*Dgb_gN&aS׭t@@VhIL~M8y퍡F & ٓgq`]ݭ]CTi 7{\>ɺ.Elrʷu0(/MDJ rMN$lw9`4;xl[jrw[M[u!51/RX{[bėFKp~x8cXZp %"IAy"]uadN +)B;Z~98z+- 4U%8R EAqh&UGj,*'{W=hkkgtѠ$}EmKzc}zI+ȵyy T!I`ThS,t!1#?IP4W^sxm K d9ϒWS׹yA:634FEw3'd9X c=[.DT}ծz{/Vq[b6~20W}L-dJ"{좶#P^{s); V[0BW4FR 1P-JB@׌!L`j8٥->iLq}l4yF]|G䯑0%{>o"B>K+b0&n?_H澐ZhSo`ci&J>>UkDalt.k*9zsDkdczg +Pm f_ln@c'n߿cD\|\#/f$"Y*/$5|IJ tEK3c d-xl$| "Z1W:YGþuGwS$?%=֩K]4p_5bp$CQ WӋvr*@pI FLx)ҹ<#.E< O1 s ʩcd?L"qWثjl/-,n+شwPjhl?&h/ͻ޹sCW9z}l0-6Ǻ8_Ձ$ױeESu@dgf6;~Ͳqݳ[L|'IDAT=lt"$JOd ¯*gL7FcRvحL%'H iWA @nHHz8`̈́A"`QtU1ΎrRb ]*-@Dĵleov3|UVeξ٘7c۸TV>Wm&ZO(גv#7֋ʹUknJMty0dzJ;\%Eo6;_o4 z Q^;F)Q q"0%i.O{  '+H4NXTCd1o0EۇewG3Mg?vUnd?E23A2{C{^fit^|APX {\q-‘\AYgLc #*E,\Lhr*Q}KR}} G 8t2D RP^Okbi=Nuel3@_c?vB:%;CgHƷmj-_~'U& Ƿlӏ洡}&%ʛ8 l^ýkMr,5zjN;04">΢2Nq !ah&ao)2|FdQKݙ~  ڶ\@1^{Xdeƻֱl9t@'د!t J[[E *oY6#"$gӽmm9p6(nX!oGpA51+j4"(Ni/1WefE_ɋ:B  9U,E rh;O۷oK/(~ǏʝnsasDNaBÃMx:1%hIEP"D"zƏhxMu:r={E囯\AD|+6O{B:k hhbo$uczqz jUs?:hpQ[;rٛA^K3ѫUZx = q*tfF@a(ס}^w:Pb<Ӊ6zT_t\Zߞ: 4N9dXu@9b:cW$RtkB5{T fAb[v ߅:!@ 4hJ'.8)]+G0EP#F'a2Y`LSk."v lUQaԄHLDTq[P _]j/M?75;kJk:ֹ]LGXE8n:;%22ӄ.j0`fu@ۥ4L17e`B*YZw> ιHcDRK_;3X^ +qPjޛ^tǞtT$R0KއyEKeoI&5 94&Z xjd9_ܑI iR.w,mD訓׍+ҎTIڲcPFӉ' Wq]X)rx\8u;*xqI[GSr,Sda٘pwHH^+H*循 ǤjVE:(d> aՓDPhoLwouyjR3ٚ:> Sg0#L4R?X>֑Ҏg%&\mPpa+Z\wt\noeTWp-McbZqggܽarc:, b_zI7hO+' lɆ ,w{3@6HsO١;xcDbAkpK:t~: dTAVIeSe.ap5"}1\T̙}lAy"*NKA[KJR,6p?? b+zPtV-wm"JF)jp0ΗUŪIcXXnu$Qt O5HWh5 Г譕5zC8 ȽU Kwb7Y\ּ8ʤ>1@n1x8f"9X)k[&C9iydVjls Jes(\ӡG=|幽Y!{3t]#Q)#4vtgm *4st-YK0nH$ ?~dkzvBx /5S3dCLtQ;ߝ>^/ru_pzCQ5q(MU=XL1kfjdw=^U8O gJ]TꄾqX `<ʎՔ̹^{ Y(ˋ.Hάz TML8X7MmpjC'ϳ dSlp ځZPUjÛӭ-qų̒'E%H[ib(nܺ.#6eeWxDoW U*3bLSW,Ԥkv=WK*ܳaЩ2{j 2QrFDY.; &UIN,u-7PN>PzquZvބӅ mZ5&ypwrM9owU, +ZUt:0`KJ } [p}쉼r1D t7*y+~+&~yb=2D%5e{x{ }1)Z|<*V j5ɔ>E(߷5uiO 㚣؊?h)0 ԷAk׮ary:KgʵY`BE@'!Wt[*>7\^P8Ut%Zn|pU-z  h= DG@e~짰ʛ'~[>8;qʆ&}:g0-I&N: g8e[jh%oٔzB7EQZl66͔frcdȷ7H]K)~E֡d1Q W"RWt פ=`lӞ[^Ml9:pݽfS[wWQ?)1~"\+\6aS5،'c|@ApwўԧKmǢSC3 5*$L0CGvA@Cp3pغ -FX1]zA!jxo}ksJ9mɤQÆRl  `cRo("N{^`e8Y#:6r4Ggrb(bf]zUPݕ ̱V w䗂c^Ö912HIc}sTG9dP8~g~sV5,"Rdq_3 ^)B]9h#!yDc72>)ޘ"8cI۽W MJ*.@^Bά1$-0 .\椧k=H"UBwpⱩ6|< ZsnWP}o6!;|0*+8&n`&<@uy`gw>b"V]Cnm}O+3O99w8mZM˶\:G8XIdu^Ų<.r^Gb  \-/Q|\gao!2_jC`U\ nzKlB k4IcT[ڋY@.S5gw_^I)E:3a>Sy ѷ)5m83tp,h NٰaMW)""}㊡V$m(ԧN}8W:ZM`"C<ͷe'T1Fyǚm3sgkӆ³^n*OUzh6՚6nnX6Xʫ_As ^Foߑ>AǸ/qo$z0%YkGx `!䘶oY4(@snk=t%M\nD~59Úu*EZx6ߓVp.w:q'\/盌bwLm <^-G/ IrMPQxk ǩX, lH+l"|» ;T̀p],^q1[,Bx|_ p?կ~S]k׮ݻw[,i fB9'@Q63ȉ28mANŲQi2d r"OHݨw0R-cw-|vJdw*5gŵD"Ο3'C b.A($LWH dk2XñEHt;b 7(J' NB[8m YsDrY(̫W|>oꪫn]Zr]uir-裏2)!,kGۙd\wrsR vV ,f;/%N)Lv^X{}$wM7}+j[¥0qgem:ݒ"؇"~&#㛚g ʕJ;2J%{!C(LEfɰ!#ENt}P9K{-K}zx荖ȴnGB0y-B63Iz^{ߴlqm,8E?H>ҘMAC TAN{Nx㳢^*uβi-!wͭb"j_(_Z@\n~K/ D.DXjmO:@ޖg PN@DLb0P}lto!:iU\MCQ1j,m楜D,[K|{_|q8qޑ57xc@/x{ lH3 zO` HֺqÎy-I)֗Qd5. ` IKmYumC%rT5,˷sD}B}I#grHQ̠Zy'P>Y4Ӱ}?J&h}-5Lamu+}ͰE.` ;]vRRςlT HY{(^ޭDyfWP6?֎_L= V^ -H"? #0KDFaYƏy$ P$ eza} y'05"e%6o^eVB, 5ZG"M&mE q"vL^{Զ5 .inj-}@=ӧ>lQx\Iy'.0 ^@GnӥCc-ՃbĤG tox0@>TA2eQqf@/s!e(ĝv4~ڣQlk8VFȩN-?p0 6&p$a{BL@A!@Ƅկr9ihh*m-|V1^㐞|Jo~giEB~ ֡B K(9gC&&$<["\ J7`AWiLfY''5hvc:;@Lgw ȐUYGQ2Wm( L]B<ZY|o\!=ӎcNrL"ȸ/q饗^sbA'Q@3bBDpShكUIXꢾD2OfdĉTw6"Q./_; g]&XR Ǜè=]OO/{0`~,I I_<9Q&1Q|A;탈]vu{,x{RRR nppmpd{Wg;\8V(*buU$2 071W \DJi97\#8O_V;`u~iozVzɏ&Mpc[V}[=}wcܐdhO/8$GYJ '=itj~>sYV_ŭSEA}{G0>0{guQZL9چN8 1>g@"!%`_֛g^gO@4- R>`vUʴoQK' XSۥFZS=aq[C>s}~׿!vHqg⊫җܡ]7#[[rL^M#dclg/ = o9-;fžIp#b9es 2hP%R${=m̞W{ &ž,MW]K,_"E,DuHJ0=~_ۧ#';}_\ Bᡟ ~^uZRnuU_)ŬƗvE&"!0ul?yg:s5ÿ6nڈGȒW\yu'> գѱ` me l~_LxVd+]D}kE(\[$4}cEؓ%.%l*Z #!r}b Ccwo6뮻>ql% q|FUr ҳcqtW^y~Y}TBpB%Q]9)gh< {$E)E,ATG(NEnn}J[-9=GNO{z΋/zkBj=od6iD=_v\)iBgxr. z,ӒBV2``45ܫgf g]m96 %Ͻ8OKW_sL ܪhzq? bw4G'%=e\^vZ1}ZaV8yy]' :ڛk_,&8~5SO9=6{!)@.yE@"sfo<SNK9:02̴0ѰY0D]\t:t(  AT~ 'XhDM=һ I.s׼%W4=S=;G?M =zNIiKo:kUr  ҒnђihIr hZ V;X'TK \.7KUm$ZSXeReZCrJ/)9 Hrž׆ , B7H^tk~%:1‹$PHv|UВ| xG%5 xܫl]mG Y[=纏Ӳopl"TV˞/y g[@ Whے:FƋƉ%n2|~fBMJor*?IENDB`tibble/man/enframe.Rd0000644000176200001440000000147013204634213014172 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/enframe.R \name{enframe} \alias{enframe} \alias{deframe} \title{Converting atomic vectors to data frames, and vice versa} \usage{ enframe(x, name = "name", value = "value") deframe(x) } \arguments{ \item{x}{An atomic vector (for \code{enframe()}) or a data frame (for \code{deframe()})} \item{name, value}{Names of the columns that store the names and values} } \value{ A \link{tibble} } \description{ \code{enframe()} converts named atomic vectors or lists to two-column data frames. For unnamed vectors, the natural sequence is used as name column. \code{deframe()} converts two-column data frames to a named vector or list, using the first column as name and the second column as value. } \examples{ enframe(1:3) enframe(c(a = 5, b = 7)) } tibble/man/tidy_names.Rd0000644000176200001440000000345013204634213014711 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/repair-names.R \name{set_tidy_names} \alias{set_tidy_names} \alias{tidy_names} \alias{repair_names} \title{Repair object names.} \usage{ set_tidy_names(x, syntactic = FALSE, quiet = FALSE) tidy_names(name, syntactic = FALSE, quiet = FALSE) repair_names(x, prefix = "V", sep = "") } \arguments{ \item{x}{A named vector.} \item{syntactic}{Should all names be made syntactically valid via \code{\link[=make.names]{make.names()}}?} \item{quiet}{If \code{TRUE} suppresses output from this function} \item{name}{A character vector representing names.} \item{prefix}{A string, the prefix to use for new column names.} \item{sep}{A string inserted between the column name and de-duplicating number.} } \value{ \code{x} with valid names. } \description{ \code{tidy_names()} ensures its input has non-missing and unique names (duplicated names get a suffix of the format \code{..#} where \code{#} is the position in the vector). Valid names are left unchanged, with the exception that existing suffixes are reorganized. \code{tidy_names()} is the workhorse behind \code{set_tidy_names()}, it treats the argument as a string to be used to name a data frame or a vector. \code{repair_names()} is an older version with different renaming heuristics, kept for backward compatibility. New code should prefer \code{tidy_names()}. } \examples{ # Works for lists and vectors, too: set_tidy_names(3:5) set_tidy_names(list(3, 4, 5)) # Clean data frames are left unchanged: set_tidy_names(mtcars) # By default, all rename operations are printed to the console: tbl <- as_tibble(structure(list(3, 4, 5), class = "data.frame"), validate = FALSE) set_tidy_names(tbl) # Optionally, names can be made syntactic: tidy_names("a b", syntactic = TRUE) } tibble/man/as_tibble.Rd0000644000176200001440000000570613204634213014507 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/as_tibble.R \name{as_tibble} \alias{as_tibble} \alias{as_tibble.tbl_df} \alias{as_tibble.data.frame} \alias{as_tibble.list} \alias{as_tibble.matrix} \alias{as_tibble.table} \alias{as_tibble.NULL} \alias{as_tibble.default} \alias{as.tibble} \alias{as_data_frame} \title{Coerce lists and matrices to data frames.} \usage{ as_tibble(x, ...) \method{as_tibble}{tbl_df}(x, ..., validate = FALSE, rownames = NULL) \method{as_tibble}{data.frame}(x, validate = TRUE, ..., rownames = NA) \method{as_tibble}{list}(x, validate = TRUE, ...) \method{as_tibble}{matrix}(x, ..., rownames = NULL) \method{as_tibble}{table}(x, n = "n", ...) \method{as_tibble}{NULL}(x, ...) \method{as_tibble}{default}(x, ...) } \arguments{ \item{x}{A list. Each element of the list must have the same length.} \item{...}{Other arguments passed on to individual methods.} \item{validate}{When \code{TRUE}, verifies that the input is a valid data frame (i.e. all columns are named, and are 1d vectors or lists). You may want to suppress this when you know that you already have a valid data frame and you want to save some time, or to explicitly enable it if you have a tibble that you want to re-check.} \item{rownames}{If \code{NULL}, remove row names (default for matrices, may become default for data frames in the future). If \code{NA}, keep row names (current default for data frames). Otherwise, the name of the new column that will contain the existing row names.} \item{n}{Name for count column, default: \code{"n"}.} } \description{ \code{\link[=as.data.frame]{as.data.frame()}} is effectively a thin wrapper around \code{data.frame}, and hence is rather slow (because it calls \code{\link[=data.frame]{data.frame()}} on each element before \link{cbind}ing together). \code{as_tibble} is a new S3 generic with more efficient methods for matrices and data frames. } \details{ This is an S3 generic. tibble includes methods for data frames (adds tbl_df classes), tibbles (returns unchanged input), lists, matrices, and tables. Other types are first coerced via \code{as.data.frame()} with \code{stringsAsFactors = FALSE}. \code{as_data_frame} and \code{as.tibble} are aliases. } \examples{ l <- list(x = 1:500, y = runif(500), z = 500:1) df <- as_tibble(l) m <- matrix(rnorm(50), ncol = 5) colnames(m) <- c("a", "b", "c", "d", "e") df <- as_tibble(m) # as_tibble is considerably simpler than as.data.frame # making it more suitable for use when you have things that are # lists \dontrun{ if (requireNamespace("microbenchmark", quiet = TRUE)) { l2 <- replicate(26, sample(letters), simplify = FALSE) names(l2) <- letters microbenchmark::microbenchmark( as_tibble(l2, validate = FALSE), as_tibble(l2), as.data.frame(l2) ) } if (requireNamespace("microbenchmark", quiet = TRUE)) { m <- matrix(runif(26 * 100), ncol = 26) colnames(m) <- letters microbenchmark::microbenchmark( as_tibble(m), as.data.frame(m) ) } } } tibble/man/tibble.Rd0000644000176200001440000000410313217670640014022 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tibble.R, R/lst.R \name{tibble} \alias{tibble} \alias{tibble_} \alias{data_frame} \alias{data_frame_} \alias{lst} \alias{lst_} \title{Build a data frame or list.} \usage{ tibble(...) tibble_(xs) lst(...) lst_(xs) } \arguments{ \item{...}{A set of name-value pairs. Arguments are evaluated sequentially, so you can refer to previously created variables. These arguments are processed with \code{\link[rlang:quos]{rlang::quos()}} and support unquote via \code{!!} and unquote-splice via \code{!!!}.} \item{xs}{A list of unevaluated expressions created with \code{~}, \code{\link[=quote]{quote()}}, or (deprecated) \code{\link[lazyeval:lazy]{lazyeval::lazy()}}.} } \description{ \code{tibble()} is a trimmed down version of \code{\link[=data.frame]{data.frame()}} that: \itemize{ \item Never coerces inputs (i.e. strings stay as strings!). \item Never adds \code{row.names}. \item Never munges column names. \item Only recycles length 1 inputs. \item Evaluates its arguments lazily and in order. \item Adds \code{tbl_df} class to output. \item Automatically adds column names. } \code{lst()} is similar to \code{\link[=list]{list()}}, but like \code{tibble()}, it evaluates its arguments lazily and in order, and automatically adds names. } \examples{ a <- 1:5 tibble(a, b = a * 2) tibble(a, b = a * 2, c = 1) tibble(x = runif(10), y = x * 2) lst(n = 5, x = runif(n)) # tibble never coerces its inputs str(tibble(letters)) str(tibble(x = list(diag(1), diag(2)))) # or munges column names tibble(`a + b` = 1:5) # You can splice-unquote a list of quotes and formulas tibble(!!! list(x = rlang::quo(1:10), y = quote(x * 2))) # data frames can only contain 1d atomic vectors and lists # and can not contain POSIXlt \dontrun{ tibble(x = tibble(1, 2, 3)) tibble(y = strptime("2000/01/01", "\%x")) } lst(n = 5, x = runif(n)) # You can splice-unquote a list of quotes and formulas lst(!!! list(n = rlang::quo(2 + 3), y = quote(runif(n)))) } \seealso{ \code{\link[=as_tibble]{as_tibble()}} to turn an existing list into a data frame. } tibble/man/add_row.Rd0000644000176200001440000000245513204634213014200 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/add.R \name{add_row} \alias{add_row} \alias{add_case} \title{Add rows to a data frame} \usage{ add_row(.data, ..., .before = NULL, .after = NULL) } \arguments{ \item{.data}{Data frame to append to.} \item{...}{Name-value pairs, passed on to \code{\link[=tibble]{tibble()}}. Only columns that exist in \code{.data} can be used, unset columns will get an \code{NA} value.} \item{.before, .after}{One-based row index where to add the new rows, default: after last row.} } \description{ This is a convenient way to add one or more rows of data to an existing data frame. See \code{\link[=tribble]{tribble()}} for an easy way to create an complete data frame row-by-row. } \details{ \code{add_case()} is an alias of \code{add_row()}. } \examples{ # add_row --------------------------------- df <- tibble(x = 1:3, y = 3:1) add_row(df, x = 4, y = 0) # You can specify where to add the new rows add_row(df, x = 4, y = 0, .before = 2) # You can supply vectors, to add multiple rows (this isn't # recommended because it's a bit hard to read) add_row(df, x = 4:5, y = 0:-1) # Absent variables get missing values add_row(df, x = 4) # You can't create new variables \dontrun{ add_row(df, z = 10) } } \seealso{ Other addition: \code{\link{add_column}} } tibble/man/reexports.Rd0000644000176200001440000000117313204634213014610 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/has-name.R, R/type-sum.r \docType{import} \name{reexports} \alias{reexports} \alias{has_name} \alias{reexports} \alias{obj_sum} \alias{reexports} \alias{type_sum} \alias{reexports} \alias{is_vector_s3} \title{Objects exported from other packages} \keyword{internal} \description{ These objects are imported from other packages. Follow the links below to see their documentation. \describe{ \item{pillar}{\code{\link[pillar]{obj_sum}}, \code{\link[pillar]{type_sum}}, \code{\link[pillar]{is_vector_s3}}} \item{rlang}{\code{\link[rlang]{has_name}}} }} tibble/man/rownames.Rd0000644000176200001440000000326413204634213014413 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rownames.R \name{rownames} \alias{rownames} \alias{has_rownames} \alias{remove_rownames} \alias{rownames_to_column} \alias{rowid_to_column} \alias{column_to_rownames} \title{Tools for working with row names} \usage{ has_rownames(df) remove_rownames(df) rownames_to_column(df, var = "rowname") rowid_to_column(df, var = "rowid") column_to_rownames(df, var = "rowname") } \arguments{ \item{df}{A data frame} \item{var}{Name of column to use for rownames.} } \description{ While a tibble can have row names (e.g., when converting from a regular data frame), they are removed when subsetting with the \code{[} operator. A warning will be raised when attempting to assign non-\code{NULL} row names to a tibble. Generally, it is best to avoid row names, because they are basically a character column with different semantics to every other column. These functions allow to you detect if a data frame has row names (\code{has_rownames()}), remove them (\code{remove_rownames()}), or convert them back-and-forth between an explicit column (\code{rownames_to_column()} and \code{column_to_rownames()}). Also included is \code{rowid_to_column()} which adds a column at the start of the dataframe of ascending sequential row ids starting at 1. Note that this will remove any existing row names. } \details{ In the printed output, the presence of row names is indicated by a star just above the row numbers. } \examples{ has_rownames(mtcars) has_rownames(iris) has_rownames(remove_rownames(mtcars)) head(rownames_to_column(mtcars)) mtcars_tbl <- as_tibble(rownames_to_column(mtcars)) mtcars_tbl column_to_rownames(as.data.frame(mtcars_tbl)) } tibble/man/new_tibble.Rd0000644000176200001440000000345613204634213014675 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/new.R \name{new_tibble} \alias{new_tibble} \title{Constructor} \usage{ new_tibble(x, ..., nrow = NULL, subclass = NULL) } \arguments{ \item{x}{A tibble-like object} \item{...}{Passed on to \code{\link[=structure]{structure()}}} \item{nrow}{The number of rows, guessed from the data by default} \item{subclass}{Subclasses to assign to the new object, default: none} } \description{ Creates a subclass of a tibble. This function is mostly useful for package authors that implement subclasses of a tibble, like \pkg{sf} or \pkg{tibbletime}. } \details{ \code{x} must be a named (or empty) list, but the names are not currently checked for correctness. The \code{...} argument allows adding more attributes to the subclass. The \code{row.names} attribute will be computed from the \code{nrow} argument, overriding any existing attribute of this name in \code{x} or in the \code{...} arguments. If \code{nrow} is \code{NULL}, the number of rows will be guessed from the data. The \code{new_tibble()} constructor makes sure that the \code{row.names} attribute is consistent with the data before returning. The \code{class} attribute of the returned object always consists of \code{c("tbl_df", "tbl", "data.frame")}. If the \code{subclass} argument is set, it will be prepended to that list of classes. } \examples{ new_tibble(list(a = 1:3, b = 4:6)) # One particular situation where the nrow argument is essential: new_tibble(list(), nrow = 150, subclass = "my_tibble") # It's safest to always pass it along: new_tibble(list(a = 1:3, b = 4:6), nrow = 3) \dontrun{ # All columns must be the same length: new_tibble(list(a = 1:3, b = 4.6)) # The length must be consistent with the nrow argument if available: new_tibble(list(a = 1:3, b = 4:6), nrow = 2) } } tibble/man/tbl_sum.Rd0000644000176200001440000000116613204634213014224 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/type-sum.r \name{tbl_sum} \alias{tbl_sum} \title{Provide a succinct summary of an object} \usage{ tbl_sum(x) } \arguments{ \item{x}{Object to summarise} } \description{ \code{tbl_sum()} gives a brief textual description of a table-like object, which should include the dimensions, the data source, and possible grouping (for \code{dplyr}). The default implementation forwards to \code{\link[pillar:obj_sum]{pillar::obj_sum()}}. } \seealso{ \code{\link[pillar:type_sum]{pillar::type_sum()}}, \code{\link[pillar:is_vector_s3]{pillar::is_vector_s3()}} } tibble/man/tibble-package.Rd0000644000176200001440000000463513204634213015415 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tibble-pkg.R \docType{package} \name{tibble-package} \alias{tibble-package} \title{tibble: Simple Data Frames} \description{ Provides a 'tbl_df' class (the 'tibble') that provides stricter checking and better formatting than the traditional data frame. } \details{ The S3 class \code{tbl_df} wraps a local data frame. The main advantage to using a \code{tbl_df} over a regular data frame is the printing: tbl objects only print a few rows and all the columns that fit on one screen, describing the rest of it as text. } \section{Methods}{ \code{tbl_df} implements four important base methods: \describe{ \item{print}{By default only prints the first 10 rows (at most 20), and the columns that fit on screen; see \code{\link[=print.tbl]{print.tbl()}}} \item{\code{[}}{Never simplifies (drops), so always returns data.frame} \item{\code{[[}, \code{$}}{Calls \code{\link[=.subset2]{.subset2()}} directly, so is considerably faster. Returns \code{NULL} if column does not exist, \code{$} warns.} } } \section{Important functions}{ \code{\link[=tibble]{tibble()}} and \code{\link[=tribble]{tribble()}} for construction, \code{\link[=as_tibble]{as_tibble()}} for coercion, and \code{\link[=print.tbl]{print.tbl()}} and \code{\link[=glimpse]{glimpse()}} for display. } \section{Package options}{ Display options for \code{tbl_df}, used by \code{\link[=trunc_mat]{trunc_mat()}} and (indirectly) by \code{\link[=print.tbl]{print.tbl()}}. \describe{ \item{\code{tibble.print_max}}{Row number threshold: Maximum number of rows printed. Set to \code{Inf} to always print all rows. Default: 20.} \item{\code{tibble.print_min}}{Number of rows printed if row number threshold is exceeded. Default: 10.} \item{\code{tibble.width}}{Output width. Default: \code{NULL} (use \code{width} option).} \item{\code{tibble.max_extra_cols}}{Number of extra columns printed in reduced form. Default: 100.} } } \seealso{ Useful links: \itemize{ \item \url{http://tibble.tidyverse.org/} \item \url{https://github.com/tidyverse/tibble} \item Report bugs at \url{https://github.com/tidyverse/tibble/issues} } } \author{ \strong{Maintainer}: Kirill Müller \email{krlmlr+r@mailbox.org} Authors: \itemize{ \item Hadley Wickham \email{hadley@rstudio.com} } Other contributors: \itemize{ \item Romain Francois \email{romain@r-enthusiasts.com} [contributor] \item RStudio [copyright holder] } } tibble/man/knit_print.trunc_mat.Rd0000644000176200001440000000045413204634213016732 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils-format.r \name{knit_print.trunc_mat} \alias{knit_print.trunc_mat} \title{knit_print method for trunc mat} \usage{ knit_print.trunc_mat(x, options) } \description{ knit_print method for trunc mat } \keyword{internal} tibble/man/tribble.Rd0000644000176200001440000000157613204634213014207 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tribble.R \name{tribble} \alias{tribble} \alias{frame_data} \title{Row-wise tibble creation} \usage{ tribble(...) } \arguments{ \item{...}{Arguments specifying the structure of a \code{tibble}. Variable names should be formulas, and may only appear before the data.} } \value{ A \link{tibble}. } \description{ Create \link{tibble}s using an easier to read row-by-row layout. This is useful for small tables of data where readability is important. Please see \link{tibble-package} for a general introduction. } \details{ \code{frame_data()} is an older name for \code{tribble()}. It will eventually be phased out. } \examples{ tribble( ~colA, ~colB, "a", 1, "b", 2, "c", 3 ) # tribble will create a list column if the value in any cell is # not a scalar tribble( ~x, ~y, "a", 1:3, "b", 4:6 ) } tibble/man/formatting.Rd0000644000176200001440000000354713204634213014736 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tbl-df.r, R/utils-format.r \name{format.tbl} \alias{format.tbl} \alias{format.tbl_df} \alias{print.tbl} \alias{print.tbl_df} \alias{formatting} \alias{trunc_mat} \title{Tools for describing matrices} \usage{ \method{format}{tbl}(x, ..., n = NULL, width = NULL, n_extra = NULL) \method{format}{tbl_df}(x, ..., n = NULL, width = NULL, n_extra = NULL) \method{print}{tbl}(x, ..., n = NULL, width = NULL, n_extra = NULL) \method{print}{tbl_df}(x, ..., n = NULL, width = NULL, n_extra = NULL) trunc_mat(x, n = NULL, width = NULL, n_extra = NULL) } \arguments{ \item{x}{Object to show.} \item{n}{Number of rows to show. If \code{NULL}, the default, will print all rows if less than option \code{tibble.print_max}. Otherwise, will print \code{tibble.print_min} rows.} \item{width}{Width of text output to generate. This defaults to NULL, which means use \code{getOption("tibble.width")} or (if also NULL) \code{getOption("width")}; the latter displays only the columns that fit on one screen. You can also set \code{options(tibble.width = Inf)} to override this default and always print all columns.} \item{n_extra}{Number of extra columns to print abbreviated information for, if the width is too small for the entire tibble. If \code{NULL}, the default, will print information about at most \code{tibble.max_extra_cols} extra columns.} } \description{ Tools for describing matrices } \examples{ trunc_mat(mtcars) print(as_tibble(mtcars)) print(as_tibble(mtcars), n = 1) print(as_tibble(mtcars), n = 3) print(as_tibble(mtcars), n = 100) if (!requireNamespace("nycflights13", quietly = TRUE)) stop("Please install the nycflights13 package to run the rest of this example") print(nycflights13::flights, n_extra = 2) print(nycflights13::flights, width = Inf) } \seealso{ \link{tibble-package} } \keyword{internal} tibble/man/glimpse.Rd0000644000176200001440000000242713204634213014220 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/glimpse.R \name{glimpse} \alias{glimpse} \title{Get a glimpse of your data.} \usage{ glimpse(x, width = NULL, ...) } \arguments{ \item{x}{An object to glimpse at.} \item{width}{Width of output: defaults to the setting of the option \code{tibble.width} (if finite) or the width of the console.} \item{...}{Other arguments passed on to individual methods.} } \value{ x original x is (invisibly) returned, allowing \code{glimpse()} to be used within a data pipe line. } \description{ This is like a transposed version of print: columns run down the page, and data runs across. This makes it possible to see every column in a data frame. It's a little like \code{\link[=str]{str()}} applied to a data frame but it tries to show you as much data as possible. (And it always shows the underlying data, even when applied to a remote data source.) } \section{S3 methods}{ \code{glimpse} is an S3 generic with a customised method for \code{tbl}s and \code{data.frames}, and a default method that calls \code{\link[=str]{str()}}. } \examples{ glimpse(mtcars) if (!requireNamespace("nycflights13", quietly = TRUE)) stop("Please install the nycflights13 package to run the rest of this example") glimpse(nycflights13::flights) } tibble/man/is.tibble.Rd0000644000176200001440000000056613204634213014435 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tibble.R \name{is.tibble} \alias{is.tibble} \alias{is_tibble} \title{Test if the object is a tibble.} \usage{ is.tibble(x) is_tibble(x) } \arguments{ \item{x}{An object} } \value{ \code{TRUE} if the object inherits from the \code{tbl_df} class. } \description{ Test if the object is a tibble. } tibble/man/frame_matrix.Rd0000644000176200001440000000133313204634213015231 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tribble.R \name{frame_matrix} \alias{frame_matrix} \title{Row-wise matrix creation} \usage{ frame_matrix(...) } \arguments{ \item{...}{Arguments specifying the structure of a \code{frame_matrix}. Column names should be formulas, and may only appear before the data.} } \value{ A \link{matrix}. } \description{ Create matrices laying out the data in rows, similar to \code{matrix(..., byrow = TRUE)}, with a nicer-to-read syntax. This is useful for small matrices, e.g. covariance matrices, where readability is important. The syntax is inspired by \code{\link[=tribble]{tribble()}}. } \examples{ frame_matrix( ~col1, ~col2, 1, 3, 5, 2 ) } tibble/LICENSE0000644000176200001440000000005213204634213012513 0ustar liggesusersYEAR: 2013-2017 COPYRIGHT HOLDER: RStudio