tibble/0000755000176200001440000000000013476213663011526 5ustar liggesuserstibble/inst/0000755000176200001440000000000013476204717012503 5ustar liggesuserstibble/inst/doc/0000755000176200001440000000000013476204717013250 5ustar liggesuserstibble/inst/doc/extending.R0000644000176200001440000001677513476204716015377 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 ## ------------------------------------------------------------------------ time <- as.POSIXlt("2018-12-20 23:29:51", tz = "CET") x <- as.POSIXlt(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.Rmd0000644000176200001440000001225213464363736015163 0ustar liggesusers--- title: "Tibbles" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Tibbles} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r, echo = FALSE, message = FALSE, error = TRUE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(tibble) set.seed(1014) options(crayon.enabled = TRUE) options(pillar.bold = TRUE) knitr::opts_chunk$set(collapse = TRUE, comment = pillar::style_subtle("#>")) colourise_chunk <- function(type) { function(x, options) { # lines <- strsplit(x, "\\n")[[1]] lines <- x if (type != "output") { lines <- crayon::red(lines) } paste0( '
',
      paste0(
        sgr_to_html(htmltools::htmlEscape(lines)),
        collapse = "\n"
      ),
      "
" ) } } knitr::knit_hooks$set( output = colourise_chunk("output"), message = colourise_chunk("message"), warning = colourise_chunk("warning"), error = colourise_chunk("error") ) # Fallback if fansi is missing sgr_to_html <- identity sgr_to_html <- fansi::sgr_to_html ``` 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 error = TRUE, eval = FALSE} l <- replicate(26, sample(100), simplify = FALSE) names(l) <- letters timing <- bench::mark( as_tibble(l), as.data.frame(l), check = FALSE ) timing ``` ```{r echo = FALSE} readRDS("timing.rds") ``` 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, and uses font styles and color for highlighting: ```{r} tibble(x = -5: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 ``` As of version 1.4.1, tibbles no longer ignore the `drop` argument: ```{r} data.frame(a = 1:3)[, "a", drop = TRUE] 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.R0000644000176200001440000000525113476204717014637 0ustar liggesusers## ---- echo = FALSE, message = FALSE, error = TRUE------------------------ knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(tibble) set.seed(1014) options(crayon.enabled = TRUE) options(pillar.bold = TRUE) knitr::opts_chunk$set(collapse = TRUE, comment = pillar::style_subtle("#>")) colourise_chunk <- function(type) { function(x, options) { # lines <- strsplit(x, "\\n")[[1]] lines <- x if (type != "output") { lines <- crayon::red(lines) } paste0( '
',
      paste0(
        sgr_to_html(htmltools::htmlEscape(lines)),
        collapse = "\n"
      ),
      "
" ) } } knitr::knit_hooks$set( output = colourise_chunk("output"), message = colourise_chunk("message"), warning = colourise_chunk("warning"), error = colourise_chunk("error") ) # Fallback if fansi is missing sgr_to_html <- identity sgr_to_html <- fansi::sgr_to_html ## ------------------------------------------------------------------------ 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) ## ----error = TRUE, eval = FALSE------------------------------------------ # l <- replicate(26, sample(100), simplify = FALSE) # names(l) <- letters # # timing <- bench::mark( # as_tibble(l), # as.data.frame(l), # check = FALSE # ) # # timing ## ----echo = FALSE-------------------------------------------------------- readRDS("timing.rds") ## ------------------------------------------------------------------------ tibble(x = -5: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 ## ------------------------------------------------------------------------ data.frame(a = 1:3)[, "a", drop = TRUE] 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.html0000644000176200001440000015466513476204717016144 0ustar liggesusers Extending tibble

Extending tibble

Kirill Müller, Hadley Wickham

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.

## 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:

## # A tibble: 3 x 4
##   venue          year loc              paths   
##   <chr>         <int> <latlon>         <list>  
## 1 rstudio::conf  2017 28°20'N  81°33'W <latlon>
## 2 rstudio::conf  2018 32°43'N 117°10'W <latlon>
## 3 rstudio::conf  2019             <NA> <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.

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.)

## # 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>

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.)

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.

## # 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:

## # 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:

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

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

## # A tibble: 3 x 4
##   venue     year          loc paths
##   <chr>    <int>        <geo> <lis>
## 1 rstudio…  2017 28°20'N  81… <geo>
## 2 rstudio…  2018 32°43'N 117… <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:

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:

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:

## Warning: The `subclass` argument to `new_pillar_shaft()` is deprecated, please use the `class` argument.
## This warning is displayed once per session.
## # 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>
## # 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.

## # 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:

## # 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.

## List of 11
##  $ sec   : num [1:3] 51 51 51
##  $ min   : int [1:3] 29 30 29
##  $ hour  : int [1:3] 23 23 0
##  $ mday  : int [1:3] 20 20 21
##  $ mon   : int [1:3] 11 11 11
##  $ year  : int [1:3] 118 118 118
##  $ wday  : int [1:3] 4 4 5
##  $ yday  : int [1:3] 353 353 354
##  $ 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" "CET" "CEST"

But it pretends to be a vector with 3 elements:

## [1] "2018-12-20 23:29:51 CET" "2018-12-20 23:30:51 CET"
## [3] "2018-12-21 00:29:51 CET"
## [1] 3
##  POSIXlt[1:3], format: "2018-12-20 23:29:51" "2018-12-20 23:30:51" ...

So we need to define a method that returns a character vector the same length as 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:

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.

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

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

## [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[31mNA\033[39m         "

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

## 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[31mNA\033[39m         "
## [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:

## 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[31mNA\033[39m         "
## y[3]: "     NA         "
## [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[31mNA\033[39m         "
## [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.Rmd0000644000176200001440000003266213464363736015716 0ustar liggesusers--- title: "Extending tibble" author: "Kirill Müller, Hadley Wickham" 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} time <- as.POSIXlt("2018-12-20 23:29:51", tz = "CET") x <- as.POSIXlt(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.html0000644000176200001440000010027613476204717015405 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!).

    #> # A tibble: 26 x 1
    #>    x    
    #>    <chr>
    #>  1 a    
    #>  2 b    
    #>  3 c    
    #>  4 d    
    #>  5 e    
    #>  6 f    
    #>  7 g    
    #>  8 h    
    #>  9 i    
    #> 10 j    
    #> # … with 16 more rows
    

    This makes it easier to use with list-columns:

    #> # 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:

    #> [1] "crazy.name"
    
    #> [1] "crazy name"
    
  • It evaluates its arguments lazily and sequentially:

    #> # A tibble: 5 x 2
    #>       x     y
    #>   <int> <dbl>
    #> 1     1     1
    #> 2     2     4
    #> 3     3     9
    #> 4     4    16
    #> 5     5    25
    
  • 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:

#> # A tibble: 2 x 14
#>   expression     min    mean  median     max `itr/sec` mem_alloc  n_gc
#>   <chr>        <dbl>   <dbl>   <dbl>   <dbl>     <dbl>     <dbl> <dbl>
#> 1 as_tibble… 2.88e-4 6.25e-4 3.27e-4 0.00451     1600.      1840     5
#> 2 as.data.f… 7.92e-4 1.66e-3 1.10e-3 0.00765      601.     34584     5
#> # … with 6 more variables: n_itr <int>, total_time <dbl>, result <list>,
#> #   memory <list>, time <list>, gc <list>

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, and uses font styles and color for highlighting:

#> # A tibble: 1,006 x 1
#>        x
#>    <int>
#>  1    -5
#>  2    -4
#>  3    -3
#>  4    -2
#>  5    -1
#>  6     0
#>  7     1
#>  8     2
#>  9     3
#> 10     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:

#> [1] "data.frame"
#> [1] "integer"
#> [1] "tbl_df"     "tbl"        "data.frame"
#> [1] "tbl_df"     "tbl"        "data.frame"

To extract a single column use [[ or $:

#> [1] "integer"
#> [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:

#> [1] 1
#> Warning: Unknown or uninitialised column: 'a'.
#> NULL

As of version 1.4.1, tibbles no longer ignore the drop argument:

#> [1] 1 2 3
#> [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:

#> # A tibble: 3 x 2
#>       a     b
#>   <dbl> <int>
#> 1     1     1
#> 2     1     2
#> 3     1     3
#> # A tibble: 3 x 2
#>       a     b
#>   <int> <dbl>
#> 1     1     1
#> 2     2     1
#> 3     3     1
#> Tibble columns must have consistent lengths, only values of length one are recycled:
#> * Length 2: Column `c`
#> * Length 3: Column `a`
#> # A tibble: 0 x 2
#> # … with 2 variables: a <dbl>, b <int>
#> # 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/0000755000176200001440000000000013476213663014530 5ustar liggesuserstibble/tests/testthat/test-has-name.R0000644000176200001440000000076113437532500017314 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.R0000644000176200001440000000770413437532500017252 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() tolerates a trailing comma", { result <- tribble( ~colA, ~colB, "a", 1, "b", 2, ) compared <- tibble(colA = c("a", "b"), colB = c(1, 2)) expect_equal(result, compared) }) 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", { # no colname expect_error( tribble(1, 2, 3), error_tribble_needs_columns(), fixed = TRUE ) # invalid colname syntax expect_error( tribble(a ~ b), error_tribble_lhs_column_syntax(quote(a)), fixed = TRUE ) # invalid colname syntax expect_error( tribble(~a + b), error_tribble_rhs_column_syntax(quote(a + b)), 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 ), error_tribble_non_rectangular(3, 5), fixed = TRUE ) expect_error( tribble( ~a, ~b, ~c, ~d, 1, 2, 3, 4, 5, 6, 7, 8, 9, ), error_tribble_non_rectangular(4, 9), 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 ), error_frame_matrix_list(c(2, 4)), fixed = TRUE ) }) tibble/tests/testthat/test-tidy_names.R0000644000176200001440000000364613437532500017764 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/test-syntactic-names.R0000644000176200001440000001673413464363736020751 0ustar liggesuserscontext("universal_names") # make_syntactic ------------------------------------------------------------- expect_syntactic <- function(name, exp_syn_name) { expect_identical( syn_name <- make_syntactic(name), exp_syn_name ) expect_identical(syn_name, make.names(syn_name)) } test_that("make_syntactic(): empty or NA", { expect_syntactic( c("", NA_character_), c(".", ".") ) }) test_that("make_syntactic(): reserved words", { expect_syntactic( c("if", "TRUE", "Inf", "NA_real_", "normal"), c(".if", ".TRUE", ".Inf", ".NA_real_", "normal") ) }) test_that("make_syntactic(): underscore", { expect_syntactic( c( "_", "_1", "_a}"), c("._", "._1", "._a.") ) }) test_that("make_syntactic(): dots", { expect_syntactic( c(".", "..", "...", "...."), c(".", "..", "....", "....") ) }) test_that("make_syntactic(): number", { expect_syntactic( c( "0", "1", "22", "333"), c("...0", "...1", "...22", "...333") ) }) test_that("make_syntactic(): number then character", { expect_syntactic( c( "0a", "1b", "22c", "333d"), c("..0a", "..1b", "..22c", "..333d") ) }) test_that("make_syntactic(): number then non-character", { expect_syntactic( c( "0)", "1&", "22*", "333@"), c("..0.", "..1.", "..22.", "..333.") ) }) test_that("make_syntactic(): dot then number", { expect_syntactic( c( ".0", ".1", ".22", ".333"), c("...0", "...1", "...22", "...333") ) }) test_that("make_syntactic(): dot then number then character", { expect_syntactic( c( ".0a", ".1b", ".22c", ".333d"), c("..0a", "..1b", "..22c", "..333d") ) }) test_that("make_syntactic(): dot then number then non-character", { expect_syntactic( c( ".0)", ".1&", ".22*", ".333@"), c("..0.", "..1.", "..22.", "..333.") ) }) test_that("make_syntactic(): dot dot then number", { expect_syntactic( c( "..0", "..1", "..22", "..333"), c("...0", "...1", "...22", "...333") ) }) test_that("make_syntactic(): dot dot dot then number", { expect_syntactic( c("...0", "...1", "...22", "...333"), c("...0", "...1", "...22", "...333") ) }) test_that("make_syntactic(): dot dot dot dot then number", { expect_syntactic( c("....0", "....1", "....22", "....333"), c("....0", "....1", "....22", "....333") ) }) test_that("make_syntactic(): dot dot dot dot dot then number", { expect_syntactic( c(".....0", ".....1", ".....22", ".....333"), c(".....0", ".....1", ".....22", ".....333") ) }) test_that("make_syntactic(): dot dot then number then character", { expect_syntactic( c("..0a", "..1b", "..22c", "..333d"), c("..0a", "..1b", "..22c", "..333d") ) }) test_that("make_syntactic(): dot dot then number then non-character", { expect_syntactic( c("..0)", "..1&", "..22*", "..333@"), c("..0.", "..1.", "..22.", "..333.") ) }) # universal_names() ----------------------------------------------------------- test_that("zero-length input", { expect_equal(universal_names(character()), character()) }) test_that("universal names are not changed", { expect_equal(universal_names(letters), letters) }) test_that("universal_names() pass checks for minimal, unique, and universal", { x <- c(NA, "", "x", "x", "a1:", "_x_y}") x_syn <- universal_names(x) expect_error(check_minimal(x_syn), NA) expect_error(check_unique(x_syn), NA) expect_true(all(is_syntactic(x_syn))) expect_identical(x_syn, c("...1", "...2", "x...3", "x...4", "a1.", "._x_y.")) }) test_that("universal_names() is idempotent", { x <- c(NA, "", "x", "x", "a1:", "_x_y}") expect_identical(universal_names(x), universal_names(universal_names(x))) }) test_that("dupes get a suffix", { expect_equal( universal_names(c("a", "b", "a", "c", "b")), c("a...1", "b...2", "a...3", "c", "b...5") ) }) test_that("solo empty or NA gets suffix", { expect_identical(universal_names(""), "...1") expect_identical(universal_names(NA_character_), "...1") }) test_that("ellipsis treated like empty string", { expect_identical(universal_names("..."), universal_names("")) }) test_that("solo dot is unchanged", { expect_equal(universal_names("."), ".") }) test_that("dot, dot gets suffix", { expect_equal(universal_names(c(".", ".")), c("....1", "....2")) }) test_that("dot-dot, dot-dot gets suffix", { expect_equal(universal_names(c("..", "..")), c(".....1", ".....2")) }) test_that("empty, dot becomes suffix, dot", { expect_equal(universal_names(c("", ".")), c("...1", ".")) }) test_that("empty, empty, dot becomes suffix, suffix, dot", { expect_equal(universal_names(c("", "", ".")), c("...1", "...2", ".")) }) test_that("dot, dot, empty becomes suffix, suffix, suffix", { expect_equal(universal_names(c(".", ".", "")), c("....1", "....2", "...3")) }) test_that("dot, empty, dot becomes suffix, suffix, suffix", { expect_equal(universal_names(c(".", "", ".")), c("....1", "...2", "....3")) }) test_that("empty, dot, empty becomes suffix, dot, suffix", { expect_equal(universal_names(c("", ".", "")), c("...1", ".", "...3")) }) test_that("'...j' gets stripped then names are modified", { expect_equal(universal_names(c("...6", "...1...2")), c("...1", "...2")) expect_equal(universal_names("if...2"), ".if") }) test_that("complicated inputs", { expect_equal( universal_names(c("", ".", NA, "if...4", "if", "if...8", "for", "if){]1")), c("...1", ".", "...3", ".if...4", ".if...5", ".if...6", ".for", "if...1") ) }) test_that("message", { expect_message( universal_names(c("a b", "b c")), "New names:\n* `a b` -> a.b\n* `b c` -> b.c\n", fixed = TRUE ) }) test_that("quiet", { expect_message( universal_names("", quiet = TRUE), NA ) }) test_that("unique then universal is universal, with shuffling", { x <- c("", ".2", "..3", "...4", "....5", ".....6", "......7", "...") expect_identical(universal_names(unique_names(x)), universal_names(x)) x2 <- x[c(7L, 4L, 3L, 6L, 5L, 1L, 2L, 8L)] expect_identical(universal_names(unique_names(x2)), universal_names(x2)) x3 <- x[c(3L, 2L, 4L, 6L, 8L, 1L, 5L, 7L)] expect_identical(universal_names(unique_names(x3)), universal_names(x3)) }) # set_universal_names --------------------------------------------------------- test_that("zero-length inputs given character names", { out <- set_universal_names(character()) expect_equal(names(out), character()) }) test_that("unnamed input gives uniquely named output", { out <- set_universal_names(1:3) expect_equal(names(out), c("...1", "...2", "...3")) }) test_that("messages by default", { expect_message( set_universal_names(set_names(1, "a:b")), "New names:\n* `a:b` -> a.b\n", fixed = TRUE ) }) test_that("quiet = TRUE", { expect_message(set_universal_names(set_names(1, ""), quiet = TRUE), NA) }) test_that("non-universal names", { out <- set_universal_names(set_names(1, "a b")) expect_equal(names(out), "a.b") expect_equal(universal_names("a b"), "a.b") }) # check syntactic test_that("check_syntactic() imposes check_minimal()", { expect_error( check_syntactic(NULL), error_names_must_be_non_null(repair = FALSE), fixed = TRUE ) }) test_that("check_syntactic() imposes check_unique()", { expect_error( check_syntactic(c("x", "x", "y")), error_column_names_must_be_unique("x"), fixed = TRUE ) }) test_that("check_syntactic() errors for non-syntactic names", { expect_error( check_syntactic(c("x", "a:b", "break")), error_column_names_must_be_syntactic(c("a:b", "break"), repair = FALSE), fixed = TRUE ) }) tibble/tests/testthat/helper-encoding.R0000644000176200001440000000260013464363736017720 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 } skip_on_non_utf8_locale <- function() { if (!l10n_info()$"UTF-8") { skip("Non-UTF-8 locale") } } tibble/tests/testthat/test-type_sum.R0000644000176200001440000000027113437532500017464 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-rownames.R0000644000176200001440000000550013437532500017452 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", { mtcars2 <- as_tibble(mtcars) expect_false(has_rownames(mtcars2)) expect_warning( rownames(mtcars2) <- rownames(mtcars), "deprecated", fixed = TRUE ) }) 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"), error_existing_names("wt"), fixed = TRUE ) mtcars2 <- as_tibble(mtcars, rownames = NA) res1 <- rownames_to_column(mtcars2, "Make&Model") expect_false(has_rownames(res1)) expect_equal(class(res1), class(mtcars2)) expect_equal(res1$`Make&Model`, rownames(mtcars)) expect_error( rownames_to_column(mtcars2, "wt"), error_existing_names("wt"), 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"), error_existing_names("wt"), fixed = TRUE ) mtcars2 <- as_tibble(mtcars, rownames = NA) res1 <- rowid_to_column(mtcars2, "row_id") expect_false(has_rownames(res1)) expect_equal(class(res1), class(mtcars2)) expect_equal(res1$row_id, seq_len(nrow(mtcars))) expect_error( rowid_to_column(mtcars2, "wt"), error_existing_names("wt"), fixed = TRUE ) }) test_that("column_to_rownames returns tbl", { var <- "car" mtcars1 <- as_tibble(mtcars, rownames = NA) expect_true(has_rownames(mtcars1)) res0 <- rownames_to_column(mtcars1, var) expect_warning(res <- column_to_rownames(res0, var), NA) expect_true(has_rownames(res)) expect_equal(class(res), class(mtcars)) expect_equal(rownames(res), rownames(mtcars1)) expect_equal(res, mtcars) 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"), NA) expect_true(has_rownames(res)) expect_equal(rownames(res), as.character(mtcars1$num)) expect_error( column_to_rownames(res), error_already_has_rownames(), fixed = TRUE ) expect_error( column_to_rownames(rownames_to_column(mtcars1, var), "num2"), error_unknown_names("num2"), 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.R0000644000176200001440000000124713437532500016425 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.R0000644000176200001440000002240713464363736016371 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"), error_inconsistent_new_rows("xxyzy"), fixed = TRUE ) expect_error( add_row(tibble(a = 3), b = "err", c = "oops"), error_inconsistent_new_rows(c("b", "c")), fixed = TRUE ) }) test_that("deprecated adding rows to non-data-frames", { scoped_lifecycle_errors() expect_error(add_row(as.matrix(mtcars), mpg = 4)) }) 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), error_both_before_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(tibble(a = as.list(1:3)))$a[[4]]) expect_null(add_row(tibble(a = as.list(1:3)), .before = 1)$a[[1]]) expect_null(add_row(tibble(a = as.list(1:3)), .after = 1)$a[[2]]) expect_null(add_row(tibble(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)", { skip_if_not_installed("dplyr") expect_error( add_row(dplyr::group_by(iris, Species), Petal.Width = 3), error_add_rows_to_grouped_df(), 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("add_column() can add to empty tibble or data frame", { expect_identical(add_column(tibble(.rows = 3), a = 1:3), tibble(a = 1:3)) expect_identical(add_column(as.data.frame(tibble(.rows = 3)), a = 1:3), data.frame(a = 1:3)) }) test_that("error if adding existing columns", { expect_error( add_column(tibble(a = 3), a = 5), error_duplicate_new_cols("a"), fixed = TRUE ) }) test_that("error if adding wrong number of rows with add_column()", { expect_error( add_column(tibble(a = 3), b = 4:5), error_inconsistent_new_cols(1, data.frame(b = 4:5)), 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), error_both_before_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"), error_unknown_names("x"), fixed = TRUE ) expect_error( add_column(df, b = 4:6, .before = "x"), error_unknown_names("x"), fixed = TRUE ) }) test_that("deprecated adding rows to non-data-frames", { scoped_lifecycle_errors() expect_error(add_column(as.matrix(mtcars), x = 1)) }) 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/0000755000176200001440000000000013407176032017520 5ustar liggesuserstibble/tests/testthat/output/glimpse/all-50.txt0000644000176200001440000000044613474034452021262 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:5… $ h [1, 2, NA] $ i [[1, <2, 3>], [<4, 5, 6>], [NA]] tibble/tests/testthat/output/glimpse/mtcars-70.txt0000644000176200001440000000145413474034451022004 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.7… $ hp 110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, 18… $ 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.190… $ qsec 16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20.00… $ 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.txt0000644000176200001440000000060213474034452021454 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, 4… $ Sepal.Width 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3… $ Petal.Length 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1… $ Petal.Width 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0… $ Species setosa, setosa, setosa, setosa, setosa, setosa… tibble/tests/testthat/output/glimpse/iris-nested-df-70.txt0000644000176200001440000000022213474034452023321 0ustar liggesusersObservations: 3 Variables: 2 $ Species setosa, versicolor, virginica $ data [, , 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-1… $ g 2015-12-09 10:51:35, … $ h [1, 2, NA] $ i [[1, <2, 3>], [<4, 5,… tibble/tests/testthat/output/glimpse/all-70.txt0000644000176200001440000000045313474034452021262 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.txt0000644000176200001440000000010513474034452023051 0ustar liggesusersObservations: 1 Variables: 2 $ `mean(x)` 5 $ `var(x)` 3 tibble/tests/testthat/output/glimpse/iris-nested-tbl-70.txt0000644000176200001440000000022213474034452023511 0ustar liggesusersObservations: 3 Variables: 2 $ Species setosa, versicolor, virginica $ data [, , 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4… $ Sepal.Width 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3… $ Petal.Length 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1… $ Petal.Width 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0… $ Species setosa, setosa, setosa, setosa, setosa, setosa… tibble/tests/testthat/output/glimpse/iris-empty-70.txt0000644000176200001440000000003713474034452022612 0ustar liggesusersObservations: 150 Variables: 0 tibble/tests/testthat/output/glimpse/5.txt0000644000176200001440000000000713474034452020425 0ustar liggesusers num 5 tibble/tests/testthat/output/trunc_mat/0000755000176200001440000000000013474030577020063 5ustar liggesuserstibble/tests/testthat/output/trunc_mat/iris-inf-30.txt0000644000176200001440000000021313474034456022560 0ustar liggesusers# A tibble: 150 x 5 # … with 3 more variables: # Petal.Length , # Petal.Width , # Species tibble/tests/testthat/output/trunc_mat/newline.txt0000644000176200001440000000006713301302606022250 0ustar liggesusers# A tibble: 2 x 2 tibble/tests/testthat/output/trunc_mat/all-1-30-2.txt0000644000176200001440000000017013474034457022110 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.txt0000644000176200001440000000024213474034456022152 0ustar liggesusers# A tibble: 150 x 5 # … with 145 more rows, and 3 # more variables: # Petal.Length , # Petal.Width , # Species tibble/tests/testthat/output/trunc_mat/POSIXlt-8-60.txt0000644000176200001440000000071613474034457022463 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.txt0000644000176200001440000000005513474034456023205 0ustar liggesusers# A tibble: 150 x 0 tibble/tests/testthat/output/trunc_mat/iris-3-5.txt0000644000176200001440000000037513474034456022101 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.txt0000644000176200001440000000010613474034456022070 0ustar liggesusers# A tibble: 150 x 5 # … with 140 more rows tibble/tests/testthat/output/trunc_mat/zero-cols_unk-5-30.txt0000644000176200001440000000012113474034456023772 0ustar liggesusers# A tibble: ?? x 0 # … with at least 5 rows # total tibble/tests/testthat/output/trunc_mat/all-1-30-0.txt0000644000176200001440000000013413474034457022106 0ustar liggesusers# A tibble: 3 x 9 # … with 2 more rows, and 5 # more variables tibble/tests/testthat/output/trunc_mat/iris_10_unk-10-70.txt0000644000176200001440000000005413474034456023410 0ustar liggesusers# A tibble: ?? x 5 tibble/tests/testthat/output/trunc_mat/iris-neg-30.txt0000644000176200001440000000024213474034456022557 0ustar liggesusers# A tibble: 150 x 5 # … with 140 more rows, and 3 # more variables: # Petal.Length , # Petal.Width , # Species tibble/tests/testthat/output/trunc_mat/long_unk-5-30.txt0000644000176200001440000000010113474034456023012 0ustar liggesusers# A tibble: ?? x 1 # … with more rows tibble/tests/testthat/output/trunc_mat/zero-rows_unk-5-30.txt0000644000176200001440000000026413474034456024034 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.txt0000644000176200001440000000022413474034457022143 0ustar liggesusers# A tibble: 3 x 2 成交日期 合同录入日期 1 1 4 2 2 5 3 3 6 tibble/tests/testthat/output/trunc_mat/iris_9_unk-10-70.txt0000644000176200001440000000005413474034456023340 0ustar liggesusers# A tibble: ?? x 5 tibble/tests/testthat/output/trunc_mat/non-syntactic.txt0000644000176200001440000000005313474034457023414 0ustar liggesusers# A tibble: 1 x 2 tibble/tests/testthat/output/trunc_mat/mtcars-8-30.txt0000644000176200001440000000027513474034456022506 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.txt0000644000176200001440000000011313474034456022140 0ustar liggesusers# A tibble: 10,000 x 1 # … with 9,995 more rows tibble/tests/testthat/output/trunc_mat/iris_unk-10-70.txt0000644000176200001440000000010113474034456023101 0ustar liggesusers# A tibble: ?? x 5 # … with more rows tibble/tests/testthat/output/trunc_mat/all--300.txt0000644000176200001440000000005313474034456021747 0ustar liggesusers# A tibble: 3 x 9 tibble/tests/testthat/output/trunc_mat/iris_11_unk-10-70.txt0000644000176200001440000000010113474034456023402 0ustar liggesusers# A tibble: ?? x 5 # … with more rows tibble/tests/testthat/output/trunc_mat/zero_rows--30.txt0000644000176200001440000000013013474034456023144 0ustar liggesusers# A tibble: 0 x 2 # … with 2 variables: # a , b tibble/tests/testthat/output/trunc_mat/all--30.txt0000644000176200001440000000020413474034456021665 0ustar liggesusers# A tibble: 3 x 9 # … with 5 more variables: # e , f , # g , h , # i tibble/tests/testthat/test-options.R0000644000176200001440000000463213437532500017317 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-name-repair.R0000644000176200001440000001424413464363736020041 0ustar liggesuserscontext("test-name_repair") # minimal names ------------------------------------------------------------- test_that("minimal names are made from `n` when `name = NULL`", { expect_identical(minimal_names(NULL, 2), c("", "")) expect_error( minimal_names(NULL), error_name_length_required(), fixed = TRUE ) }) test_that("minimal names have '' instead of NAs", { expect_identical(minimal_names(c("", NA, "", NA)), c("", "", "", "")) }) test_that("set_minimal_names() copes with NULL input names", { x <- 1:3 x_named <- set_minimal_names(x) expect_equal(names(x_named), rep("", 3)) }) test_that("check_minimal() errors when names aren't minimal", { expect_error( check_minimal(NULL), error_names_must_be_non_null(repair = FALSE), fixed = TRUE ) expect_error( check_minimal(c("a", NA)), error_column_must_be_named(2, repair = FALSE), fixed = TRUE ) }) test_that("minimal_names() is idempotent", { x <- c("", "", NA) expect_identical(minimal_names(x), minimal_names(minimal_names(x))) }) # unique names ------------------------------------------------------------- test_that("unique_names() eliminates emptiness and duplication", { x <- c("", "x", "y", "x") expect_identical(unique_names(x), c("...1", "x...2", "y", "x...4")) }) test_that("solo empty or NA gets suffix", { expect_identical(unique_names(""), "...1") expect_identical(unique_names(NA_character_), "...1") }) test_that("ellipsis treated like empty string", { expect_identical(unique_names("..."), unique_names("")) }) test_that("two_three_dots() does its job and no more", { x <- c(".", ".1", "...1", "..1a") expect_identical(two_to_three_dots(x), x) expect_identical(two_to_three_dots(c("..1", "..22")), c("...1", "...22")) }) test_that("two dots then number treated like three dots then number", { expect_identical(unique_names("..2"), unique_names("...5")) }) test_that("unique_names() strips positional suffixes, re-applies as needed", { x <- c("...20", "a...1", "b", "", "a...2...34") expect_identical(unique_names(x), c("...1", "a...2", "b", "...4", "a...5")) expect_identical(unique_names("a...1"), "a") expect_identical(unique_names(c("a...2", "a")), c("a...1", "a...2")) expect_identical(unique_names(c("a...3", "a", "a")), c("a...1", "a...2", "a...3")) expect_identical(unique_names(c("a...2", "a", "a")), c("a...1", "a...2", "a...3")) expect_identical(unique_names(c("a...2", "a...2", "a...2")), c("a...1", "a...2", "a...3")) }) test_that("check_unique() imposes check_minimal()", { expect_error( check_unique(NULL), error_names_must_be_non_null(repair = FALSE), fixed = TRUE ) expect_error( check_unique(c("x", NA)), error_column_must_be_named(2, repair = FALSE), fixed = TRUE ) }) test_that("check_unique() errors for empty or duplicated names", { expect_error( check_unique(c("x", "")), error_column_must_be_named(2, repair = FALSE), fixed = TRUE ) expect_error( check_unique(c("", "x", "")), error_column_must_be_named(c(1, 3), repair = FALSE), fixed = TRUE ) expect_error( check_unique(c("x", "x", "y")), error_column_names_must_be_unique("x", repair = FALSE), fixed = TRUE ) expect_error( check_unique(c("x", "y", "x", "y")), error_column_names_must_be_unique(c("x", "y"), repair = FALSE), fixed = TRUE ) }) test_that("unique_names() is idempotent", { x <- c("...20", "a...1", "b", "", "a...2") expect_identical(unique_names(!!x), unique_names(unique_names(!!x))) }) test_that("unique-ification has an 'algebraic'-y property", { ## inspired by, but different from, this guarantee about base::make.unique() ## make.unique(c(A, B)) == make.unique(c(make.unique(A), B)) ## If A is already unique, then make.unique(c(A, B)) preserves A. ## I haven't formulated what we guarantee very well yet, but it's probably ## implicit in this test (?) x <- c("...20", "a...1", "b", "", "a...2", "d") y <- c("", "a...3", "b", "...3", "e") ## fix names on each, catenate, fix the whole z1 <- unique_names( c( unique_names(x), unique_names(y) ) ) ## fix names on x, catenate, fix the whole z2 <- unique_names( c( unique_names(x), y ) ) ## fix names on y, catenate, fix the whole z3 <- unique_names( c( x, unique_names(y) ) ) ## catenate, fix the whole z4 <- unique_names( c( x, y ) ) expect_identical(z1, z2) expect_identical(z1, z3) expect_identical(z1, z4) }) # names<-() ------------------------------------------------------------------- test_that("names<-() and set_names() reject non-minimal names", { df <- tibble(a = 1:3, b = 4:6, c = 7:9) scoped_lifecycle_warnings() # https://github.com/tidyverse/tibble/issues/562 expect_warning( set_names(df, NULL), if (is_rstudio()) NA else error_names_must_be_non_null(), fixed = TRUE ) expect_warning( `names<-`(df, NA), error_names_must_have_length(1, 3), fixed = TRUE ) expect_warning( `names<-`(df, ""), error_names_must_have_length(1, 3), fixed = TRUE ) expect_warning( `names<-`(df, 1), error_names_must_have_length(1, 3), fixed = TRUE ) expect_warning( `names<-`(df, 1:2), error_names_must_have_length(2, 3), fixed = TRUE ) expect_identical( set_names(df, letters[1:3]), tibble(a = 1:3, b = 4:6, c = 7:9) ) }) # repair_names (deprecated) --------------------------------------------------- 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 (deprecated) ---------------------------------------------------- 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-tbl-df.R0000644000176200001440000003061013474034327016774 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)", { foo <- tibble(x = 1:10, y = 1:10) expect_error( foo["z"], error_unknown_names("z"), fixed = TRUE ) expect_error( foo[c("x", "y", "z")], error_unknown_names("z"), fixed = TRUE ) expect_error( foo[, "z"], error_unknown_names("z"), fixed = TRUE ) expect_error( foo[, c("x", "y", "z")], error_unknown_names("z"), fixed = TRUE ) expect_error( foo[as.matrix("x")], error_dim_column_index(as.matrix("x")), fixed = TRUE ) expect_error( foo[array("x", dim = c(1, 1, 1))], error_dim_column_index(array("x", dim = c(1, 1, 1))), 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], error_nonint_column_index(1, 0.5), fixed = TRUE ) expect_error( foo[1:5], error_large_column_index(3, 4:5, 4:5), fixed = TRUE ) # Message from base R expect_error(foo[-1:1]) expect_error(foo[c(-1, 1)]) expect_error( foo[-4], error_small_column_index(3, 1, -4), fixed = TRUE ) expect_error( foo[c(1:3, NA)], error_na_column_index(), fixed = TRUE ) expect_error( foo[as.matrix(1)], error_dim_column_index(as.matrix("x")), fixed = TRUE ) expect_error( foo[array(1, dim = c(1, 1, 1))], error_dim_column_index(array("x", dim = c(1, 1, 1))), 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)], error_mismatch_column_flag(3, 2), fixed = TRUE ) expect_error( foo[c(TRUE, TRUE, FALSE, FALSE)], error_mismatch_column_flag(3, 4), fixed = TRUE ) expect_error( foo[c(TRUE, TRUE, NA)], error_na_column_flag(), fixed = TRUE ) expect_error( foo[as.matrix(TRUE)], error_dim_column_index(as.matrix("x")), fixed = TRUE ) expect_error( foo[array(TRUE, dim = c(1, 1, 1))], error_dim_column_index(array("x", dim = c(1, 1, 1))), 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)], error_unsupported_index(list(1:3)), fixed = TRUE ) expect_error( foo[as.list(1:3)], error_unsupported_index(as.list(1:3)), fixed = TRUE ) expect_error( foo[factor(1:3)], error_unsupported_index(factor(1:3)), fixed = TRUE ) expect_error( foo[Sys.Date()], error_unsupported_index(Sys.Date()), fixed = TRUE ) expect_error( foo[Sys.time()], error_unsupported_index(Sys.time()), 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[rlang::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, rownames = NA) 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[rlang::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]) expect_identical(df_all[1, , drop = TRUE], df_all[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 is careful about attributes (#155)", { df <- tibble(x = 1:2, y = x) attr(df, "along for the ride") <- "still here" expect_identical(attr(df[names(df)], "along for the ride"), "still here") expect_identical(attr(df["x"], "along for the ride"), "still here") expect_identical(attr(df[1:2], "along for the ride"), "still here") expect_identical(attr(df[2], "along for the ride"), "still here") expect_identical(attr(df[c(TRUE, FALSE)], "along for the ride"), "still here") expect_identical(attr(df[, names(df)], "along for the ride"), "still here") expect_identical(attr(df[, "x"], "along for the ride"), "still here") expect_identical(attr(df[, 1:2], "along for the ride"), "still here") expect_identical(attr(df[, 2], "along for the ride"), "still here") expect_identical(attr(df[, c(TRUE, FALSE)], "along for the ride"), "still here") expect_identical(attr(df[1, names(df)], "along for the ride"), "still here") expect_identical(attr(df[1, "x"], "along for the ride"), "still here") expect_identical(attr(df[1, 1:2], "along for the ride"), "still here") expect_identical(attr(df[1, 2], "along for the ride"), "still here") expect_identical(attr(df[1, c(TRUE, FALSE)], "along for the ride"), "still here") expect_identical(attr(df[1:2, ], "along for the ride"), "still here") expect_identical(attr(df[-1, ], "along for the ride"), "still here") expect_identical(attr(df[, ], "along for the ride"), "still here") expect_identical(attr(df[], "along for the ride"), "still here") }) # [[ ---------------------------------------------------------------------- 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", { scoped_lifecycle_silence() expect_identical(is.tibble(iris), is_tibble(iris)) }) # new_tibble -------------------------------------------------------------- test_that("new_tibble() with deprecated subclass argument", { tbl <- new_tibble( data.frame(a = 1:3), names = "b", attr1 = "value1", attr2 = 2, nrow = 3, 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(b = 1:3), attr1 = "value1", attr2 = 2, .Names = "b", row.names = .set_row_names(3L) ) ) }) test_that("new_tibble() with new class argument", { tbl <- new_tibble( data.frame(a = 1:3), names = "b", attr1 = "value1", attr2 = 2, nrow = 3, class = "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(b = 1:3), attr1 = "value1", attr2 = 2, .Names = "b", row.names = .set_row_names(3L) ) ) }) test_that("new_tibble checks", { scoped_lifecycle_errors() expect_identical(new_tibble(list(), nrow = 0), tibble()) expect_identical(new_tibble(list(), nrow = 5), tibble(.rows = 5)) expect_identical(new_tibble(list(a = 1:3, b = 4:6), nrow = 3), tibble(a = 1:3, b = 4:6)) expect_error( new_tibble(1:3, nrow = 1), error_new_tibble_must_be_list(), fixed = TRUE ) expect_error( new_tibble(list(a = 1)), class = get_defunct_error_class(), error_new_tibble_needs_nrow(), fixed = TRUE ) expect_error( new_tibble(list(1), nrow = NULL), error_new_tibble_needs_nrow(), fixed = TRUE ) expect_error( new_tibble(list(1), nrow = 1), error_names_must_be_non_null(repair = FALSE), fixed = TRUE ) expect_error( new_tibble(set_names(list(1), NA_character_), nrow = 1), NA ) expect_error( new_tibble(set_names(list(1), ""), nrow = 1), NA ) expect_error( new_tibble(list(a = 1, b = 2:3), nrow = 1), NA ) expect_error( new_tibble( structure(list(a = 1, b = 2), row.names = .set_row_names(2)), nrow = 1 ), NA ) }) test_that("validate_tibble() checks", { expect_error( validate_tibble(new_tibble(list(a = 1, b = 2:3), nrow = 1)), error_inconsistent_cols(1, c("a", "b"), 1:2, "`nrow` argument"), fixed = TRUE ) expect_error( validate_tibble(new_tibble(list(a = array(1:3)), nrow = 3)), error_1d_array_column(), fixed = TRUE ) }) tibble/tests/testthat/test-glimpse.R0000644000176200001440000000726413464363736017305 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 factor", { expect_equal(format_v(factor(c("1", "a"))), c("1", "a")) expect_equal(format_v(factor(c("foo", '"bar"'))), c("foo", "\"bar\"")) expect_equal(format_v(factor()), character()) # Add quotes around factor levels with comma # so they don't appear as if they were two observations (GH 384) expect_equal( format_v(factor(c("foo, bar", "foo", '"bar"'))), paste0('"', c("foo, bar", "foo", "\\\"bar\\\""), '"') ) }) 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", { skip_on_non_utf8_locale() 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), error_glimpse_infinite_width(), fixed = TRUE ) }) test_that("glimpse works for structures with unknown rows", { skip_on_non_utf8_locale() # capture_output_lines() forces native encoding iris2 <- as_unknown_rows(iris) expect_output_file( glimpse(iris2, width = 70L), output_file("glimpse/iris-70-na-nrow.txt") ) }) test_that("glimpse calls tbl_sum() (#550)", { skip_on_non_utf8_locale() # capture_output_lines() forces native encoding iris2 <- as_override_tbl_sum(iris) expect_output( glimpse(iris2), "Overridden: tbl_sum", fixed = TRUE ) }) test_that("glimpse works on nested data (#486)", { skip_on_non_utf8_locale() nested_iris_df <- tibble( Species = unique(iris$Species), data = unname(split(iris, iris$Species)) ) nested_iris_tbl <- tibble( Species = unique(iris$Species), data = map(unname(split(iris, iris$Species)), as_tibble) ) expect_output_file_rel( glimpse(nested_iris_df, width = 70L), "glimpse/iris-nested-df-70.txt" ) expect_output_file_rel( glimpse(nested_iris_tbl, width = 70L), "glimpse/iris-nested-tbl-70.txt" ) }) tibble/tests/testthat/test-trunc-mat.R0000644000176200001440000001102213464363736017542 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(iris)))) expect_false(ret$visible) expect_identical(ret$value, as_tibble(iris)) }) test_that("trunc_mat output matches known output", { skip_on_non_utf8_locale() skip_if_not_installed("mockr") testthat::skip_if(getRversion() < "3.2") mtcars2 <- as_tibble(mtcars, rownames = NA) expect_output_file_rel( print_without_body(mtcars2, 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 = -1L, width = 30L), "trunc_mat/iris-neg-30.txt" ) expect_output_file_rel( print_without_body(as_tibble(iris), n = Inf, width = 30L), "trunc_mat/iris-inf-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(as_unknown_rows(iris[1:9, ]), n = 10, width = 70L), "trunc_mat/iris_9_unk-10-70.txt" ) expect_output_file_rel( print_without_body(as_unknown_rows(iris[1:10, ]), n = 10, width = 70L), "trunc_mat/iris_10_unk-10-70.txt" ) expect_output_file_rel( print_without_body(as_unknown_rows(iris[1:11, ]), n = 10, width = 70L), "trunc_mat/iris_11_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_non_utf8_locale() 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(df, n = 8L, width = 60L), "trunc_mat/POSIXlt-8-60.txt" ) }) test_that("trunc_mat for wide-character columns (#100)", { skip_on_non_utf8_locale() # 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_non_utf8_locale() # 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/helper-output.R0000644000176200001440000000105513437532500017460 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) } unell <- function(x) { gsub(cli::symbol$ellipsis, "...", x, fixed = TRUE) } unell_bullets <- function(...) { unell(bullets(...)) } unell_commas <- function(...) { unell(commas(...)) } tibble/tests/testthat/test-string-to-indices.R0000644000176200001440000000071413437532500021163 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/helper-error.R0000644000176200001440000000017513474107166017262 0ustar liggesusersget_defunct_error_class <- function() { if (getRversion() < "3.6") { "simpleError" } else { "defunctError" } } tibble/tests/testthat/test-enframe.R0000644000176200001440000000430313437532500017234 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 unnamed list", { expect_identical( enframe(as.list(3:1)), tibble(name = 1:3, value = as.list(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 convert NULL (#352)", { expect_identical( enframe(NULL), 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 ) ) }) test_that("can enframe without names", { expect_identical( enframe(letters, name = NULL, value = "letter"), tibble(letter = letters) ) }) test_that("can't use value = NULL", { expect_error( enframe(letters, value = NULL), error_enframe_value_null(), fixed = TRUE ) }) test_that("can't pass objects with dimensions", { expect_error( enframe(iris), error_enframe_has_dim(iris), fixed = TRUE ) }) # 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) ) }) test_that("can deframe one-column data frame", { expect_identical( deframe(tibble(value = 3:1)), 3:1 ) }) test_that("can deframe tibble with list column", { expect_identical( deframe(tibble(name = letters[1:3], value = as.list(3:1))), setNames(as.list(3:1), nm = letters[1:3]) ) }) test_that("can deframe three-column data frame with warning", { expect_warning( expect_identical( deframe(tibble(name = letters[1:3], value = 3:1, oops = 1:3)), c(a = 3L, b = 2L, c = 1L) ), "one- or two-column", fixed = TRUE ) }) tibble/tests/testthat/test-data-frame.R0000644000176200001440000004402213474034334017625 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("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( tibble(a = NULL), error_column_must_be_vector("a", "NULL"), fixed = TRUE ) expect_error( tibble(a = new.env()), error_column_must_be_vector("a", "environment"), fixed = TRUE ) expect_error( tibble(a = quote(a)), error_column_must_be_vector("a", "name"), 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), error_inconsistent_cols(NULL, c("x", "y"), c(10, 2), NA), fixed = TRUE ) }) test_that("length 1 vectors in hierarchical data frames are recycled (#502)", { expect_identical( tibble(x = 1:10, y = tibble(z = 1)), tibble(x = 1:10, y = tibble(z = rep(1, 10))) ) expect_identical( tibble(y = tibble(z = 1), x = 1:10), tibble(y = tibble(z = rep(1, 10)), x = 1:10) ) expect_identical( tibble(x = 1, y = tibble(z = 1:10)), tibble(x = rep(1, 10), y = tibble(z = 1:10)) ) expect_identical( tibble(y = tibble(z = 1:10), x = 1), tibble(y = tibble(z = 1:10), x = rep(1, 10)) ) }) 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", { scoped_lifecycle_silence() 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", { scoped_lifecycle_silence() expect_identical(data_frame(a = 1), tibble(a = 1)) expect_identical(data_frame_, tibble_) }) # as_tibble ----------------------------------------------------------- test_that("columns are recycled to common length", { expect_identical( as_tibble(list(x = 1, y = 1:3)), tibble(x = rep(1, 3), y = 1:3) ) expect_identical( as_tibble(list(x = 1:3, y = 1)), tibble(x = 1:3, y = rep(1, 3)) ) expect_identical( as_tibble(list(x = character(), y = 1)), tibble(x = character(), y = numeric()) ) }) test_that("columns must be same length", { expect_error( as_tibble(list(x = 1:2, y = 1:3)), error_inconsistent_cols(NULL, c("x", "y"), 2:3, NA), fixed = TRUE ) expect_error( as_tibble(list(x = 1:2, y = 1:3, z = 1:4)), error_inconsistent_cols( NULL, c("x", "y", "z"), 2:4, NA ), fixed = TRUE ) expect_error( as_tibble(list(x = 1:4, y = 1:2, z = 1:2)), error_inconsistent_cols( NULL, c("x", "y", "z"), c(4, 2, 2), NA ), fixed = TRUE ) expect_error( as_tibble(list(x = 1, y = 1:4, z = 1:2)), error_inconsistent_cols( NULL, c("y", "z"), c(4, 2), NA ), fixed = TRUE ) expect_error( as_tibble(list(x = 1:2, y = 1:4, z = 1)), error_inconsistent_cols( NULL, c("x", "y"), c(2, 4), NA ), 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) mtcars2 <- as_tibble(mtcars_table) expect_equal(names(mtcars2), c(names(dimnames(mtcars_table)), "n")) expect_warning( mtcars2 <- as_tibble(mtcars_table, "Freq"), "named argument", fixed = TRUE ) expect_equal(names(mtcars2), c(names(dimnames(mtcars_table)), "Freq")) mtcars2 <- as_tibble(mtcars_table, n = "Freq") expect_equal(names(mtcars2), c(names(dimnames(mtcars_table)), "Freq")) }) test_that("Can convert unnamed atomic vectors to tibble by default", { scoped_lifecycle_warnings() expect_warning( expect_equal(as_tibble(1:3), tibble(value = 1:3)), "discouraged", fixed = TRUE ) expect_warning( expect_equal(as_tibble(c(TRUE, FALSE, NA)), tibble(value = c(TRUE, FALSE, NA))), "discouraged", fixed = TRUE ) expect_warning( expect_equal(as_tibble(1.5:3.5), tibble(value = 1.5:3.5)), "discouraged", fixed = TRUE ) expect_warning( expect_equal(as_tibble(letters), tibble(value = letters)), "discouraged", fixed = TRUE ) }) test_that("Can convert named atomic vectors to data frame", { skip("Do we want an .as_row argument?") expect_equal(as_tibble(setNames(nm = 1:3)), tibble(`1` = 1L, `2` = 2L, `3` = 3L)) expect_equal(as_tibble(setNames(nm = c(TRUE, FALSE))), tibble(`TRUE` = TRUE, `FALSE` = FALSE)) expect_equal(as_tibble(setNames(nm = 1.5:3.5)), tibble(`1.5` = 1.5, `2.5` = 2.5, `3.5` = 3.5)) expect_equal(as_tibble(setNames(nm = letters)), tibble(!!!setNames(nm = letters))) expect_error( as_tibble(setNames(nm = c(TRUE, FALSE, NA))), invalid_df("must be named", 3), fixed = TRUE ) }) test_that("as_tibble() checks for `unique` names by default (#278)", { l1 <- list(1:10) expect_error( as_tibble(l1), error_column_must_be_named(1, repair = TRUE), fixed = TRUE ) l2 <- list(x = 1, 2) expect_error( as_tibble(l2), error_column_must_be_named(2, repair = TRUE), fixed = TRUE ) l3 <- list(x = 1, ... = 2) expect_error( as_tibble(l3), error_column_must_not_be_dot_dot(2, repair = TRUE), fixed = TRUE ) l4 <- list(x = 1, ..1 = 2) expect_error( as_tibble(l4), error_column_must_not_be_dot_dot(2, repair = TRUE), fixed = TRUE ) df <- list(a = 1, b = 2) names(df) <- c("", NA) df <- new_tibble(df, nrow = 1) expect_error( as_tibble(df), error_column_must_be_named(1:2, repair = TRUE), fixed = TRUE ) }) test_that("as_tibble() makes names `minimal`, even if not fixing names", { invalid_df <- as_tibble(list(3, 4, 5), .name_repair = "minimal") expect_equal(length(invalid_df), 3) expect_equal(nrow(invalid_df), 1) expect_equal(names(invalid_df), rep("", 3)) }) test_that("as_tibble() implements unique names", { invalid_df <- as_tibble(list(3, 4, 5), .name_repair = "unique") expect_equal(length(invalid_df), 3) expect_equal(nrow(invalid_df), 1) expect_equal(names(invalid_df), unique_names(rep("", 3))) }) test_that("as_tibble() implements universal names", { invalid_df <- as_tibble(list(3, 4, 5), .name_repair = "universal") expect_equal(length(invalid_df), 3) expect_equal(nrow(invalid_df), 1) expect_equal(names(invalid_df), universal_names(rep("", 3))) }) test_that("as_tibble() implements custom name repair", { invalid_df <- as_tibble( list(3, 4, 5), .name_repair = function(x) make.names(x, unique = TRUE) ) expect_equal(length(invalid_df), 3) expect_equal(nrow(invalid_df), 1) expect_equal(names(invalid_df), make.names(rep("", 3), unique = TRUE)) invalid_df_purrr <- as_tibble( list(3, 4, 5), .name_repair = ~make.names(., unique = TRUE) ) expect_identical(invalid_df_purrr, invalid_df) }) test_that("as_tibble.matrix() supports validate (with warning) (#558)", { scoped_lifecycle_silence() expect_identical( as_tibble(diag(3), validate = TRUE), tibble( V1 = c(1, 0, 0), V2 = c(0, 1, 0), V3 = c(0, 0, 1) ) ) }) test_that("as_tibble.matrix() supports .name_repair", { scoped_lifecycle_errors() # When removing this, double-check error messages below. x <- matrix(1:6, nrow = 3) expect_error( as_tibble(x), class = get_defunct_error_class(), "name", fixed = TRUE ) expect_identical( names(as_tibble(x, .name_repair = "minimal")), rep("", 2) ) expect_identical( names(as_tibble(x, .name_repair = "universal")), paste0("...", 1:2) ) x <- matrix(1:6, nrow = 3, dimnames = list(x = LETTERS[1:3], y = c("if", "when"))) expect_identical( names(as_tibble(x)), c("if", "when") ) expect_identical( names(as_tibble(x, .name_repair = "minimal")), c("if", "when") ) expect_identical( names(as_tibble(x, .name_repair = "universal")), c(".if", "when") ) }) test_that("as_tibble.poly() supports .name_repair", { x <- poly(1:6, 3) expect_identical( names(as_tibble(x)), as.character(1:3) ) expect_identical( names(as_tibble(x, .name_repair = "minimal")), as.character(1:3) ) expect_identical( names(as_tibble(x, .name_repair = "universal")), paste0("...", 1:3) ) }) test_that("as_tibble.table() supports .name_repair", { x <- table(a = c(1, 1, 1, 2, 2, 2), a = c(3, 4, 5, 3, 4, 5)) expect_error( as_tibble(x), error_column_names_must_be_unique("a") ) expect_identical( names(as_tibble(x, .name_repair = "minimal")), c("a", "a", "n") ) expect_identical( names(as_tibble(x, .name_repair = "universal")), c("a...1", "a...2", "n") ) x <- table("if" = c(1, 1, 1, 2, 2, 2), "when" = c(3, 4, 5, 3, 4, 5)) expect_identical( names(as_tibble(x)), c("if", "when", "n") ) expect_identical( names(as_tibble(x, .name_repair = "minimal")), c("if", "when", "n") ) expect_identical( names(as_tibble(x, .name_repair = "universal")), c(".if", "when", "n") ) x <- table("m" = c(1, 1, 1, 2, 2, 2), "n" = c(3, 4, 5, 3, 4, 5)) expect_identical( names(as_tibble(x, .name_repair = "minimal")), c("m", "n", "n") ) expect_identical( names(as_tibble(x, .name_repair = "universal")), c("m", "n...2", "n...3") ) }) test_that("as_tibble.ts() supports .name_repair, minimal by default (#537)", { x <- ts(matrix(rnorm(6), nrow = 3), start = c(1961, 1), frequency = 12, names = NULL) expect_identical( names(as_tibble(x)), rep("", 2) ) expect_identical( names(as_tibble(x, .name_repair = "minimal")), rep("", 2) ) expect_identical( names(as_tibble(x, .name_repair = "universal")), paste0("...", 1:2) ) x <- ts(matrix(rnorm(6), nrow = 3), start = c(1961, 1), frequency = 12, names = c("if", "when")) expect_identical( names(as_tibble(x)), c("if", "when") ) expect_identical( names(as_tibble(x, .name_repair = "minimal")), c("if", "when") ) expect_identical( names(as_tibble(x, .name_repair = "universal")), c(".if", "when") ) }) 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) ) tbl_df <- as_tibble(df, rownames = NA) expect_identical(rownames(tbl_df), rownames(df)) expect_identical(unclass(tbl_df), unclass(df)) }) test_that("as_tibble() can convert row names for zero-row tibbles", { df <- data.frame(a = 1:3, b = 2:4, row.names = letters[5:7])[0, ] expect_identical( as_tibble(df, rownames = NULL), tibble(a = integer(), b = integer()) ) expect_identical( as_tibble(df, rownames = "id"), tibble(id = character(), a = integer(), b = integer()) ) tbl_df <- as_tibble(df, rownames = NA) expect_identical(rownames(tbl_df), rownames(df)) expect_identical(unclass(tbl_df), unclass(df)) }) test_that("as_tibble() throws an error when user turns missing row names into column", { df <- data.frame(a = 1:3, b = 2:4) expect_error( as_tibble(df, rownames = "id"), error_as_tibble_needs_rownames(), fixed = TRUE ) expect_error( as_tibble(df[0, ], rownames = "id"), error_as_tibble_needs_rownames(), fixed = TRUE ) }) test_that("as_data_frame is an alias of as_tibble", { scoped_lifecycle_silence() expect_identical(as_data_frame(NULL), as_tibble(NULL)) }) test_that("as.tibble is an alias of as_tibble", { scoped_lifecycle_silence() expect_identical(as.tibble(NULL), as_tibble(NULL)) }) # Validation -------------------------------------------------------------- test_that("POSIXlt isn't a valid column", { expect_error( check_valid_cols(list(x = as.POSIXlt(Sys.time()))), error_time_column_must_be_posixct("x"), fixed = TRUE ) }) test_that("NULL isn't a valid column", { expect_error( check_valid_cols(list(a = NULL)), error_column_must_be_vector("a", "NULL"), 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) ) }) test_that("`validate` triggers deprecation message, but then works", { scoped_lifecycle_warnings() expect_error( expect_warning( as_tibble(list(a = 1, "hi"), validate = TRUE), "deprecated", fixed = TRUE ), error_column_must_be_named(2, repair = TRUE) ) expect_warning( df <- as_tibble(list(a = 1, "hi", a = 2), validate = FALSE), "deprecated", fixed = TRUE ) expect_identical(names(df), c("a", "", "a")) df <- data.frame(a = 1, "hi", a = 2) names(df) <- c("a", "", "a") expect_warning( df <- as_tibble(df, validate = FALSE), "deprecated", fixed = TRUE ) expect_identical(names(df), c("a", "", "a")) df <- data.frame(a = 1, "hi") names(df) <- c("a", "") expect_error( expect_warning( as_tibble(df, validate = TRUE), "deprecated", fixed = TRUE ), error_column_must_be_named(2, repair = TRUE) ) }) test_that("Consistent `validate` and `.name_repair` used together keep silent.", { scoped_lifecycle_warnings() expect_error( expect_warning( as_tibble(list(a = 1, "hi"), validate = TRUE, .name_repair = "check_unique"), NA ), error_column_must_be_named(2, repair = TRUE) ) expect_warning( df <- as_tibble(list(a = 1, "hi", a = 2), validate = FALSE, .name_repair = "minimal"), NA ) expect_identical(names(df), c("a", "", "a")) df <- data.frame(a = 1, "hi", a = 2) names(df) <- c("a", "", "a") expect_warning( df <- as_tibble(df, validate = FALSE, .name_repair = "minimal"), NA ) expect_identical(names(df), c("a", "", "a")) df <- data.frame(a = 1, "hi") names(df) <- c("a", "") expect_error( expect_warning( as_tibble(df, validate = TRUE, .name_repair = "check_unique"), NA ), error_column_must_be_named(2, repair = TRUE) ) }) test_that("Inconsistent `validate` and `.name_repair` used together raise a warning.", { expect_error( expect_warning( as_tibble(list(a = 1, "hi"), validate = FALSE, .name_repair = "check_unique"), "precedence" ), error_column_must_be_named(2, repair = TRUE) ) expect_warning( df <- as_tibble(list(a = 1, "hi", a = 2), validate = TRUE, .name_repair = "minimal"), "precedence" ) expect_identical(names(df), c("a", "", "a")) df <- data.frame(a = 1, "hi", a = 2) names(df) <- c("a", "", "a") expect_warning( df <- as_tibble(df, validate = TRUE, .name_repair = "minimal"), "precedence" ) expect_identical(names(df), c("a", "", "a")) df <- data.frame(a = 1, "hi") names(df) <- c("a", "") expect_error( expect_warning( as_tibble(df, validate = FALSE, .name_repair = "check_unique"), "precedence" ), error_column_must_be_named(2, repair = TRUE) ) }) # Data frame and matrix columns ------------------------------------------- test_that("can make tibble containing data.frame or array (#416)", { expect_identical( tibble(mtcars), new_tibble(list(mtcars = remove_rownames(mtcars)), nrow = nrow(mtcars)) ) expect_identical( tibble(diag(5)), new_tibble(list(`diag(5)` = diag(5)), nrow = 5) ) }) test_that("can coerce list data.frame or array (#416)", { expect_identical( as_tibble(list(x = mtcars)), new_tibble(list(x = remove_rownames(mtcars)), nrow = nrow(mtcars)) ) expect_identical( as_tibble(list(x = diag(5))), new_tibble(list(x = diag(5)), nrow = 5) ) }) test_that("susbsetting returns the correct number of rows", { expect_identical( tibble(x = mtcars)[1:3, ], tibble(x = mtcars[1:3, ]) ) expect_identical( tibble(y = diag(5))[1:3, ], tibble(y = diag(5)[1:3, ]) ) }) test_that("subsetting one row retains columns", { expect_identical( tibble(y = diag(5))[1, ], tibble(y = diag(5)[1, , drop = FALSE]) ) }) tibble/tests/testthat/test-matrix.R0000644000176200001440000000772413464363736017152 0ustar liggesuserscontext("matrix") test_that("correct rows and cols", { x <- matrix(1:6, nrow = 2) out <- as_tibble(x, .name_repair = "minimal") expect_equal(dim(out), c(2, 3)) }) test_that("correct rows and cols for 0 cols", { x <- matrix(integer(), nrow = 2) out <- as_tibble(x, .name_repair = "minimal") expect_equal(dim(out), c(2, 0)) }) test_that("correct rows and cols for 0 cols and legacy naming", { scoped_lifecycle_silence() x <- matrix(integer(), nrow = 2) out <- as_tibble(x) expect_equal(dim(out), c(2, 0)) }) test_that("correct rows and cols for 0 rows", { x <- matrix(integer(), ncol = 3) out <- as_tibble(x, .name_repair = "minimal") expect_equal(dim(out), c(0, 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("supports compat col names", { scoped_lifecycle_silence() x <- matrix(1:4, nrow = 2) out <- as_tibble(x) expect_equal(names(out), c("V1", "V2")) }) test_that("creates col names with name repair", { x <- matrix(1:4, nrow = 2) out <- as_tibble(x, .name_repair = "unique") expect_equal(names(out), c("...1", "...2")) out <- as_tibble(x, .name_repair = "universal") expect_equal(names(out), c("...1", "...2")) }) 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, .name_repair = "minimal") expect_equal(out[[1]], c(TRUE, TRUE)) x <- matrix(1L, nrow = 2) out <- as_tibble(x, .name_repair = "minimal") expect_equal(out[[1]], c(1L, 1L)) x <- matrix(1.5, nrow = 2) out <- as_tibble(x, .name_repair = "minimal") expect_equal(out[[1]], c(1.5, 1.5)) x <- matrix("a", nrow = 2) out <- as_tibble(x, .name_repair = "minimal") expect_equal(out[[1]], c("a", "a")) x <- matrix(complex(real = 1, imag = 2), nrow = 2) out <- as_tibble(x, .name_repair = "minimal") expect_equal(out[[1]], as.vector(x)) }) 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(remove_rownames(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) }) test_that("converting from matrix throws an error if user turns missing row names into column", { x <- matrix(1:30, 6, 5) expect_error( as_tibble(x, rownames = "id", .name_repair = "minimal"), error_as_tibble_needs_rownames(), fixed = TRUE ) }) tibble/tests/testthat/test-msg.R0000644000176200001440000002675613437532500016425 0ustar liggesuserscontext("msg") test_that("error_enframe_value_null()", { expect_equal( error_enframe_value_null(), "The `value` argument to `enframe()` cannot be NULL." ) }) test_that("error_enframe_has_dim()", { expect_equal( error_enframe_has_dim(Titanic), "`x` must not have more than one dimension. `length(dim(x))` must be zero or one, not 4." ) }) test_that("error_1d_array_column()", { expect_equal( error_1d_array_column(), "1d arrays are not supported in a tibble column." ) }) test_that("error_unsupported_index()", { expect_equal( error_unsupported_index(raw()), "Can't subset with `[` using an object of class raw." ) }) test_that("error_na_column_index()", { expect_equal( error_na_column_index(), "Can't use numeric NA as column index with `[`." ) }) test_that("error_nonint_column_index()", { expect_equal( error_nonint_column_index(2:3, 3:4 + 0.5), bullets( "Must use integers to index columns with `[`:", paste0("Position ", 2:3, " equals ", 3:4 + 0.5) ) ) }) test_that("error_small_column_index()", { expect_equal( error_small_column_index(3, 2, -4), bullets( "Negative column indexes in `[` must match number of columns:", "`.data` has 3 columns", "Position 2 equals -4" ) ) }) test_that("error_large_column_index()", { expect_equal( error_large_column_index(3, 2, 5), bullets( "Positive column indexes in `[` must match number of columns:", "`.data` has 3 columns", "Position 2 equals 5" ) ) }) test_that("error_mismatch_column_flag()", { expect_equal( error_mismatch_column_flag(5, 3), bullets( "Length of logical index vector for `[` must equal number of columns (or 1):", "`.data` has 5 columns", "Index vector has length 3" ) ) }) test_that("error_na_column_flag()", { expect_equal( error_na_column_flag(), "Can't use logical NA when selecting columns with `[`." ) }) test_that("error_unknown_names()", { expect_equal( error_unknown_names("a"), "Can't find column `a` in `.data`." ) expect_equal( error_unknown_names(c("b", "c")), "Can't find columns `b`, `c` in `.data`." ) expect_equal( unell(error_unknown_names(LETTERS)), "Can't find columns `A`, `B`, `C`, `D`, `E`, ... (and 21 more) in `.data`." ) }) test_that("error_existing_names()", { expect_equal( error_existing_names("a"), "Column `a` already exists in `.data`." ) expect_equal( error_existing_names(c("b", "c")), "Columns `b`, `c` already exist in `.data`." ) expect_equal( unell(error_existing_names(LETTERS)), "Columns `A`, `B`, `C`, `D`, `E`, ... (and 21 more) already exist in `.data`." ) }) test_that("error_add_rows_to_grouped_df()", { expect_equal( error_add_rows_to_grouped_df(), "Can't add rows to grouped data frames" ) }) test_that("error_inconsistent_new_rows()", { expect_equal( error_inconsistent_new_rows("a"), bullets( "New rows in `add_row()` must use columns that already exist:", "Can't find column `a` in `.data`." ) ) expect_equal( error_inconsistent_new_rows(letters[2:3]), bullets( "New rows in `add_row()` must use columns that already exist:", "Can't find columns `b`, `c` in `.data`." ) ) expect_equal( unell(error_inconsistent_new_rows(LETTERS)), bullets( "New rows in `add_row()` must use columns that already exist:", "Can't find columns `A`, `B`, `C`, `D`, `E`, ... (and 21 more) in `.data`." ) ) }) test_that("error_names_must_not_be_null()", { expect_equal( error_names_must_be_non_null(repair = TRUE), "The `names` must not be `NULL`.\nUse .name_repair to specify repair." ) expect_equal( error_names_must_be_non_null(repair = FALSE), "The `names` must not be `NULL`." ) }) test_that("error_names_must_have_length()", { expect_equal( error_names_must_have_length(length = 5, n = 3), "The `names` must have length 3, not 5." ) }) test_that("error_column_must_be_named()", { expect_equal( error_column_must_be_named(1, repair = TRUE), "Column 1 must be named.\nUse .name_repair to specify repair." ) expect_equal( error_column_must_be_named(2:3, repair = TRUE), "Columns 2, 3 must be named.\nUse .name_repair to specify repair." ) expect_equal( unell(error_column_must_be_named(seq_along(letters), repair = TRUE)), "Columns 1, 2, 3, 4, 5, ... (and 21 more) must be named.\nUse .name_repair to specify repair." ) expect_equal( error_column_must_be_named(4:6, repair = FALSE), "Columns 4, 5, 6 must be named." ) }) test_that("error_column_names_must_be_unique()", { expect_equal( error_column_names_must_be_unique("a", repair = FALSE), "Column name `a` must not be duplicated." ) expect_equal( error_column_names_must_be_unique(letters[2:3], repair = TRUE), "Column names `b`, `c` must not be duplicated.\nUse .name_repair to specify repair." ) expect_equal( unell(error_column_names_must_be_unique(LETTERS, repair = TRUE)), "Column names `A`, `B`, `C`, `D`, `E`, ... (and 21 more) must not be duplicated.\nUse .name_repair to specify repair." ) }) test_that("error_column_names_must_be_syntactic()", { expect_equal( error_column_names_must_be_syntactic("a", repair = FALSE), "Column name `a` must be syntactic." ) expect_equal( error_column_names_must_be_syntactic(letters[2:3], repair = TRUE), "Column names `b`, `c` must be syntactic.\nUse .name_repair to specify repair." ) expect_equal( unell(error_column_names_must_be_syntactic(LETTERS, repair = TRUE)), "Column names `A`, `B`, `C`, `D`, `E`, ... (and 21 more) must be syntactic.\nUse .name_repair to specify repair." ) }) test_that("error_column_must_be_vector()", { expect_equal( error_column_must_be_vector("a", "environment"), bullets( "All columns in a tibble must be 1d or 2d objects:", "Column `a` is environment" ) ) expect_equal( error_column_must_be_vector(letters[2:3], c("name", "NULL")), bullets( "All columns in a tibble must be 1d or 2d objects:", "Column `b` is name", "Column `c` is NULL" ) ) expect_equal( error_column_must_be_vector(LETTERS, letters), bullets( "All columns in a tibble must be 1d or 2d objects:", paste0("Column `", LETTERS, "` is ", letters) ) ) }) test_that("error_time_column_must_be_posixct()", { expect_equal( error_time_column_must_be_posixct("a"), "Column `a` is a date/time and must be stored as POSIXct, not POSIXlt." ) expect_equal( error_time_column_must_be_posixct(letters[2:3]), "Columns `b`, `c` are dates/times and must be stored as POSIXct, not POSIXlt." ) expect_equal( unell(error_time_column_must_be_posixct(LETTERS)), "Columns `A`, `B`, `C`, `D`, `E`, ... (and 21 more) are dates/times and must be stored as POSIXct, not POSIXlt." ) }) test_that("error_inconsistent_cols()", { expect_equal( error_inconsistent_cols( 10, letters[1:3], c(4, 4, 3), "`uvw` argument" ), bullets( "Tibble columns must have consistent lengths, only values of length one are recycled:", "Length 10: Requested with `uvw` argument", "Length 3: Column `c`", "Length 4: Columns `a`, `b`" ) ) expect_equal( error_inconsistent_cols( 10, letters[1:3], c(2, 2, 3), "`xyz` argument" ), bullets( "Tibble columns must have consistent lengths, only values of length one are recycled:", "Length 10: Requested with `xyz` argument", "Length 2: Columns `a`, `b`", "Length 3: Column `c`" ) ) expect_equal( error_inconsistent_cols( NULL, letters[1:3], c(2, 2, 3), "`xyz` argument" ), bullets( "Tibble columns must have consistent lengths, only values of length one are recycled:", "Length 2: Columns `a`, `b`", "Length 3: Column `c`" ) ) }) test_that("error_inconsistent_new_cols()", { expect_equal( error_inconsistent_new_cols(10, data.frame(a = 1:2)), bullets( "New columns in `add_column()` must be consistent with `.data`:", "`.data` has 10 rows", "New column contributes 2 rows" ) ) expect_equal( error_inconsistent_new_cols(1, data.frame(a = 1:3, b = 2:4)), bullets( "New columns in `add_column()` must be consistent with `.data`:", "`.data` has 1 row", "New columns contribute 3 rows" ) ) }) test_that("error_duplicate_new_cols()", { expect_equal( error_duplicate_new_cols("a"), bullets( "Can't add duplicate columns with `add_column()`:", "Column `a` already exists in `.data`." ) ) expect_equal( error_duplicate_new_cols(letters[2:3]), bullets( "Can't add duplicate columns with `add_column()`:", "Columns `b`, `c` already exist in `.data`." ) ) expect_equal( unell(error_duplicate_new_cols(LETTERS)), bullets( "Can't add duplicate columns with `add_column()`:", "Columns `A`, `B`, `C`, `D`, `E`, ... (and 21 more) already exist in `.data`." ) ) }) test_that("error_both_before_after()", { expect_equal( error_both_before_after(), "Can't specify both `.before` and `.after`." ) }) test_that("error_already_has_rownames()", { expect_equal( error_already_has_rownames(), "`df` must be a data frame without row names in `column_to_rownames()`." ) }) test_that("error_already_has_rownames()", { expect_equal( error_as_tibble_needs_rownames(), "Object passed to `as_tibble()` must have row names if the `rownames` argument is set." ) }) test_that("error_glimpse_infinite_width()", { expect_equal( error_glimpse_infinite_width(), "`glimpse()` requires a finite value for the `width` argument." ) }) test_that("error_tribble_needs_columns()", { expect_equal( error_tribble_needs_columns(), "`tribble()` needs to specify at least one column using the `~name` syntax." ) }) test_that("error_tribble_lhs_column_syntax()", { expect_equal( error_tribble_lhs_column_syntax(quote(lhs)), bullets( "All column specifications in `tribble()` must use the `~name` syntax.", "Found `lhs` on the left-hand side of `~`." ) ) }) test_that("error_tribble_rhs_column_syntax()", { expect_equal( error_tribble_rhs_column_syntax(quote(a + b)), bullets( 'All column specifications in `tribble()` must use the `~name` or `~"name"` syntax.', "Found `a + b` on the right-hand side of `~`." ) ) }) test_that("error_tribble_non_rectangular()", { expect_equal( error_tribble_non_rectangular(5, 17), bullets( "`tribble()` must be used with rectangular data:", "Found 5 columns.", "Found 17 cells.", "17 is not an integer multiple of 5." ) ) }) test_that("error_frame_matrix_list()", { expect_equal( error_frame_matrix_list(2:4), bullets( "All values in `frame_matrix()` must be atomic:", "Found list-valued elements at positions 2, 3, 4." ) ) }) test_that("error_name_repair_arg()", { expect_equal( error_name_repair_arg(), "The `.name_repair` argument must be a string or a function that specifies the name repair strategy." ) }) test_that("error_new_tibble_must_be_list()", { expect_equal( error_new_tibble_must_be_list(), "Must pass a list as `x` argument to `new_tibble()`." ) }) test_that("error_new_tibble_needs_nrow()", { expect_equal( error_new_tibble_needs_nrow(), "Must pass a scalar integer as `nrow` argument to `new_tibble()`." ) }) tibble/tests/testthat/test-msg-format.R0000644000176200001440000000271113437532500017674 0ustar liggesuserscontext("msg-format") test_that("bullets", { expect_equal( unell_bullets("header", c("item 1", "item 2")), "header\n* item 1\n* item 2" ) expect_equal( unell_bullets("header", LETTERS), "header\n* A\n* B\n* C\n* D\n* E\n* ... and 21 more problems" ) expect_equal( unell_bullets("header", 1:6), "header\n* 1\n* 2\n* 3\n* 4\n* 5\n* ... and 1 more problem" ) }) test_that("commas", { expect_equal( commas("1"), "1" ) expect_equal( commas(letters[2:4]), "b, c, d" ) expect_equal( unell_commas(LETTERS), "A, B, C, D, E, ... (and 21 more)" ) }) 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-type-sum.R0000644000176200001440000000133313464363736017717 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")) as_override_tbl_sum <- function(x) { structure(x, class = c("override_tbl_sum", class(x))) } tbl_sum.override_tbl_sum <- function(x, ...) { c(NextMethod(), "Overridden" = "tbl_sum") } registerS3method("tbl_sum", "override_tbl_sum", tbl_sum.override_tbl_sum, envir = asNamespace("tibble")) tibble/tests/testthat/helper-unknown-rows.R0000644000176200001440000000054313437532500020610 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-api.R0000644000176200001440000000123413437532500016670 0ustar liggesusers# I like the API file, but can't use pkgapi::api_roclet reliably: # * pkgapi is not on CRAN, can't add to Suggests # * RStudio default is to ignore the `Roxygen` field in `DESCRIPTION` if (any(c("pkgload", "devtools") %in% loadedNamespaces())) { if (grepl("/tests/testthat$", getwd()) && file.exists("../../API")) { if (max(file.info(dir("../../R", full.names = TRUE))$mtime) > file.info("../../API")$mtime) { if (rlang::is_installed("pkgapi")) { rlang::inform("Updating API file") writeLines(format(pkgapi::extract_api()), "../../API") } else { rlang::warn("Install r-lib/pkgapi to update the API file") } } } } tibble/tests/testthat/helper-data.R0000644000176200001440000000123713437532500017033 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/0000755000176200001440000000000013476204717012315 5ustar liggesuserstibble/src/coerce.c0000644000176200001440000000261213301302606013701 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.c0000644000176200001440000001233113407176023016025 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_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_RowNamesSymbol, get_rownames(x, nrow)); Rf_setAttrib(out, R_ClassSymbol, get_class()); UNPROTECT(nprot); return out; } tibble/src/Makevars.win0000644000176200001440000000003313407176023014571 0ustar liggesusersPKG_CPPFLAGS += -std=gnu99 tibble/src/init.c0000644000176200001440000000100613301302606013400 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.h0000644000176200001440000000027013364701553013722 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/NAMESPACE0000644000176200001440000000362013473044414012737 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("$",tbl_df) S3method("[",tbl_df) S3method("[[",tbl_df) S3method("names<-",tbl_df) S3method("row.names<-",tbl_df) 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,ts) S3method(format,tbl) S3method(format,trunc_mat) S3method(format_v,character) S3method(format_v,default) S3method(format_v,factor) S3method(format_v,list) S3method(glimpse,data.frame) S3method(glimpse,default) S3method(glimpse,tbl) S3method(print,tbl) 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) export(validate_tibble) export(view) exportClasses(tbl_df) import(rlang) importFrom(methods,setOldClass) importFrom(pillar,is_vector_s3) importFrom(pillar,new_pillar_title) importFrom(pillar,new_pillar_type) importFrom(pillar,obj_sum) importFrom(pillar,style_subtle) importFrom(pillar,type_sum) importFrom(pkgconfig,set_config) importFrom(utils,head) importFrom(utils,str) importFrom(utils,tail) useDynLib(tibble, .registration = TRUE) tibble/NEWS.md0000644000176200001440000006543513476204577012645 0ustar liggesusers# tibble 2.1.3 - Fix compatibility with R 3.5 and earlier, regression introduced in tibble 2.1.2. # tibble 2.1.2.9000 - No changes. # tibble 2.1.2 - Relax version requirements. - Fix test failing after pillar upgrade. # tibble 2.1.1 - Three dots are used even for `"unique"` name repair (#566). - `add_row()`, `add_case()` and `add_column()` now signal a warning once per session if the input is not a data frame (#575). - Fix `view()` for the case when an object named `x` exists in the global environment (#579). # tibble 2.0.1 - tibble names can again be set to `NULL` within RStudio, as some R routines within RStudio relied on this behaviour (#563, @kevinushey). - `as_tibble.matrix(validate = TRUE)` works again, with a lifecycle warning (#558). - Replace `new_list_along()` by `rep_along()` to support rlang 0.3.1 (#557, @lionel-). # tibble 2.0.0 ## Breaking changes The `tibble()` and `as_tibble()` functions, and the low-level `new_tibble()` constructor, have undergone a major overhaul to improve consistency. We suspect that package code will be affected more than analysis code. To improve compatibility with existing code, breaking changes were reduced to a minimum and in some cases replaced with a warning that appears once per session. Call `tibble:::scoped_lifecycle_errors()` when updating your packages or scripts to the new semantics API to turn these warnings into errors. The compatibility code will be removed in tibble 3.0.0. - All optional arguments have moved past the ellipsis, and must be specified as named arguments. This affects mostly the `n` argument to `as_tibble.table()`, passing `n` unnamed still works (with a warning). - `new_tibble()` has been optimized for performance, the function no longer strips dimensions from 1d arrays and no longer checks correctness of names or column lengths. (It still checks if the object is named, except for zero-length input.) Use the new `validate_tibble()` if you need these checks (#471). - The `nrow` argument to `new_tibble()` is now mandatory. The `class` argument replaces the now deprecated `subclass` argument, the latter will be supported quietly for some time (#518). - Setting names on a tibble via `names(df) <- ...` now also requires minimal names, otherwise a warning is issued once per session (#466). - In `as_tibble()`, checking names is also enabled by default, even for tibbles, matrices and other matrix-like objects: names must exist, `NA` names are not allowed. Coercing a matrix without column names will trigger a warning once per session. (This corresponds to the `"minimal"` checks described below.). - The `validate` argument to `as_tibble()` has been deprecated, see below for alternatives. (The `as_tibble.tbl_df()` method has been removed, the `as_tibble.data.frame()` method will be used for tibbles.) - `as_tibble()` always checks that all columns are 1D or 2D vectors and not of type `POSIXlt`, even with `validate = FALSE` (which is now deprecated). - Calling `as_tibble()` on a vector now warns once per session. Use `enframe(name = NULL)` for converting a vector to a one-column tibble, or `enframe()` for converting a named vector to a two-column tibble. - `data_frame()` and `frame_data()` are soft-deprecated, please use `tibble()` or `tribble()` (#111). - `tibble_()`, `data_frame_()`, and `lst_()` are soft-deprecated. Please use `tibble()` or `lst()` (#111, #509). - `as.tibble()` and `as_data_frame()` are officially deprecated and not generic anymore, please use/implement `as_tibble()` (#111). - `as_tibble.data.frame()` (and also `as_tibble.matrix()`) strip row names by default. Code that relies on tibbles keeping row names now will see: - a different result when calling `rownames()` or `row.names()`, - rows full of `NA` values when subsetting rows with with a character vector, e.g. `as_tibble(mtcars)["Mazda RX4", ]`. Call `pkgconfig::set_config("tibble::rownames", NA)` to revert to the old behavior of keeping row names. Packages that import _tibble_ can call `set_config()` in their `.onLoad()` function (#114). - `as_tibble()` drops extra classes, in particular `as_tibble.grouped_df()` now removes grouping (#535). - `column_to_rownames()` now always coerces to a data frame, because row names are no longer supported in tibbles (#114). - In all `*_rownames()` functions, the first argument has been renamed to `.data` for consistency (#412). - Subsetting one row with `[..., , drop = TRUE]` returns a tibble (#442). - The `print.tbl_df()` method has been removed, the `print.tbl()` method handles printing (#519). ## New features - `tibble()` supports columns that are matrices or data frames (#416). - The new `.rows` argument to `tibble()` and `as_tibble()` allows specifying the expected number of rows explicitly, even if it's evident from the data. This allows writing more defensive code. - Column name repair has more direct support, via the new `.name_repair` argument to `tibble()` and `as_tibble()`. It takes the following values: - `"minimal"`: No name repair or checks, beyond basic existence. - `"unique"`: Make sure names are unique and not empty. - `"check_unique"`: (default value), no name repair, but check they are `unique`. - `"universal"`: Make the names `unique` and syntactic. - a function: apply custom name repair (e.g., `.name_repair = make.names` or `.name_repair = ~make.names(., unique = TRUE)` for names in the style of base R). The `validate` argument of `as_tibble()` is deprecated but supported (emits a message once per session). Use `.name_repair = "minimal"` instead of `validate = FALSE`, and `.name_repair = "check_unique"` instead of `validate = TRUE`. If you need to support older versions of tibble, pass both `.name_repair` and `validate` arguments in a consistent way, no message will be emitted in this case (#469, @jennybc). - Row name handling is stricter. Row names are never (and never were) supported in `tibble()` and `new_tibble()`, and are now stripped by default in `as_tibble()`. The `rownames` argument to `as_tibble()` supports: - `NULL`: remove row names (default), - `NA`: keep row names, - A string: the name of the new column that will contain the existing row names, which are no longer present in the result. The old default can be restored by calling `pkgconfig::set_config("tibble::rownames", NA)`, this also works for packages that import _tibble_. - `new_tibble()` and `as_tibble()` now also strip the `"dim"` attribute from columns that are one-dimensional arrays. (`tibble()` already did this before.) - Internally, all `as_tibble()` implementation forward all extra arguments and `...` to `as_tibble.list()` where they are handled. This means that the common `.rows` and `.name_repair` can be used for all inputs. We suggest that your implementations of this method do the same. - `enframe()` (with `name = NULL`) and `deframe()` now support one-column tibbles (#449). - Improved S4 support by adding `exportClass(tbl_df)` to `NAMESPACE` (#436, @jeffreyhanson and @javierfajnolla). - New `validate_tibble()` checks a tibble for internal consistency (#471). - Bring error message for invalid column type in line with allowed matrix/df cols (#465, @maxheld83). ## New functions - Added experimental `view()` function that always returns its input invisibly and calls `utils::View()` only in interactive mode (#373). ## Output - The `set_tidy_names()` and `tidy_names()` helpers the list of new names using a bullet list with at most six items (#406). - A one-character ellipse (`cli::symbol$ellipsis`) is printed instead of `"..."` where available, this affects `glimpse()` output and truncated lists (#403). - Column names and types are now formatted identically with `glimpse()` and `print.tbl_df()`. - `tidy_names()` quotes variable names when reporting on repair (#407). - All error messages now follow the tidyverse style guide (#223). - `as_tibble()` prints an informative error message when using the `rownames` argument and the input data frame or matrix does not have row names (#388, @anhqle). - `column_to_rownames()` uses the real variable name in its error message (#399, @alexwhan). - Lazy tibbles with exactly 10 rows no longer show "...with more rows" (#371). - `glimpse()` shows information obtained from `tbl_sum()`, e.g. grouping information for `grouped_df` from dplyr (#550). ## Bug fixes - `glimpse()` takes coloring into account when computing column width, the output is no longer truncated prematurely when coloring is enabled. - `glimpse()` disambiguates outputs for factors if the levels contain commas (#384, @anhqle). - `print.tbl_df()` with a negative value for `n` behaves as if `n` was omitted (#371). ## Internal - Skip dplyr in tests if unavailable (#420, @QuLogic). - Skip mockr in tests if unavailable (#454, @Enchufa2). - Use `fansi::strwrap_ctl()` instead of own string wrapping routine. - `tibble()` uses recycled values during construction but unrecycled values for validation. - `tibble()` is now faster for very wide tibbles. - Subsetting with the `[` operator is faster (#544). - Avoid use of `stop()` in examples if packages are not installed (#453, @Enchufa2). - Fix `as_tibble()` examples by using correct argument names in `requireNamespace()` call (#424, @michaelweylandt). - `as_tibble()` checks column length only once (#365, @anhqle). - Using `rlang::list2()` (#391, @lionel-). # tibble 1.4.2 Bug fixes --------- - Fix OS X builds. - The `tibble.width` option is honored again (#369). - `tbl[1, , drop = TRUE]` now behaves identically to data frames (#367). - Fix error message when accessing columns using a logical index vector (#337, @mundl). - `glimpse()` returns its input for zero-column data frames. Features -------- - `enframe(NULL)` now returns the same as `enframe(logical())` (#352). - `tribble()` now ignores trailing commas (#342, @anhqle). - Updated vignettes and website documentation. Performance ----------- - Faster printing of very wide tibbles (#360). - Faster construction and subsetting for tibbles (#353). - Only call `nrow()` and `head()` in `glimpse()`, not `ncol()`. # tibble 1.4.1 ## 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[j, 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 ## 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 ## 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 ## 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 ## 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 ## 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 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 - 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/0000755000176200001440000000000013476204717011727 5ustar liggesuserstibble/R/compat-name-repair.R0000644000176200001440000001234013464363736015537 0ustar liggesusers# compat-name-repair (last updated: tibble 2.0.1.9000) # This file serves as a reference for compatibility functions for # name repair in tibble, until name repair is available in rlang. error_name_length_required <- function() { "`n` must be specified, when the `names` attribute is `NULL`." } minimal_names <- function(name, n) { if (is.null(name) && missing(n)) { abort(error_name_length_required()) } ## TODO: address scenarios where name is not NULL and n != length(name)? if (is.null(name)) { rep_len("", n) } else { name %|% "" } } set_minimal_names <- function(x) { new_names <- minimal_names(names(x), n = length(x)) set_names(x, new_names) } unique_names <- function(name, quiet = FALSE, transform = identity) { min_name <- minimal_names(name) naked_name <- two_to_three_dots(min_name) naked_name <- strip_pos(naked_name) naked_needs_suffix <- (naked_name %in% c("", "...")) new_name <- rep_along(naked_name, "") new_name[!naked_needs_suffix] <- transform(naked_name[!naked_needs_suffix]) duped_after <- duplicated(new_name) | duplicated(new_name, fromLast = TRUE) new_name <- append_pos(new_name, needs_suffix = naked_needs_suffix | duped_after) if (!quiet) { describe_repair(name, new_name) } new_name } set_unique_names <- function(x, quiet = FALSE) { x <- set_minimal_names(x) new_names <- unique_names(names(x), quiet = quiet) set_names(x, new_names) } universal_names <- function(name, quiet = FALSE) { unique_names(name, quiet = quiet, transform = make_syntactic) } set_universal_names <- function(x, quiet = FALSE) { x <- set_minimal_names(x) new_names <- universal_names(names(x), quiet = quiet) set_names(x, new_names) } ## makes each individual name syntactic ## does not enforce unique-ness make_syntactic <- function(name) { name[is.na(name)] <- "" name[name == ""] <- "." name[name == "..."] <- "...." name <- sub("^_", "._", name) new_name <- make.names(name) X_prefix <- grepl("^X", new_name) & !grepl("^X", name) new_name[X_prefix] <- sub("^X", "", new_name[X_prefix]) dot_suffix <- which(new_name == paste0(name, ".")) new_name[dot_suffix] <- sub("^(.*)[.]$", ".\\1", new_name[dot_suffix]) ## illegal characters have been replaced with '.' via make.names() ## however, we have: ## * declined its addition of 'X' prefixes ## * turned its '.' suffixes to '.' prefixes regex <- paste0( "^(?[.]{0,2})", "(?[0-9]*)", "(?[^0-9]?.*$)" ) re <- re_match(new_name, pattern = regex) needs_dots <- which(re$numbers != "") needs_third_dot <- (re$leftovers[needs_dots] == "") re$leading_dots[needs_dots] <- ifelse(needs_third_dot, "...", "..") new_name <- paste0(re$leading_dots, re$numbers, re$leftovers) new_name } two_to_three_dots <- function(name) { sub("(^[.][.][1-9][0-9]*$)", ".\\1", name) } append_pos <- function(name, needs_suffix) { need_append_pos <- which(needs_suffix) name[need_append_pos] <- paste0(name[need_append_pos], "...", need_append_pos) name } strip_pos <- function(name) { rx <- "([.][.][.][1-9][0-9]*)+$" gsub(rx, "", name) %|% "" } describe_repair <- function(orig_name, name) { stopifnot(length(orig_name) == length(name)) new_names <- name != minimal_names(orig_name) if (any(new_names)) { msg <- bullets( "New names:", paste0( tick_if_needed(orig_name[new_names]), " -> ", tick_if_needed(name[new_names]), .problem = "" ) ) message(msg) } } ## from rematch2, except we don't add tbl_df or tbl classes to the return value re_match <- function(text, pattern, perl = TRUE, ...) { stopifnot(is.character(pattern), length(pattern) == 1, !is.na(pattern)) text <- as.character(text) match <- regexpr(pattern, text, perl = perl, ...) start <- as.vector(match) length <- attr(match, "match.length") end <- start + length - 1L matchstr <- substring(text, start, end) matchstr[ start == -1 ] <- NA_character_ res <- data.frame( stringsAsFactors = FALSE, .text = text, .match = matchstr ) if (!is.null(attr(match, "capture.start"))) { gstart <- attr(match, "capture.start") glength <- attr(match, "capture.length") gend <- gstart + glength - 1L groupstr <- substring(text, gstart, gend) groupstr[ gstart == -1 ] <- NA_character_ dim(groupstr) <- dim(gstart) res <- cbind(groupstr, res, stringsAsFactors = FALSE) } names(res) <- c(attr(match, "capture.names"), ".text", ".match") res } # A better version (with far more dependencies) exists in msg-format.R bullets <- function(header, ..., .problem) { problems <- c(...) MAX_BULLETS <- 6L if (length(problems) >= MAX_BULLETS) { n_more <- length(problems) - MAX_BULLETS + 1L problems[[MAX_BULLETS]] <- "..." length(problems) <- MAX_BULLETS } paste0( header, "\n", paste0("* ", problems, collapse = "\n") ) } # FIXME: Also exists in pillar, do we need to export? tick <- function(x) { ifelse(is.na(x), "NA", encodeString(x, quote = "`")) } is_syntactic <- function(x) { ret <- (make_syntactic(x) == x) ret[is.na(x)] <- FALSE ret } tick_if_needed <- function(x) { needs_ticks <- !is_syntactic(x) x[needs_ticks] <- tick(x[needs_ticks]) x } tibble/R/strrep.R0000644000176200001440000000023013437532500013353 0ustar liggesusersif (getRversion() < "3.3.0") { strrep <- function(x, times) { map_chr( times, function(n) paste(rep(x, n), collapse = "") ) } } tibble/R/type-sum.r0000644000176200001440000000242013464363736013677 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 and the data source in the first element, #' and additional information in the other elements (such as grouping for \pkg{dplyr}). #' The default implementation forwards to [pillar::obj_sum()]. #' #' @return A named character vector, describing the dimensions in the first element #' and the data source in the name of the first element. #' #' @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) { c("Description" = 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) 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.R0000644000176200001440000000347713437532500014232 0ustar liggesuserscheck_names_df <- function(j, x) { if (is.object(j)) { abort(error_unsupported_index(j)) } else { if (length(dim(j)) > 1) { abort(error_dim_column_index(j)) } switch(typeof(j), integer = , double = check_names_df_numeric(j, x), character = check_names_before_after_character(j, names(unclass(x))), logical = check_names_df_logical(j, x), abort(error_unsupported_index(j)) ) } } check_names_df_numeric <- function(j, x) { if (anyNA(j)) { abort(error_na_column_index()) } n <- length(unclass(x)) if (any(j != trunc(j)) || any(abs(j) > n)) { non_integer <- which(j != trunc(j)) if (has_length(non_integer)) { abort(error_nonint_column_index(non_integer, j[non_integer])) } neg_too_small <- which(j < -n) if (has_length(neg_too_small)) { abort(error_small_column_index(n, neg_too_small, j[neg_too_small])) } pos_too_large <- which(j > n) if (has_length(pos_too_large)) { abort(error_large_column_index(n, pos_too_large, j[pos_too_large])) } } j } check_names_df_logical <- function(j, x) { if (!(length(j) %in% c(1L, length(x)))) { abort(error_mismatch_column_flag(length(x), length(j))) } if (anyNA(j)) { abort(error_na_column_flag()) } seq_along(x)[j] } check_needs_no_dim <- function(j) { if (needs_dim(j)) { abort(error_dim_column_index(j)) } } # check_names_before_after ------------------------------------------------ check_names_before_after <- function(j, x) { if (!is_bare_character(j)) { return(j) } check_needs_no_dim(j) check_names_before_after_character(j, x) } check_names_before_after_character <- function(j, names) { pos <- safe_match(j, names) if (anyNA(pos)) { unknown_names <- j[is.na(pos)] abort(error_unknown_names(unknown_names)) } pos } tibble/R/subsetting.R0000644000176200001440000001053713437532500014236 0ustar liggesusers#' Subsetting tibbles #' #' @description #' Accessing columns, rows, or cells via `$`, `[[`, or `[` is mostly similar to #' [regular data frames][base::Extract.data.frame]. However, the #' behavior is different for tibbles and data frames in some cases: #' * `[` always returns a tibble by default, even if #' only one column is accessed. #' * Partial matching of column names with `$` and `[[` is not supported, a #' warning is given and `NULL` is returned. #' #' Unstable return type and implicit partial matching can lead to surprises and #' bugs that are hard to catch. If you rely on code that requires the original #' data frame behavior, coerce to a data frame via [as.data.frame()]. #' #' @details #' For better compatibility with older code written for regular data frames, #' `[` supports a `drop` argument which defaults to `FALSE`. #' New code should use `[[` to turn a column into a vector. #' #' @name subsetting #' @examples #' df <- data.frame(a = 1:3, bc = 4:6) #' tbl <- tibble(a = 1:3, bc = 4:6) #' #' # Subsetting single columns: #' df[, "a"] #' tbl[, "a"] #' tbl[, "a", drop = TRUE] #' as.data.frame(tbl)[, "a"] #' #' # Subsetting single rows with the drop argument: #' df[1, , drop = TRUE] #' tbl[1, , drop = TRUE] #' as.list(tbl[1, ]) #' #' # Accessing non-existent columns: #' df$b #' tbl$b #' #' df[["b", exact = FALSE]] #' tbl[["b", exact = FALSE]] #' #' df$bd <- c("n", "e", "w") #' tbl$bd <- c("n", "e", "w") #' df$b #' tbl$b #' #' df$b <- 7:9 #' tbl$b <- 7:9 #' df$b #' tbl$b #' #' # Identical behavior: #' tbl[1, ] #' tbl[1, c("bc", "a")] #' tbl[, c("bc", "a")] #' tbl[c("bc", "a")] #' tbl["a"] #' tbl$a #' tbl[["a"]] NULL #' @rdname subsetting #' @param i,j Row and column indices. If `j` is omitted, `i` is used as column index. #' @param ... Ignored. #' @param exact Ignored, with a warning. #' @export `[[.tbl_df` <- function(x, i, j, ..., exact = TRUE) { if (!exact) { warningc("exact ignored") } if (missing(j)) { return(.subset2(x, i)) } NextMethod() } #' @rdname subsetting #' @inheritParams base::`[.data.frame` #' @export `$.tbl_df` <- function(x, name) { if (is.character(name)) { ret <- .subset2(x, name) if (is.null(ret)) warningc("Unknown or uninitialised column: '", name, "'.") return(ret) } .subset2(x, name) } #' @rdname subsetting #' @param drop Coerce to a vector if fetching one column via `tbl[, j]` . #' Default `FALSE`, ignored when accessing a column via `tbl[j]` . #' @export `[.tbl_df` <- function(x, i, j, drop = FALSE) { # 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)) { return(x) } i <- check_names_df(i, x) result <- .subset(x, i) nr <- fast_nrow(x) return(vec_restore_tbl_df_with_nr(result, x, nr)) } # First, subset columns if (missing(j)) { result <- x } else { j <- check_names_df(j, x) result <- .subset(x, j) } # Next, subset rows if (missing(i)) { nr <- fast_nrow(x) } else { if (is.logical(i) && !(length(i) %in% c(1L, fast_nrow(x)))) { warningc( "Length of logical index must be 1", if (fast_nrow(x) != 1) paste0(" or ", fast_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, subset_rows, i) nr <- NROW(result[[1]]) } } if (drop) { if (length(result) == 1L) { return(result[[1L]]) } } vec_restore_tbl_df_with_nr(result, x, nr) } fast_nrow <- function(x) { .row_names_info(x, 2L) } subset_rows <- function(x, i) { if (is.data.frame(x) || is.matrix(x)) { x[i, , drop = FALSE] } else { x[i] } } # TODO: Consider changing to vec_restore.tbl_df() when vctrs is available, # but this will impact performance of subsetting! vec_restore_tbl_df_with_nr <- function(x, to, nr) { # Copy attribute, preserving existing names and rownames attr_to <- attributes(to) new_names <- names(unclass(x)) new_nr <- .set_row_names(nr) attr_to[["names"]] <- new_names attr_to[["row.names"]] <- new_nr attributes(x) <- attr_to x } tibble/R/has-name.R0000644000176200001440000000003313437532500013526 0ustar liggesusers#' @export rlang::has_name tibble/R/enframe.R0000644000176200001440000000365313437532500013465 0ustar liggesusers#' Converting vectors to data frames, and vice versa #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} #' #' `enframe()` converts named atomic vectors or lists to one- or two-column #' data frames. #' For a list, the result will be a nested tibble with a column of type `list`. #' For unnamed vectors, the natural sequence is used as name column. #' #' @param x An atomic vector (for `enframe()`) or a data frame with one or two columns #' (for `deframe()`). #' @param name,value Names of the columns that store the names and values. #' If `name` is `NULL`, a one-column tibble is returned; `value` cannot be `NULL`. #' #' @return A [tibble] with two columns (if `name` is not `NULL`, the default) #' or one column (otherwise). #' @export #' #' @examples #' enframe(1:3) #' enframe(c(a = 5, b = 7)) #' enframe(list(one = 1, two = 2:3, three = 4:6)) enframe <- function(x, name = "name", value = "value") { if (is_null(value)) { abort(error_enframe_value_null()) } if (length(dim(x)) > 1) { abort(error_enframe_has_dim(x)) } if (is_null(x)) x <- logical() if (is_null(name)) { df <- list(unname(x)) } else if (is_null(names(x))) { df <- list(seq_along(x), x) } else { df <- list(names(x), unname(x)) } names(df) <- c(name, value) new_tibble(df, nrow = length(x)) } #' @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. #' If the input has only one column, an unnamed vector is returned. #' @export #' @examples #' deframe(enframe(1:3)) #' deframe(tibble(a = 1:3)) #' deframe(tibble(a = as.list(1:3))) deframe <- function(x) { if (length(x) == 1) { return(x[[1]]) } else if (length(x) != 2) { warn("The input to `deframe()` must be a one- or two-column data frame.") } value <- x[[2L]] name <- x[[1L]] names(value) <- name value } tibble/R/msg.R0000644000176200001440000001565213464363736012655 0ustar liggesusers# Looks into top-level tibble function, # returns TRUE if that function has a given argument. has_tibble_arg <- function(arg_name) { frames <- sys.frames() frame_env <- map(frames, parent.env) frame_is_namespace <- which(map_lgl(frame_env, identical, ns_env())) if (is_empty(frame_is_namespace)) return(FALSE) my_vars <- names(formals(sys.function(frame_is_namespace[[1]]))) arg_name %in% my_vars } data_has_n_cols <- function(n) { paste0("`.data` has ", n, " columns") } invalid_df <- function(problem, vars, ...) { if (is.character(vars)) { vars <- tick(vars) } pluralise_commas( "Column(s) ", vars, paste0(" ", problem, ".", ...) ) } use_repair <- function(repair) { if (repair) "\nUse .name_repair to specify repair." } error_enframe_value_null <- function() { "The `value` argument to `enframe()` cannot be NULL." } error_enframe_has_dim <- function(x) { paste0("`x` must not have more than one dimension. `length(dim(x))` must be zero or one, not ", length(dim(x)), ".") } error_1d_array_column <- function() { "1d arrays are not supported in a tibble column." } error_unsupported_index <- function(j) { paste0("Can't subset with `[` using an object of class ", class(j)[[1L]], ".") } error_na_column_index <- function() { "Can't use numeric NA as column index with `[`." } error_nonint_column_index <- function(pos, value) { bullets( "Must use integers to index columns with `[`:", paste0("Position ", pos, " equals ", value) ) } error_small_column_index <- function(n, pos, value) { bullets( "Negative column indexes in `[` must match number of columns:", data_has_n_cols(n), paste0("Position ", pos, " equals ", value) ) } error_large_column_index <- function(n, pos, value) { bullets( "Positive column indexes in `[` must match number of columns:", data_has_n_cols(n), paste0("Position ", pos, " equals ", value) ) } error_dim_column_index <- function(j) { paste0("Must use a vector in `[`, not an object of class ", class(j)[[1L]], ".") } error_mismatch_column_flag <- function(n, j) { bullets( "Length of logical index vector for `[` must equal number of columns (or 1):", data_has_n_cols(n), paste0("Index vector has length ", j) ) } error_na_column_flag <- function() { "Can't use logical NA when selecting columns with `[`." } error_unknown_names <- function(names) { pluralise_commas("Can't find column(s) ", tick(names), " in `.data`.") } error_existing_names <- function(names) { pluralise_commas("Column(s) ", tick(names), " already exist[s] in `.data`.") } error_add_rows_to_grouped_df <- function() { "Can't add rows to grouped data frames" } error_inconsistent_new_rows <- function(names) { bullets( "New rows in `add_row()` must use columns that already exist:", error_unknown_names(names) ) } error_names_must_be_non_null <- function(repair = has_tibble_arg(".name_repair")) { paste0("The `names` must not be `NULL`.", use_repair(repair)) } error_names_must_have_length <- function(length, n) { paste0("The `names` must have length ", n, ", not ", length, ".") } error_column_must_be_named <- function(names, repair = has_tibble_arg(".name_repair")) { invalid_df("must be named", names, use_repair(repair)) } error_column_must_not_be_dot_dot <- function(names, repair = has_tibble_arg(".name_repair")) { invalid_df("must not have names of the form ... or ..j", names, use_repair(repair)) } error_column_names_must_be_unique <- function(names, repair = has_tibble_arg(".name_repair")) { pluralise_commas("Column name(s) ", tick(names), " must not be duplicated.", use_repair(repair)) } error_column_names_must_be_syntactic <- function(names, repair = has_tibble_arg(".name_repair")) { pluralise_commas("Column name(s) ", tick(names), " must be syntactic.", use_repair(repair)) } error_column_must_be_vector <- function(names, classes) { bullets( "All columns in a tibble must be 1d or 2d objects:", paste0("Column ", tick(names), " is ", classes) ) } error_time_column_must_be_posixct <- function(names) { invalid_df("[is](are) [a ]date(s)/time(s) and must be stored as POSIXct, not POSIXlt", names) } error_inconsistent_cols <- function(.rows, vars, vars_len, rows_source) { vars_split <- split(vars, vars_len) vars_split[["1"]] <- NULL if (!is.null(.rows)) { vars_split[[as.character(.rows)]] <- NULL } bullets( "Tibble columns must have consistent lengths, only values of length one are recycled:", if (!is.null(.rows)) paste0("Length ", .rows, ": Requested with ", rows_source), map2_chr(names(vars_split), vars_split, function(x, y) paste0("Length ", x, ": ", pluralise_commas("Column(s) ", tick(y)))) ) } error_inconsistent_new_cols <- function(n, df) { bullets( "New columns in `add_column()` must be consistent with `.data`:", pluralise_count("`.data` has ", n, " row(s)"), paste0( pluralise_n("New column(s) contribute[s]", ncol(df)), " ", nrow(df), " rows" ) ) } error_duplicate_new_cols <- function(names) { bullets( "Can't add duplicate columns with `add_column()`:", error_existing_names(names) ) } error_both_before_after <- function() { "Can't specify both `.before` and `.after`." } error_already_has_rownames <- function() { "`df` must be a data frame without row names in `column_to_rownames()`." } error_as_tibble_needs_rownames <- function() { "Object passed to `as_tibble()` must have row names if the `rownames` argument is set." } error_glimpse_infinite_width <- function() { "`glimpse()` requires a finite value for the `width` argument." } error_tribble_needs_columns <- function() { "`tribble()` needs to specify at least one column using the `~name` syntax." } error_tribble_lhs_column_syntax <- function(lhs) { bullets( "All column specifications in `tribble()` must use the `~name` syntax.", paste0("Found ", expr_label(lhs), " on the left-hand side of `~`.") ) } error_tribble_rhs_column_syntax <- function(rhs) { bullets( 'All column specifications in `tribble()` must use the `~name` or `~"name"` syntax.', paste0("Found ", expr_label(rhs), " on the right-hand side of `~`.") ) } error_tribble_non_rectangular <- function(cols, cells) { bullets( "`tribble()` must be used with rectangular data:", paste0("Found ", cols, " columns."), paste0("Found ", cells, " cells."), paste0(cells, " is not an integer multiple of ", cols, ".") ) } error_frame_matrix_list <- function(pos) { bullets( "All values in `frame_matrix()` must be atomic:", pluralise_commas("Found list-valued element(s) at position(s) ", pos, ".") ) } error_name_repair_arg <- function() { "The `.name_repair` argument must be a string or a function that specifies the name repair strategy." } error_new_tibble_must_be_list <- function() { "Must pass a list as `x` argument to `new_tibble()`." } error_new_tibble_needs_nrow <- function() { "Must pass a scalar integer as `nrow` argument to `new_tibble()`." } tibble/R/compat-lifecycle.R0000644000176200001440000001451613464363736015305 0ustar liggesusers# nocov start - compat-lifecycle (last updated: rlang 0.3.0.9000) # This file serves as a reference for currently unexported rlang # lifecycle functions. Please find the most recent version in rlang's # repository. These functions require rlang in your `Imports` # DESCRIPTION field but you don't need to import rlang in your # namespace. #' Signal deprecation #' #' @description #' #' These functions provide two levels of verbosity for deprecation #' warnings. #' #' * `signal_soft_deprecated()` warns only if called from the global #' environment (so the user can change their script) or from the #' package currently being tested (so the package developer can fix #' the package). #' #' * `warn_deprecated()` warns unconditionally. #' #' * `stop_defunct()` fails unconditionally. #' #' Both functions warn only once per session by default to avoid #' overwhelming the user with repeated warnings. #' #' @param msg The deprecation message. #' @param id The id of the deprecation. A warning is issued only once #' for each `id`. Defaults to `msg`, but you should give a unique ID #' when the message is built programmatically and depends on inputs. #' @param env The environment in which the soft-deprecated function #' was called. A warning is issued if called from the global #' environment. If testthat is running, a warning is also called if #' the retired function was called from the package being tested. #' #' @section Controlling verbosity: #' #' The verbosity of retirement warnings can be controlled with global #' options. You'll generally want to set these options locally with #' one of these helpers: #' #' * `with_lifecycle_silence()` disables all soft-deprecation and #' deprecation warnings. #' #' * `with_lifecycle_warnings()` enforces warnings for both #' soft-deprecated and deprecated functions. The warnings are #' repeated rather than signalled once per session. #' #' * `with_lifecycle_errors()` enforces errors for both #' soft-deprecated and deprecated functions. #' #' All the `with_` helpers have `scoped_` variants that are #' particularly useful in testthat blocks. #' #' @noRd #' @seealso [lifecycle()] NULL signal_soft_deprecated <- function(msg, id = msg, env = caller_env(2)) { if (rlang::is_true(rlang::peek_option("lifecycle_disable_warnings"))) { return(invisible(NULL)) } if (rlang::is_true(rlang::peek_option("lifecycle_verbose_soft_deprecation")) || rlang::is_reference(topenv(env), rlang::global_env())) { warn_deprecated(msg, id) return(invisible(NULL)) } # Test for environment names rather than reference/contents because # testthat clones the namespace tested_package <- Sys.getenv("TESTTHAT_PKG") if (nzchar(tested_package) && identical(Sys.getenv("NOT_CRAN"), "true") && rlang::env_name(topenv(env)) == rlang::env_name(ns_env(tested_package))) { warn_deprecated(msg, id) return(invisible(NULL)) } rlang::signal(msg, "lifecycle_soft_deprecated") } warn_deprecated <- function(msg, id = msg) { if (rlang::is_true(rlang::peek_option("lifecycle_disable_warnings"))) { return(invisible(NULL)) } if (!rlang::is_true(rlang::peek_option("lifecycle_repeat_warnings"))) { if (rlang::env_has(deprecation_env, id)) { return(invisible(NULL)) } has_colour <- function() rlang::is_installed("crayon") && crayon::has_color() silver <- function(x) if (has_colour()) crayon::silver(x) else x msg <- paste0( msg, "\n", silver("This warning is displayed once per session.") ) } rlang::env_poke(deprecation_env, id, TRUE) if (rlang::is_true(rlang::peek_option("lifecycle_warnings_as_errors"))) { signal <- .Defunct } else { signal <- .Deprecated } signal(msg = msg) } deprecation_env <- new.env(parent = emptyenv()) stop_defunct <- function(msg) { .Defunct(msg = msg) } scoped_lifecycle_silence <- function(frame = rlang::caller_env()) { rlang::scoped_options(.frame = frame, lifecycle_disable_warnings = TRUE ) } with_lifecycle_silence <- function(expr) { scoped_lifecycle_silence() expr } scoped_lifecycle_warnings <- function(frame = rlang::caller_env()) { rlang::scoped_options(.frame = frame, lifecycle_disable_warnings = FALSE, lifecycle_verbose_soft_deprecation = TRUE, lifecycle_repeat_warnings = TRUE ) } with_lifecycle_warnings <- function(expr) { scoped_lifecycle_warnings() expr } scoped_lifecycle_errors <- function(frame = rlang::caller_env()) { scoped_lifecycle_warnings(frame = frame) rlang::scoped_options(.frame = frame, lifecycle_warnings_as_errors = TRUE ) } with_lifecycle_errors <- function(expr) { scoped_lifecycle_errors() expr } #' Embed a lifecycle badge in documentation #' #' @description #' #' Use `lifecycle()` within a `Sexpr` macro to embed a #' [lifecycle](https://www.tidyverse.org/lifecycle/) badge in your #' documentation. The badge should appear first in the description: #' #' ``` #' \Sexpr[results=rd, stage=render]{mypkg:::lifecycle("questioning")} #' ``` #' #' The badge appears as an image in the HTML version of the #' documentation. To make them available in your package, visit #' and copy #' all the files starting with `lifecycle-` in your `man/figures/` #' folder. #' #' @param stage A lifecycle stage as a string, one of: #' `"experimental"`, `"maturing"`, `"stable"`, `"questioning"`, #' `"archived"`, `"soft-deprecated"`, `"deprecated"`, `"defunct"`. #' #' @noRd NULL lifecycle <- function(stage) { url <- paste0("https://www.tidyverse.org/lifecycle/#", stage) img <- lifecycle_img(stage, url) sprintf( "\\ifelse{html}{%s}{\\strong{%s}}", img, upcase1(stage) ) } lifecycle_img <- function(stage, url) { file <- sprintf("lifecycle-%s.svg", stage) stage_alt <- upcase1(stage) switch(stage, experimental = , maturing = , stable = , questioning = , archived = sprintf( "\\out{%s lifecycle}", url, file.path("figures", file), stage_alt ) , `soft-deprecated` = , deprecated = , defunct = sprintf( "\\figure{%s}{options: alt='%s lifecycle'}", file, stage_alt ), rlang::abort(sprintf("Unknown lifecycle stage `%s`", stage)) ) } upcase1 <- function(x) { substr(x, 1, 1) <- toupper(substr(x, 1, 1)) x } # nocov end tibble/R/new.R0000644000176200001440000001004013474034253012630 0ustar liggesusers#' Tibble constructor and validator #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} #' #' Creates or validates a subclass of a tibble. #' These function is mostly useful for package authors that implement subclasses #' of a tibble, like \pkg{sf} or \pkg{tsibble}. #' #' `new_tibble()` creates a new object as a subclass of `tbl_df`, `tbl` and `data.frame`. #' This function is optimized for performance, checks are reduced to a minimum. #' #' @param x A tibble-like object #' @param ... Passed on to [structure()] #' @param nrow The number of rows, required #' @param class Subclasses to assign to the new object, default: none #' @param subclass Deprecated, retained for compatibility. Please use the `class` argument. #' #' @seealso #' [tibble()] and [as_tibble()] for ways to construct a tibble #' with recycling of scalars and automatic name repair. #' #' @export #' @examples #' # The nrow argument is always required: #' new_tibble(list(a = 1:3, b = 4:6), nrow = 3) #' #' # Existing row.names attributes are ignored: #' try(new_tibble(iris, nrow = 3)) #' #' # The length of all columns must be consistent with the nrow argument: #' try(new_tibble(list(a = 1:3, b = 4:6), nrow = 2)) new_tibble <- function(x, ..., nrow, class = NULL, subclass = NULL) { # For compatibility with tibble < 2.0.0 if (is.null(class)) { class <- subclass } #' @section Construction: #' #' For `new_tibble()`, `x` must be a list. x <- unclass(x) if (!is.list(x)) { abort(error_new_tibble_must_be_list()) } #' The `...` argument allows adding more attributes to the subclass. x <- update_tibble_attrs(x, ...) #' An `nrow` argument is required. if (missing(nrow)) { if (length(x) >= 1) { signal_soft_deprecated(error_new_tibble_needs_nrow()) nrow <- NROW(x[[1]]) } else { abort(error_new_tibble_needs_nrow()) } } #' This should be an integer of length 1, #' and every element of the list `x` should have [NROW()] #' equal to this value. #' (But this is not checked by the constructor). #' This takes the place of the "row.names" attribute in a data frame. if (!is_integerish(nrow, 1)) { abort(error_new_tibble_needs_nrow()) } #' `x` must have names (or be empty), #' but the names are not checked for correctness. if (length(x) == 0) { # Leaving this because creating a named list of length zero seems difficult names(x) <- character() } else if (is.null(names(x))) { abort(error_names_must_be_non_null()) } set_tibble_subclass(x, nrow, class) } #' @description #' `validate_tibble()` checks a tibble for internal consistency. #' Correct behavior can be guaranteed only if this function #' runs without raising an error. #' #' @rdname new_tibble #' @export validate_tibble <- function(x) { #' @section Validation: #' `validate_tibble()` checks for "minimal" names check_minimal_names(x) #' and that all columns are vectors, data frames or matrices. check_valid_cols(x) #' It also makes sure that all columns have the same length, #' and that [NROW()] is consistent with the data. validate_nrow(names(x), col_lengths(x), NROW(x)) #' 1d arrays are not supported. map(x, check_no_dim) x } col_lengths <- function(x) { map_int(x, NROW) } validate_nrow <- function(names, lengths, nrow) { # Validate column lengths, don't recycle bad_len <- which(lengths != nrow) if (has_length(bad_len)) { abort(error_inconsistent_cols(nrow, names, lengths, "`nrow` argument")) } } update_tibble_attrs <- function(x, ...) { # Can't use structure() here because it breaks the row.names attribute attribs <- list(...) if (has_length(attribs)) { attributes(x)[names(attribs)] <- attribs } x } tibble_class <- c("tbl_df", "tbl", "data.frame") # Two dedicated functions for faster subsetting set_tibble_class <- function(x, nrow) { attr(x, "row.names") <- .set_row_names(nrow) class(x) <- tibble_class x } set_tibble_subclass <- function(x, nrow, subclass) { attr(x, "row.names") <- .set_row_names(nrow) class(x) <- c(subclass, tibble_class) x } tibble/R/exports.R0000644000176200001440000000024713437532500013550 0ustar liggesusersmatrixToDataFrame <- function(x) { .Call(`tibble_matrixToDataFrame`, x) } string_to_indices <- function(x) { .Call(`tibble_string_to_indices`, as.character(x)) } tibble/R/msg-format.R0000644000176200001440000000370213464363736014134 0ustar liggesuserspluralise_msg <- function(message, objects) { paste0( pluralise(message, objects), format_n(objects) ) } pluralise_commas <- function(message, objects, ...) { paste0( pluralise_n(message, length(objects)), commas(objects), pluralise_n(paste0(...), length(objects)) ) } pluralise_count <- function(message, count, ...) { paste0( pluralise_n(message, count), count, pluralise_n(paste0(...), count) ) } pluralise <- function(message, objects) { pluralise_n(message, length(objects)) } pluralise_n <- function(message, n) { stopifnot(n >= 0) # Don't strip parens if they have a space in between # (but not if the space comes before the closing paren) if (n == 1) { # strip [ message <- gsub("\\[([^\\] ]* *)\\]", "\\1", message, perl = TRUE) # remove ( and its content message <- gsub("\\([^\\) ]* *\\)", "", message, perl = TRUE) } else { # strip ( message <- gsub("\\(([^\\) ]* *)\\)", "\\1", message, perl = TRUE) # remove [ and its content message <- gsub("\\[[^\\] ]* *\\]", "", message, perl = TRUE) } message } # Also exists in compat-name-repair.R, need to make sure to overwrite with a better version #' @include compat-name-repair.R bullets <- function(header, ..., .problem = " problem(s)") { problems <- c(...) MAX_BULLETS <- 6L if (length(problems) >= MAX_BULLETS) { n_more <- length(problems) - MAX_BULLETS + 1L problems[[MAX_BULLETS]] <- pluralise_n(paste0(pre_dots("and "), n_more, " more", .problem), n_more) length(problems) <- MAX_BULLETS } paste0( header, "\n", paste0("* ", problems, collapse = "\n") ) } commas <- function(problems) { MAX_BULLETS <- 6L if (length(problems) >= MAX_BULLETS) { n_more <- length(problems) - MAX_BULLETS + 1L problems[[MAX_BULLETS]] <- pluralise_n(paste0(pre_dots("(and "), n_more, " more)"), n_more) length(problems) <- MAX_BULLETS } paste0(problems, collapse = ", ") } tibble/R/utils-format.r0000644000176200001440000002355413407176030014537 0ustar liggesusers#' Printing tibbles #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} #' #' One of the main features of the `tbl_df` class is the printing: #' #' * Tibbles only print as many rows and columns as fit on one screen, #' supplemented by a summary of the remaining rows and columns. #' * Tibble reveals the type of each column, which keeps the user informed about #' whether a variable is, e.g., `` or `` (character versus factor). #' #' Printing can be tweaked for a one-off call by calling `print()` explicitly #' and setting arguments like `n` and `width`. More persistent control is #' available by setting the options described below. #' #' @inheritSection pillar::`pillar-package` Package options #' @section Package options: #' #' Options used by the tibble and pillar packages to format and print `tbl_df` #' objects. Used by the formatting workhorse `trunc_mat()` and, therefore, #' indirectly, by `print.tbl()`. #' #' * `tibble.print_max`: Row number threshold: Maximum number of rows printed. #' Set to `Inf` to always print all rows. Default: 20. #' * `tibble.print_min`: Number of rows printed if row number threshold is #' exceeded. Default: 10. #' * `tibble.width`: Output width. Default: `NULL` (use `width` option). #' * `tibble.max_extra_cols`: Number of extra columns printed in reduced form. #' Default: 100. #' #' @param x Object to format or print. #' @param ... Other arguments passed on to individual methods. #' @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. #' @examples #' print(as_tibble(mtcars)) #' print(as_tibble(mtcars), n = 1) #' print(as_tibble(mtcars), n = 3) #' #' print(as_tibble(iris), n = 100) #' #' print(mtcars, width = 10) #' #' mtcars2 <- as_tibble(cbind(mtcars, mtcars), .name_repair = "unique") #' print(mtcars2, n = 25, n_extra = 3) #' #' trunc_mat(mtcars) #' #' if (requireNamespace("nycflights13", quietly = TRUE)) { #' print(nycflights13::flights, n_extra = 2) #' print(nycflights13::flights, width = Inf) #' } #' @name formatting NULL #' @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) } #' Legacy help page for compatibility with existing packages #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("archived")} #' #' Please see [print.tbl()] for the print method for tibbles. #' #' @name print.tbl_df #' @keywords internal NULL #' @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) } #' @export #' @rdname formatting trunc_mat <- function(x, n = NULL, width = NULL, n_extra = NULL) { rows <- nrow(x) if (is_null(n) || n < 0) { 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") if (is.na(rows)) { df <- as.data.frame(head(x, n + 1)) if (nrow(df) <= n) { rows <- nrow(df) } else { df <- df[seq_len(n), , drop = FALSE] } } else { 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 } width <- tibble_width(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, n = x$n_extra)) 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) 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) { # Also covers empty extra_cols vector! if (is.na(extra_cols[1])) return("") if (anyNA(extra_cols)) { extra_cols <- c(extra_cols[!is.na(extra_cols)], cli::symbol$ellipsis) } paste0(": ", collapse(extra_cols)) } 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(cli::symbol$ellipsis, " ", 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 "," ret <- formatC(x, big.mark = mark, ...) ret[is.na(x)] <- "??" ret } 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") } 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.R0000644000176200001440000001066513473044414013476 0ustar liggesusers#' Row-wise tibble creation #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} #' #' 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. #' #' @param ... Arguments specifying the structure of a `tibble`. #' Variable names should be formulas, and may only appear before the #' data. These arguments support [tidy dots][rlang::tidy-dots]. #' @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) } #' Row-wise matrix creation #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} #' #' 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. These arguments support [tidy dots][rlang::tidy-dots]. #' @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 <- list2(...) # Extract the names. frame_names <- extract_frame_names_from_dots(dots) # Extract the data if (length(frame_names) == 0 && length(dots) != 0) { abort(error_tribble_needs_columns()) } 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) { abort(error_tribble_lhs_column_syntax(el[[2]])) } candidate <- el[[2]] if (!(is.symbol(candidate) || is.character(candidate))) { abort(error_tribble_rhs_column_syntax(candidate)) } frame_names <- c(frame_names, as.character(candidate)) } 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) { abort(error_tribble_non_rectangular( length(frame_names), length(frame_rest) )) } } 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) if (length(frame_col) == 0) { return(new_tibble(list(), nrow = 0)) } # Create a tbl_df and return it names(frame_col) <- names new_tibble(frame_col, nrow = NROW(frame_col[[1]])) } 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) { list_cols <- which(map_lgl(rest, needs_list_col)) if (has_length(list_cols)) { abort(error_frame_matrix_list(list_cols)) } frame_ncol <- length(names) frame_mat <- matrix(unlist(rest), ncol = frame_ncol, byrow = TRUE) colnames(frame_mat) <- names frame_mat } tibble/R/tibble-package.R0000644000176200001440000000335013437532500014674 0ustar liggesusers#' @useDynLib tibble, .registration = TRUE #' @importFrom utils head tail #' @importFrom pkgconfig set_config #' @import rlang #' @aliases NULL tibble-package #' @details #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("stable")} #' #' The tibble package provides utilities for handling __tibbles__, where #' "tibble" is a colloquial term for the S3 [`tbl_df`] class. The [`tbl_df`] #' class is a special case of the base [`data.frame`][base::data.frame()]. #' class, developed in response to lessons learned over many years of data #' analysis with data frames. #' #' Tibble is the central data structure for the set of packages known as the #' [tidyverse](https://www.tidyverse.org/packages/), including #' [dplyr](http://dplyr.tidyverse.org/), #' [ggplot2](http://ggplot2.tidyverse.org/), #' [tidyr](http://tidyr.tidyverse.org/), and #' [readr](http://readr.tidyverse.org/). #' #' General resources: #' * Website for the tibble package: #' * [Tibbles chapter](http://r4ds.had.co.nz/tibbles.html) in *R for Data #' Science* #' #' Resources on specific topics: #' * Create a tibble: [tibble()], [as_tibble()], [tribble()], [enframe()] #' * Inspect a tibble: [print.tbl()], [glimpse()] #' * Details on the S3 `tbl_df` class: [`tbl_df-class`] "_PACKAGE" ## user-facing docs kept in `formatting` topic; see utils-format.r op.tibble <- list( tibble.print_max = 20L, tibble.print_min = 10L, tibble.width = NULL, 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/glimpse.R0000644000176200001440000000713513464363736013524 0ustar liggesusers#' Get a glimpse of your data #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} #' #' 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)) { #' glimpse(nycflights13::flights) #' } glimpse <- function(x, width = NULL, ...) { UseMethod("glimpse") } #' @export #' @importFrom pillar new_pillar_title #' @importFrom pillar new_pillar_type glimpse.tbl <- function(x, width = NULL, ...) { width <- tibble_glimpse_width(width) if (!is.finite(width)) { abort(error_glimpse_infinite_width()) } cat_line("Observations: ", big_mark(nrow(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)) cat_line("Variables: ", big_mark(ncol(df))) summary <- tbl_sum(x) brief_summary <- summary[-1] if (has_length(brief_summary)) { cat_line(names(brief_summary), ": ", brief_summary) } if (ncol(df) == 0) return(invisible(x)) var_types <- map_chr(map(df, new_pillar_type), format) ticked_names <- format(new_pillar_title(tick_if_needed(names(df)))) var_names <- paste0("$ ", justify(ticked_names, right = FALSE), " ", var_types, " ") data_width <- width - crayon::col_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) nchar_ellipsis <- nchar_width(cli::symbol$ellipsis) for (i in seq_along(x)) { if (width[i] <= max_width[i]) next x[i] <- paste0(substr(x[i], 1, max_width[i] - nchar_ellipsis), cli::symbol$ellipsis) } x } format_v <- function(x) UseMethod("format_v") #' @export format_v.default <- function(x) { dims <- dim(x) if (!is.null(dims)){ dims_out <- paste0(dims, collapse = " x ") out <- paste0("<", class(x)[1], "[", dims_out, "]>") out } else { 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 = '"') #' @export format_v.factor <- function(x) { if (any(grepl(",", x, fixed = TRUE))) { encodeString(as.character(x), quote = '"') } else { format(x, trim = TRUE, justify = "none") } } tibble/R/utils.r0000644000176200001440000000216713464363736013264 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<-` check_no_dim <- function(x) { if (is_atomic(x) && has_dim(x)) { abort(error_1d_array_column()) } invisible(x) } strip_dim <- function(x) { if (is.matrix(x)) { rownames(x) <- NULL } else if (is.data.frame(x)) { x <- remove_rownames(x) x[] <- map(x, strip_dim) } else if (is_atomic(x) && has_dim(x)) { # Careful update only if necessary, to avoid copying which is checked by # the "copying" test in dplyr dim(x) <- NULL } x } needs_list_col <- function(x) { is_list(x) || length(x) != 1L } # Work around bug in R 3.3.0 # Can be ressigned during loading (#544) safe_match <- match warningc <- function(...) { warn(paste0(...)) } nchar_width <- function(x) { nchar(x, type = "width") } cat_line <- function(...) { cat(paste0(..., "\n"), sep = "") } is_rstudio <- function() { !is.na(Sys.getenv("RSTUDIO", unset = NA)) } tibble/R/rownames.R0000644000176200001440000000567113437532500013705 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. #' #' @return `column_to_rownames()` always returns a data frame. #' `has_rownames()` returns a scalar logical. #' All other functions return an object of the same class as the input. #' #' @param .data 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 #' head(column_to_rownames(mtcars_tbl)) #' @name rownames NULL #' @export #' @rdname rownames has_rownames <- function(.data) { .row_names_info(.data) > 0L } #' @export #' @rdname rownames remove_rownames <- function(.data) { stopifnot(is.data.frame(.data)) rownames(.data) <- NULL .data } #' @export #' @rdname rownames rownames_to_column <- function(.data, var = "rowname") { # rename, because .data has special semantics in tidy evaluation df <- .data stopifnot(is.data.frame(df)) if (has_name(df, var)) { abort(error_existing_names(var)) } new_df <- add_column(df, !!var := rownames(df), .before = 1) remove_rownames(new_df) } #' @export #' @rdname rownames rowid_to_column <- function(.data, var = "rowid") { # rename, because .data has special semantics in tidy evaluation df <- .data stopifnot(is.data.frame(df)) if (has_name(df, var)) { abort(error_existing_names(var)) } new_df <- add_column(df, !!var := seq_len(nrow(df)), .before = 1) remove_rownames(new_df) } #' @rdname rownames #' @export column_to_rownames <- function(.data, var = "rowname") { stopifnot(is.data.frame(.data)) if (has_rownames(.data)) { abort(error_already_has_rownames()) } if (!has_name(.data, var)) { abort(error_unknown_names(var)) } .data <- as.data.frame(.data) rownames(.data) <- .data[[var]] .data[[var]] <- NULL .data } #' @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.R0000644000176200001440000001323313473044414013306 0ustar liggesusers#' Build a data frame #' #' @description #' #' `tibble()` constructs a data frame. It is used like [base::data.frame()], but #' with a couple notable differences: #' #' * The returned data frame has the class [`tbl_df`][tbl_df-class], in #' addition to `data.frame`. This allows so-called "tibbles" to exhibit some #' special behaviour, such as [enhanced printing][formatting]. Tibbles are #' fully described in [`tbl_df`][tbl_df-class]. #' * `tibble()` is much lazier than [base::data.frame()] in terms of #' transforming the user's input. Character vectors are not coerced to #' factor. List-columns are expressly anticipated and do not require special #' tricks. Column names are not modified. #' * `tibble()` builds columns sequentially. When defining a column, you can #' refer to columns created earlier in the call. Only columns of length one #' are recycled. #' #' @param ... A set of name-value pairs. Arguments are evaluated sequentially, #' so you can refer to previously created elements. These arguments are #' processed with [rlang::quos()] and support unquote via [`!!`] and #' unquote-splice via [`!!!`]. Use `:=` to create columns that start with a dot. #' @param .rows The number of rows, useful to create a 0-column tibble or #' just as an additional check. #' @param .name_repair Treatment of problematic column names: #' * `"minimal"`: No name repair or checks, beyond basic existence, #' * `"unique"`: Make sure names are unique and not empty, #' * `"check_unique"`: (default value), no name repair, but check they are #' `unique`, #' * `"universal"`: Make the names `unique` and syntactic #' * a function: apply custom name repair (e.g., `.name_repair = make.names` #' for names in the style of base R). #' * A purrr-style anonymous function, see [rlang::as_function()] #' #' See [name-repair] for more details on these terms and the strategies used #' to enforce them. #' #' @return A tibble, which is a colloquial term for an object of class #' [`tbl_df`][tbl_df-class]. A [`tbl_df`][tbl_df-class] object is also a data #' frame, i.e. it has class `data.frame`. #' @seealso Use [as_tibble()] to turn an existing object into a tibble. Use #' `enframe()` to convert a named vector into tibble. Name repair is detailed #' in [name-repair]. [rlang::list2()] provides more details on tidy dots #' semantics, i.e. exactly how [quasiquotation] works for the `...` argument. #' @export #' @examples #' # Unnamed arguments are named with their expression: #' a <- 1:5 #' tibble(a, a * 2) #' #' # Scalars (vectors of length one) are recycled: #' tibble(a, b = a * 2, c = 1) #' #' # Columns are available in subsequent expressions: #' tibble(x = runif(10), y = x * 2) #' #' # tibble() never coerces its inputs, #' str(tibble(letters)) #' str(tibble(x = list(diag(1), diag(2)))) #' #' # or munges column names (unless requested), #' tibble(`a + b` = 1:5) #' #' # but it forces you to take charge of names, if they need repair: #' try(tibble(x = 1, x = 2)) #' tibble(x = 1, x = 2, .name_repair = "unique") #' tibble(x = 1, x = 2, .name_repair = "minimal") #' #' ## By default, non-syntactic names are allowed, #' df <- tibble(`a 1` = 1, `a 2` = 2) #' ## because you can still index by name: #' df[["a 1"]] #' df$`a 1` #' with(df, `a 1`) #' #' ## Syntactic names are easier to work with, though, and you can request them: #' df <- tibble(`a 1` = 1, `a 2` = 2, .name_repair = "universal") #' df$a.1 #' #' ## You can specify your own name repair function: #' tibble(x = 1, x = 2, .name_repair = make.unique) #' #' fix_names <- function(x) gsub("\\s+", "_", x) #' tibble(`year 1` = 1, `year 2` = 2, .name_repair = fix_names) #' #' ## purrr-style anonymous functions and constants #' ## are also supported #' tibble(x = 1, x = 2, .name_repair = ~ make.names(., unique = TRUE)) #' #' tibble(x = 1, x = 2, .name_repair = ~ c("a", "b")) #' #' # Tibbles can contain columns that are tibbles or matrices #' # if the number of rows is consistent: #' tibble( #' a = 1:3, #' b = tibble( #' c = 4:6, #' d = 7:9 #' ), #' e = tibble( #' f = tibble( #' g = letters[1:3] #' ) #' ) #' ) #' tibble( #' a = 1:4, #' b = diag(4), #' c = cov(iris[1:4]) #' ) #' #' # data can not contain POSIXlt columns, or tibbles or matrices #' # with inconsistent number of rows: #' try(tibble(y = strptime("2000/01/01", "%x"))) #' try(tibble(a = 1:3, b = tibble(c = 4:7))) #' #' # Use := to create columns with names that start with a dot: #' tibble(.rows = 3) #' tibble(.rows := 3) #' #' # You can unquote an expression: #' x <- 3 #' tibble(x = 1, y = x) #' tibble(x = 1, y = !!x) #' #' # You can splice-unquote a list of quosures and expressions: #' tibble(!!!list(x = rlang::quo(1:10), y = quote(x * 2))) #' tibble <- function(..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal")) { xs <- quos(..., .named = TRUE) xlq <- lst_quos(xs, transform = expand_lst) lst_to_tibble(xlq$output, .rows, .name_repair, lengths = xlq$lengths) } #' Test if the object is a tibble #' #' This function returns `TRUE` for tibbles or subclasses thereof, #' and `FALSE` for all other objects, including regular data frames. #' #' @param x An object #' @return `TRUE` if the object inherits from the `tbl_df` class. #' @export is_tibble <- function(x) { inherits(x, "tbl_df") } #' Deprecated test for tibble-ness #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("soft-deprecated")} #' #' Please use [is_tibble()] instead. #' #' @inheritParams is_tibble #' @export #' @keywords internal is.tibble <- function(x) { signal_soft_deprecated("`is.tibble()` is deprecated, use `is_tibble()`.") is_tibble(x) } tibble/R/as_tibble.R0000644000176200001440000002133713473044414013775 0ustar liggesusers#' Coerce lists, matrices, and more to data frames #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} #' #' `as_tibble()` turns an existing object, such as a data frame, list, or #' matrix, into a so-called tibble, a data frame with class [`tbl_df`]. This is #' in contrast with [tibble()], which builds a tibble from individual columns. #' `as_tibble()` is to [`tibble()`] as [base::as.data.frame()] is to #' [base::data.frame()]. #' #' `as_tibble()` is an S3 generic, with methods for: #' * [`data.frame`][base::data.frame()]: Thin wrapper around the `list` method #' that implements tibble's treatment of [rownames]. #' * list #' * [`matrix`][methods::matrix-class], [`poly`][stats::poly()], #' [`ts`][stats::ts()], [`table`][base::table()] #' * Default: An atomic vector is first coerced to a list and, unlike #' [base::as.data.frame()], the returned tibble has one column per element. #' Other inputs are first coerced with [base::as.data.frame()]. #' #' @section Row names: #' The default behavior is to silently remove row names. #' #' New code should explicitly convert row names to a new column using the #' `rownames` argument. #' #' For existing code that relies on the retention of row names, call #' `pkgconfig::set_config("tibble::rownames" = NA)` in your script or in your #' package's [.onLoad()] function. #' #' @seealso [tibble()] constructs a tibble from individual columns. [enframe()] #' converts a named vector to a tibble with a column of names and column of #' values. [name-repair] documents the details of name repair. #' #' @param x A data frame, list, matrix, or other object that could reasonably be #' coerced to a tibble. #' @param ... Other arguments passed on to individual methods. #' @inheritParams tibble #' @param rownames How to treat existing row names of a data frame or matrix: #' * `NULL`: remove row names. This is the default. #' * `NA`: keep row names. #' * A string: the name of a new column. Existing rownames are transferred #' into this column and the `row.names` attribute is deleted. #' Read more in [rownames]. #' @param _n,validate For compatibility only, do not use for new code. #' @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(as.list(1:3), .name_repair = "unique") #' #' # Prefer enframe() for vectors #' enframe(1:3) #' enframe(1:3, name = NULL) #' #' # For list-like inputs, `as_tibble()` is considerably simpler than #' # `as.data.frame()` and hence faster #' \dontrun{ #' if (requireNamespace("bench", quietly = TRUE)) { #' l2 <- replicate(26, sample(letters), simplify = FALSE) #' names(l2) <- letters #' bench::mark( #' as_tibble(l2, .name_repair = "universal"), #' as_tibble(l2, .name_repair = "unique"), #' as_tibble(l2, .name_repair = "minimal"), #' as_tibble(l2), #' as.data.frame(l2), #' check = FALSE #' ) #' } #' } as_tibble <- function(x, ..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal"), rownames = pkgconfig::get_config("tibble::rownames", NULL)) { UseMethod("as_tibble") } #' @export #' @rdname as_tibble as_tibble.data.frame <- function(x, validate = NULL, ..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal"), rownames = pkgconfig::get_config("tibble::rownames", NULL)) { .name_repair <- compat_name_repair(.name_repair, validate) old_rownames <- raw_rownames(x) if (is.null(.rows)) { .rows <- nrow(x) } result <- as_tibble.list(unclass(x), ..., .rows = .rows, .name_repair = .name_repair) if (is.null(rownames)) { result } else if (is.na(rownames)) { attr(result, "row.names") <- old_rownames result } else { if (is.integer(old_rownames)) { abort(error_as_tibble_needs_rownames()) } add_column(result, !!rownames := old_rownames, .before = 1L) } } #' @export #' @rdname as_tibble as_tibble.list <- function(x, validate = NULL, ..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal")) { .name_repair <- compat_name_repair(.name_repair, validate) lst_to_tibble(x, .rows, .name_repair, col_lengths(x)) } lst_to_tibble <- function(x, .rows, .name_repair, lengths = NULL) { x <- set_repaired_names(x, .name_repair) check_valid_cols(x) x[] <- map(x, strip_dim) recycle_columns(x, .rows, lengths) } compat_name_repair <- function(.name_repair, validate) { if (is.null(validate)) return(.name_repair) name_repair <- if (isTRUE(validate)) "check_unique" else "minimal" if (!has_length(.name_repair, 1)) { signal_soft_deprecated("The `validate` argument to `as_tibble()` is deprecated. Please use `.name_repair` to control column names.") } else if (.name_repair != name_repair) { warn("The `.name_repair` argument to `as_tibble()` takes precedence over the deprecated `validate` argument.") return(.name_repair) } name_repair } # TODO: Still necessary with vctrs (because vctrs_size() already checks this)? check_valid_cols <- function(x) { names_x <- names2(x) is_xd <- which(!map_lgl(x, is_1d_or_2d)) if (has_length(is_xd)) { classes <- map_chr(x[is_xd], function(x) class(x)[[1]]) abort(error_column_must_be_vector(names_x[is_xd], classes)) } posixlt <- which(map_lgl(x, inherits, "POSIXlt")) if (has_length(posixlt)) { abort(error_time_column_must_be_posixct(names_x[posixlt])) } invisible(x) } is_1d_or_2d <- function(x) { # dimension check is for matrices and data.frames (is_vector(x) && !needs_dim(x)) || is.data.frame(x) || is.matrix(x) } recycle_columns <- function(x, .rows, lengths) { if (is.null(lengths)) { lengths <- col_lengths(x) need_recycle <- FALSE } else { need_recycle <- TRUE } nrow <- guess_nrow(lengths, .rows) # Shortcut if all columns have the requested or implied length different_len <- which(lengths != nrow) if (is_empty(different_len)) return(new_tibble(x, nrow = nrow, subclass = NULL)) if (any(lengths[different_len] != 1)) { abort(error_inconsistent_cols(.rows, names(x), lengths, "`.rows` argument")) } if (need_recycle && nrow != 1L) { short <- which(lengths == 1L) if (has_length(short)) { x[short] <- expand_vecs(x[short], nrow) } } new_tibble(x, nrow = nrow, subclass = NULL) } guess_nrow <- function(lengths, .rows) { if (!is.null(.rows)) { return(.rows) } if (is_empty(lengths)) { return(0) } nontrivial_lengths <- lengths[lengths != 1L] if (is_empty(nontrivial_lengths)) { return(1) } max(nontrivial_lengths) } #' @export #' @rdname as_tibble as_tibble.matrix <- function(x, ..., validate = NULL, .name_repair = NULL) { m <- matrixToDataFrame(x) names <- colnames(x) if (is.null(.name_repair)) { if ((is.null(names) || any(bad_names <- duplicated(names) | names == "")) && has_length(x)) { signal_soft_deprecated('`as_tibble.matrix()` requires a matrix with column names or a `.name_repair` argument. Using compatibility `.name_repair`.') compat_names <- paste0("V", seq_along(m)) if (is.null(names)) { names <- compat_names } else { names[bad_names] <- compat_names[bad_names] } .name_repair <- function(x) names } else { .name_repair <- "check_unique" } validate <- NULL } colnames(m) <- names as_tibble(m, ..., validate = validate, .name_repair = .name_repair) } #' @export as_tibble.poly <- function(x, ...) { m <- matrixToDataFrame(unclass(x)) colnames(m) <- colnames(x) as_tibble(m, ...) } #' @export as_tibble.ts <- function(x, ..., .name_repair = "minimal") { df <- as.data.frame(x) if (length(dim(x)) == 2) { colnames(df) <- colnames(x) } as_tibble(df, ..., .name_repair = .name_repair) } #' @export #' @param n Name for count column, default: `"n"`. #' @rdname as_tibble as_tibble.table <- function(x, `_n` = "n", ..., n = `_n`) { if (!missing(`_n`)) { warn("Please pass `n` as a named argument to `as_tibble.table()`.") } df <- as.data.frame(x, stringsAsFactors = FALSE) names(df) <- c(names2(dimnames(x)), n) as_tibble(df, ...) } #' @export #' @rdname as_tibble as_tibble.NULL <- function(x, ...) { as_tibble(list(), ...) } #' @export #' @rdname as_tibble as_tibble.default <- function(x, ...) { value <- x if (is_atomic(value)) { signal_soft_deprecated("Calling `as_tibble()` on a vector is discouraged, because the behavior is likely to change in the future. Use `tibble::enframe(name = NULL)` instead.") } as_tibble(as.data.frame(value, stringsAsFactors = FALSE), ...) } tibble/R/lst.R0000644000176200001440000000506313464363736012664 0ustar liggesusers#' Build a list #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("questioning")} #' #' `lst()` constructs a list, similar to [base::list()], but with some of the #' same features as [tibble()]. `lst()` builds components sequentially. When #' defining a component, you can refer to components created earlier in the #' call. `lst()` also generates missing names automatically. #' #' @section Life cycle: #' The `lst()` function is in the [questioning #' stage](https://www.tidyverse.org/lifecycle/#questioning). It is essentially #' [rlang::list2()], but with a couple features copied from [tibble()]. It's not #' clear that a function for creating lists belongs in the tibble package. #' Consider using [rlang::list2()] instead. #' #' @inheritParams tibble #' @return A named list. #' @export #' @examples #' # the value of n can be used immediately in the definition of x #' lst(n = 5, x = runif(n)) #' #' # missing names are constructed from user's input #' lst(1:3, z = letters[4:6], runif(3)) #' #' a <- 1:3 #' b <- letters[4:6] #' lst(a, b) #' #' # pre-formed quoted expressions can be used with lst() and then #' # unquoted (with !!) or unquoted and spliced (with !!!) #' n1 <- 2 #' n2 <- 3 #' n_stuff <- quote(n1 + n2) #' x_stuff <- quote(seq_len(n)) #' lst(!!!list(n = n_stuff, x = x_stuff)) #' lst(n = !!n_stuff, x = !!x_stuff) #' lst(n = 4, x = !!x_stuff) #' lst(!!!list(n = 2, x = x_stuff)) lst <- function(...) { xs <- quos(..., .named = TRUE) lst_quos(xs)$output } lst_quos <- function(xs, transform = function(x, i) x) { # Evaluate each column in turn col_names <- names2(xs) lengths <- rep_along(xs, 0L) output <- rep_named(rep_along(xs, ""), list(NULL)) for (i in seq_along(xs)) { unique_output <- output[!duplicated(names(output)[seq_len(i)], fromLast = TRUE)] res <- eval_tidy(xs[[i]], unique_output) if (!is_null(res)) { lengths[[i]] <- NROW(res) output[[i]] <- res output <- transform(output, i) } names(output)[[i]] <- col_names[[i]] } list(output = output, lengths = lengths) } expand_lst <- function(x, i) { idx_to_fix <- integer() if (i > 1L) { if (NROW(x[[i]]) == 1L && NROW(x[[1L]]) != 1L) { idx_to_fix <- i idx_boilerplate <- 1L } else if (NROW(x[[i]]) != 1L && NROW(x[[1L]]) == 1L) { idx_to_fix <- seq2(1L, i - 1L) idx_boilerplate <- i } } if (length(idx_to_fix) > 0L) { x[idx_to_fix] <- expand_vecs(x[idx_to_fix], NROW(x[[idx_boilerplate]])) } x } expand_vecs <- function(x, length) { ones <- rep(1L, length) map(x, subset_rows, ones) } tibble/R/wrap.R0000644000176200001440000000063413437532500013015 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) { fansi::strwrap_ctl(x, width = max(width, 0), indent = indent, exdent = indent + 2) } tibble/R/compat-lazyeval.R0000644000176200001440000000424713437532500015160 0ustar liggesusers# nocov start - compat-lazyeval (last updated: rlang 0.3.0) # 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()) } if (is_quosure(lazy)) { return(lazy) } if (is_formula(lazy)) { return(as_quosure(lazy, env)) } out <- switch(typeof(lazy), symbol = , language = new_quosure(lazy, env), character = { if (warn) warn_text_se() parse_quo(lazy[[1]], env) }, logical = , integer = , double = { if (length(lazy) > 1) { warn("Truncating vector to length 1") lazy <- lazy[[1]] } new_quosure(lazy, env) }, list = if (inherits(lazy, "lazy")) { lazy = new_quosure(lazy$expr, lazy$env) } ) if (is_null(out)) { abort(sprintf("Can't convert a %s to a quosure", typeof(lazy))) } else { out } } compat_lazy_dots <- function(dots, env, ..., .named = FALSE) { if (missing(dots)) { dots <- list() } if (inherits(dots, c("lazy", "formula"))) { 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 <- vapply(dots[!named], function(x) expr_text(get_expr(x)), character(1)) names(dots)[!named] <- nms } names(dots) <- names2(dots) dots } compat_as_lazy <- function(quo) { structure(class = "lazy", list( expr = get_expr(quo), env = get_env(quo) )) } compat_as_lazy_dots <- function(...) { structure(class = "lazy_dots", lapply(quos(...), compat_as_lazy)) } # nocov end tibble/R/deprecated.R0000644000176200001440000000335613437532500014150 0ustar liggesusers#' Deprecated functions #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("deprecated")} #' #' Use [tibble()] instead of `data_frame()`. #' #' @export #' @keywords internal #' @name deprecated data_frame <- function(...) { signal_soft_deprecated("`data_frame()` is deprecated, use `tibble()`.") # Unquote-splice to avoid argument matching tibble(!!!quos(...)) } #' @description #' Use [quasiquotation] instead of `tibble_()`, `data_frame_()`, and `lst_()`. #' #' @export #' @keywords internal #' @rdname deprecated tibble_ <- function(xs) { signal_soft_deprecated("`tibble_()` and `data_frame_()` are deprecated, use `tibble()` with quasiquotation.") xs <- compat_lazy_dots(xs, caller_env()) tibble(!!!xs) } #' @export #' @rdname deprecated data_frame_ <- tibble_ #' @export #' @rdname deprecated lst_ <- function(xs) { signal_soft_deprecated("`lst_()` is deprecated, use `lst()` with quasiquotation.") xs <- compat_lazy_dots(xs, caller_env()) lst(!!!xs) } #' @description #' Use [as_tibble()] instead of `as_data_frame()` or `as.tibble()`, but mind the #' new signature and semantics. #' #' @export #' @rdname deprecated as_data_frame <- function(x, ...) { signal_soft_deprecated("`as_data_frame()` is deprecated, use `as_tibble()` (but mind the new semantics).") as_tibble(x, ...) } #' @export #' @rdname deprecated as.tibble <- function(x, ...) { signal_soft_deprecated("`as.tibble()` is deprecated, use `as_tibble()` (but mind the new semantics).") as_tibble(x, ...) } #' @include tribble.R #' @description #' Use [tribble()] instead of `frame_data()`. #' @export #' @rdname deprecated frame_data <- function(...) { signal_soft_deprecated("`frame_data()` is deprecated, use `tribble()`.") tribble(...) } tibble/R/compat-purrr.R0000644000176200001440000000723413437532500014502 0ustar liggesusers# nocov start - compat-purrr (last updated: rlang 0.1.9000) # 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) names(out) <- names(.x) out } 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/view.R0000644000176200001440000000132413464363736013030 0ustar liggesusers#' View an object #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("experimental")} #' #' Calls [utils::View()] on the input and returns it, invisibly. #' The RStudio IDE overrides `utils::View()`, this is picked up #' correctly. #' #' @param x The object to display. #' @param title The title to use for the display, by default #' the deparsed expression is used. #' @param ... Unused, for extensibility. #' #' @export view <- function(x, title = NULL, ...) { if (!interactive()) return(invisible(x)) if (is.null(title)) { title <- expr_deparse(enexpr(x)) } view_fun <- get("View", envir = as.environment("package:utils")) eval_tidy(quo(view_fun(!!x, "title"))) invisible(x) } tibble/R/repair-names.R0000644000176200001440000003021413464363736014441 0ustar liggesusers#' Repair the names of a vector #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} #' #' tibble deals with a few levels of name repair: #' * `minimal` names exist. The `names` attribute is not `NULL`. The name of #' an unnamed element is `""` and never `NA`. Tibbles created by the tibble #' package have names that are, at least, `minimal`. #' * `unique` names are `minimal`, have no duplicates, and can be used where a variable name is expected. #' Empty names, and `...` or `..` followed by a sequence of digits are banned. #' - All columns can be accessed by name via `df[["name"]]` and `` df$`name` `` and ``with(df, `name`)``. #' * `universal` names are `unique` and syntactic (see Details for more). #' - Names work everywhere, without quoting: `df$name` and `with(df, name)` and #' `lm(name1 ~ name2, data = df)` and `dplyr::select(df, name)` all work. #' #' `universal` implies `unique`, `unique` implies `minimal`. These levels are #' nested. #' #' The `.name_repair` argument of [tibble()] and [as_tibble()] refers to these #' levels. Alternatively, the user can pass their own name repair function. It #' should anticipate `minimal` names as input and should, likewise, return names #' that are at least `minimal`. #' #' The existing functions [tidy_names()], [set_tidy_names()], #' and [repair_names()] are soft-deprecated. #' #' @section `minimal` names: #' #' `minimal` names exist. The `names` attribute is not `NULL`. The name of an #' unnamed element is `""` and never `NA`. #' #' Examples: #' ``` #' Original names of a vector with length 3: NULL #' minimal names: "" "" "" #' #' Original names: "x" NA #' minimal names: "x" "" #' ``` #' #' Request `.name_repair = "minimal"` to suppress almost all name munging. This #' is useful when the first row of a data source -- allegedly variable names -- #' actually contains *data* and the resulting tibble is destined for reshaping #' with, e.g., `tidyr::gather()`. #' #' @section `unique` names: #' #' `unique` names are `minimal`, have no duplicates, and can be used (possibly with backticks) #' in contexts where a variable is expected. Empty names, and `...` or `..` followed by a #' sequence of digits are banned #' If a data frame has `unique` names, you can index it by name, and also access the columns #' by name. #' In particular, `df[["name"]]` and `` df$`name` `` and also ``with(df, `name`)`` always work. #' #' There are many ways to make names `unique`. We append a suffix of the form #' `...j` to any name that is `""` or a duplicate, where `j` is the position. #' We also change `..#` and `...` to `...#`. #' #' Example: #' ``` #' Original names: "" "x" "" "y" "x" "..2" "..." #' unique names: "...1" "x...2" "...3" "y" "x...5" "...6" "...7" #' ``` #' #' Pre-existing suffixes of the form `...j` are always stripped, prior to making #' names `unique`, i.e. reconstructing the suffixes. If this interacts poorly #' with your names, you should take control of name repair. #' #' @section `universal` names: #' #' `universal` names are `unique` and syntactic, meaning they: #' * Are never empty (inherited from `unique`). #' * Have no duplicates (inherited from `unique`). #' * Are not `...`. Do not have the form `..i`, where `i` is a number (inherited from `unique`). #' * Consist of letters, numbers, and the dot `.` or underscore `_` #' characters. #' * Start with a letter or start with the dot `.` not followed by a number. #' * Are not a [reserved] word, e.g., `if` or `function` or `TRUE`. #' #' If a data frame has `universal` names, variable names can be used "as is" in #' code. They work well with nonstandard evaluation, e.g., `df$name` works. #' #' Tibble has a different method of making names syntactic than #' [base::make.names()]. In general, tibble prepends one or more dots `.` until #' the name is syntactic. #' #' Examples: #' ``` #' Original names: "" "x" NA "x" #' universal names: "...1" "x...2" "...3" "x...4" #' #' Original names: "(y)" "_z" ".2fa" "FALSE" #' universal names: ".y." "._z" "..2fa" ".FALSE" #' ``` #' #' @seealso #' [rlang::names2()] returns the names of an object, after making them #' `minimal`. #' #' #' The [Names attribute](https://principles.tidyverse.org/names-attribute.html) #' section in the "tidyverse package development principles". #' #' @examples #' \dontrun{ #' ## by default, duplicate names are not allowed #' tibble(x = 1, x = 2) #' } #' ## you can authorize duplicate names #' tibble(x = 1, x = 2, .name_repair = "minimal") #' ## or request that the names be made unique #' tibble(x = 1, x = 2, .name_repair = "unique") #' #' ## by default, non-syntactic names are allowed #' df <- tibble(`a 1` = 1, `a 2` = 2) #' ## because you can still index by name #' df[["a 1"]] #' df$`a 1` #' #' ## syntactic names are easier to work with, though, and you can request them #' df <- tibble(`a 1` = 1, `a 2` = 2, .name_repair = "universal") #' df$a.1 #' #' ## you can specify your own name repair function #' tibble(x = 1, x = 2, .name_repair = make.unique) #' #' fix_names <- function(x) gsub("%", " percent", x) #' tibble(`25%` = 1, `75%` = 2, .name_repair = fix_names) #' #' fix_names <- function(x) gsub("\\s+", "_", x) #' tibble(`year 1` = 1, `year 2` = 2, .name_repair = fix_names) #' #' ## purrr-style anonymous functions and constants #' ## are also supported #' tibble(x = 1, x = 2, .name_repair = ~ make.names(., unique = TRUE)) #' #' tibble(x = 1, x = 2, .name_repair = ~ c("a", "b")) #' #' ## the names attibute will be non-NULL, with "" as the default element #' df <- as_tibble(list(1:3, letters[1:3]), .name_repair = "minimal") #' names(df) #' @name name-repair NULL set_repaired_names <- function(x, .name_repair = c("check_unique", "unique", "universal", "minimal")) { x <- set_minimal_names(x) set_names(x, repaired_names(names(x), .name_repair = .name_repair)) } repaired_names <- function(name, .name_repair = c("check_unique", "unique", "universal", "minimal")) { if (is_formula(.name_repair, lhs = FALSE)) { .name_repair <- as_function(.name_repair) } if (is_function(.name_repair)) { repair_fun <- .name_repair } else { if (!is.character(.name_repair)) { abort(error_name_repair_arg()) } .name_repair <- match.arg(.name_repair) repair_fun <- switch( .name_repair, minimal = , check_unique = NULL, unique = unique_names, universal = universal_names, abort(error_name_repair_arg()) ) } new_name <- if (is_function(repair_fun)) repair_fun(name) else name if (is.character(.name_repair) && .name_repair %in% c("check_unique", "unique", "universal")) { check_unique(new_name) } else { check_minimal(new_name) } new_name } check_names_non_null <- function(name, abort = rlang::abort) { if (is.null(name)) { abort(error_names_must_be_non_null()) } invisible(name) } check_names_non_na <- function(name, abort = rlang::abort) { bad_name <- which(is.na(name)) if (has_length(bad_name)) { abort(error_column_must_be_named(bad_name)) } invisible(name) } check_minimal <- function(name) { check_names_non_null(name) check_names_non_na(name) } check_minimal_names <- function(x) { check_minimal(names(x)) invisible(x) } check_unique <- function(name) { check_minimal(name) bad_name <- which(name == "") if (has_length(bad_name)) { abort(error_column_must_be_named(bad_name)) } dot_dot_name <- grep("^[.][.](?:[.]|[1-9][0-9]*)$", name) if (has_length(dot_dot_name)) { abort(error_column_must_not_be_dot_dot(dot_dot_name)) } dups <- which(duplicated(name)) if (has_length(dups)) { abort(error_column_names_must_be_unique(name[dups])) } invisible(name) } check_unique_names <- function(x) { check_unique(names(x)) invisible(x) } check_syntactic <- function(name) { check_minimal(name) check_unique(name) bad_name <- !is_syntactic(name) if (has_length(bad_name)) { abort(error_column_names_must_be_syntactic(name[bad_name])) } invisible(name) } #' Retired functions for name repair #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("soft-deprecated")} #' #' @description #' `tidy_names()`, `set_tidy_names()`, and `repair_names()` were early efforts #' to facilitate *post hoc* name repair in tibble, given that [tibble()] and #' [as_tibble()] did not do this. #' #' From tibble v2.0.0, the `.name_repair` argument gives direct access to three #' specific levels of name repair: `minimal`, `unique`, and `universal`. We #' recommend that new code use this instead of `tidy_names()`, #' `set_tidy_names()`, or `repair_names()`. After a period of use, the repair #' stategies behind `minimal`, `unique`, and `universal` are likely to be #' exposed in standalone functions and this could affect the behaviour of #' `tidy_names()`. `repair_names()` should be considered deprecated. #' #' ``` #' tibble(..., `.name_repair = "unique"`) #' ## is preferred to #' df <- tibble(...) #' set_tidy_names(df, syntactic = FALSE) #' #' tibble(..., `.name_repair = "universal"`) #' ## is preferred to #' df <- tibble(...) #' set_tidy_names(df, syntactic = TRUE) #' ``` #' #' @param x A vector. #' @param name A `names` attribute, usually a character vector. #' @param syntactic Should names be made syntactically valid? If `FALSE`, uses #' same logic as `.name_repair = "unique"`. If `TRUE`, uses same logic as #' `.name_repair = "universal"`. #' @param quiet Whether to suppress messages about name repair. #' #' @return `x` with repaired names or a repaired version of `name`. #' #' @export #' @rdname name-repair-retired #' @keywords internal tidy_names <- function(name, syntactic = FALSE, quiet = FALSE) { # Local functions to preserve behavior in v1.4.2 is_syntactic <- function(x) { ret <- make.names(x) == x ret[is.na(x)] <- FALSE ret } 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") ) } } name[is.na(name)] <- "" orig_name <- name name <- make_syntactic(name, syntactic) name <- append_pos(name) describe_tidying(orig_name, name, quiet) name } #' @export #' @rdname name-repair-retired set_tidy_names <- function(x, syntactic = FALSE, quiet = FALSE) { x <- set_minimal_names(x) new_names <- tidy_names(names(x), syntactic = syntactic, quiet = quiet) set_names(x, new_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 #' @rdname name-repair-retired repair_names <- function(x, prefix = "V", sep = "") { ## TODO: plot a deprecation strategy once we deal with the fact that ## `dplyr::bind_cols()` calls this function 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(name, prefix = "V", sep = "") { blank <- (name == "") # Ensure existing names are unique name[!blank] <- make.unique(name[!blank], sep = sep) # Replace blank names new_vars <- setdiff(paste(prefix, seq_along(name), sep = sep), name) name[blank] <- new_vars[seq_len(sum(blank))] name } tibble/R/add.R0000644000176200001440000001312013464363736012603 0ustar liggesusers#' Add rows to a data frame #' #' @description #' \Sexpr[results=rd, stage=render]{tibble:::lifecycle("questioning")} #' #' 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()`. #' #' @section Life cycle: #' It is unclear if `add_row()` and its alias `add_cases()` should ensure #' that all columns have length one by wrapping in a list if necessary. #' See and #' for details. #' #' @param .data Data frame to append to. #' @param ... Name-value pairs, passed on to [tibble()]. Values can be defined #' only for columns that already exist in `.data` and unset columns will get an #' `NA` value. These arguments are passed on to [tibble()], and therefore also #' support unquote via `!!` and unquote-splice via `!!!`. However, unlike in #' \pkg{dplyr} verbs, columns in `.data` are not available for the expressions. #' #' @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")) { abort(error_add_rows_to_grouped_df()) } if (!is.data.frame(.data)) { signal_soft_deprecated("`.data` must be a data frame in `add_row()` and `add_case()`.") } df <- tibble(...) attr(df, "row.names") <- .set_row_names(max(1L, nrow(df))) extra_vars <- setdiff(names(df), names(.data)) if (has_length(extra_vars)) { abort(error_inconsistent_new_rows(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. #' These arguments are passed on to [tibble()], and therefore also support #' unquote via `!!` and unquote-splice via `!!!`. However, unlike in #' \pkg{dplyr} verbs, columns in `.data` are not available for the #' expressions. Use [dplyr::mutate()] if you need to add a column based on #' existing data. #' @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) { if (!is.data.frame(.data)) { signal_soft_deprecated("`.data` must be a data frame in `add_column()`.") } df <- tibble(...) if (ncol(df) == 0L) { return(.data) } if (nrow(df) != nrow(.data)) { if (nrow(df) == 1) { df <- df[rep(1L, nrow(.data)), ] } else { abort(error_inconsistent_new_cols(nrow(.data), df)) } } extra_vars <- intersect(names(df), names(.data)) if (length(extra_vars) > 0) { abort(error_duplicate_new_cols(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 { abort(error_both_before_after()) } } } limit_pos_range <- function(pos, len) { max(0L, min(len, pos)) } tibble/R/tbl-df.r0000644000176200001440000000742113464363736013272 0ustar liggesusers#' @importFrom methods setOldClass #' @exportClass tbl_df setOldClass(c("tbl_df", "tbl", "data.frame")) #' `tbl_df` class #' #' @description #' The `tbl_df` class is a subclass of [`data.frame`][base::data.frame()], #' created in order to have different default behaviour. The colloquial term #' "tibble" refers to a data frame that has the `tbl_df` class. Tibble is the #' central data structure for the set of packages known as the #' [tidyverse](https://www.tidyverse.org/packages/), including #' [dplyr](http://dplyr.tidyverse.org/), #' [ggplot2](http://ggplot2.tidyverse.org/), #' [tidyr](http://tidyr.tidyverse.org/), and #' [readr](http://readr.tidyverse.org/). #' #' The general ethos is that tibbles are lazy and surly: they do less and #' complain more than base [`data.frame`s][base::data.frame()]. This forces #' problems to be tackled earlier and more explicitly, typically leading to code #' that is more expressive and robust. #' #' @section Properties of `tbl_df`: #' #' Objects of class `tbl_df` have: #' * A `class` attribute of `c("tbl_df", "tbl", "data.frame")`. #' * A base type of `"list"`, where each element of the list has the same #' [NROW()]. #' * A `names` attribute that is a character vector the same length as the #' underlying list. #' * A `row.names` attribute, included for compatibility with the base #' [`data.frame` class][base::data.frame()]. #' This attribute is only consulted to query the number of rows, #' any row names that might be stored there are ignored #' by most tibble methods. #' #' @section Behavior of `tbl_df`: #' #' How default behaviour of tibbles differs from that of #' [`data.frame`s][base::data.frame()], during creation and access: #' #' * Column data is not coerced. A character vector is not turned into a factor. #' List-columns are expressly anticipated and do not require special tricks. #' Read more in [tibble()]. #' * Recycling only happens for a length 1 input. #' * Column names are not munged, although missing names are auto-populated. #' Empty and duplicated column names are strongly discouraged, but the user #' must indicate how to resolve. Read more in [name-repair]. #' * Row names are not added and are strongly discouraged, in favor of storing #' that info as a column. Read about in [rownames]. #' * `df[, j]` returns a tibble; it does not automatically extract the column #' inside. `df[, j, drop = FALSE]` is the default. Read more in [subsetting]. #' * There is no partial matching when `$` is used to index by name. `df$name` #' for a nonexistent name generates a warning. Read more in [subsetting]. #' * Printing and inspection are a very high priority. The goal is to convey as #' much information as possible, in a concise way, even for large and complex #' tibbles. Read more in [formatting]. #' #' @name tbl_df-class #' @aliases tbl_df tbl_df-class #' @seealso [tibble()], [as_tibble()], [tribble()], [print.tbl()], #' [glimpse()] NULL # Standard data frame methods -------------------------------------------------- #' @export as.data.frame.tbl_df <- function(x, row.names = NULL, optional = FALSE, ...) { class(x) <- "data.frame" x } #' @export `names<-.tbl_df` <- function(x, value) { # workaround for RStudio v1.1, which relies on the ability to set # data.frame names to NULL if (is.null(value) && is_rstudio()) { attr(x, "names") <- NULL return(x) } check_names_non_null(value, signal_soft_deprecated) if (!has_length(value, length(x))) { signal_soft_deprecated(error_names_must_have_length(length(value), length(x)), "error_names_must_have_length") } check_names_non_na(value, signal_soft_deprecated) if (!is_character(value)) { signal_soft_deprecated("Must use a character vector as names.") value <- as.character(value) } attr(x, "names") <- as.character(value) x } tibble/R/zzz.R0000644000176200001440000000057013437532500012700 0ustar liggesusers.onLoad <- function(libname, pkgname) { if (getRversion() == "3.3.0") { safe_match <<- safe_match_3_0 } else { safe_match <<- safe_match_default } } safe_match_3_0 <- function(x, table) { # nocov start match(x, table, incomparables = character()) # nocov end } safe_match_default <- function(x, table) { # nocov start match(x, table) # nocov end } tibble/vignettes/0000755000176200001440000000000013476204717013536 5ustar liggesuserstibble/vignettes/timing.rds0000644000176200001440000002237713464363736015556 0ustar liggesusers} xTEvA! d!!a' tw:+ : ! $N#lda (ˌ;.wd\pQWugԹ*|';_rBnjxӅnJ}{'I>q҆1[Qï1''B{~cFh/~m໇%&V#HUh΍6r#F5Ҏbc<#ٌ4HFa$(F=#7R ld#Ui"jUF2RʌTn$ i 4HFr)HIFmHTlF0R b"#i࢚4HK7R1HF2hQˌ4HS#2R)HuFgFJF4R*m$ >/FuhFp1y+\9w- G_Y1|NfA] '’2q|;$E+’[ O#&Sh&n{LIǚU~I{3g .ċ qyU0Xzq6b+G>0Kbp܇zLXQ"$N n 7b[o pۨLO)0 Nƀ32oިAj]WsF iB'ǑxEy|HYbb&e h^_i*[6_l2R i I- M /AQ3O wp&}//u#:X % دDKԶ }{\6(Ai3q'¿>&t`SK^!isxf%#M3/IZ F̭DSa 0 .Z9npވ`48?`4p'y?,K#z`qho"p_~B0N,_0@1fĘ.(.L5pXbO[ IK ~"I14@$IS2ւ.ΈF|NICN (i)%x 8?q 픣O}%ox/9D8_>B]>L . JtRpLvHpJ9q>qJz"}8CI94V)❸iL: ť9V".A\!|·+sѶ[](Y +p L-O#)y5XX ='LiǣD_ iK9a>I;qD+U?kҟI6O epfR8磝)LSp2"l쉻*ė g 0/Ki.*+vpBZLT%~H9 ܑnH{ H90&I?ˉ߅%^&om2A=j*pR/=E3}o;|̵|ef2:vs~~G|K<-iCZ 鉴1iK ?%2\VϗT@vp2?盁E,ȁ?E}ڬPߕ|eSi40 %an#?Ř _'8$ )ep'-DŽ/itVf?43HIy'nq?L RO*_)s20S#p:~t*bo`Fw(¨#V2 ʀm >k r~p ?K/i4i\['~H_+ҲK2TV(snuأ|`~B^W!3K,V|Fρ<20x0V渆D>f7„3|6: RpEZ!iLJE#}+ \{5i+[v\:8K\X j> +9Eyx%pzc26!e<Np1xIs ZsO?_(>2e5e+ˆIlV [GNZkOzIgit2 ~!MH2Rj^O2TEnB>U |B}恏` ÿ]E/NL UI/y}8]yb`E>H6Lk,G -\?+'+^#I_\pI&5!iO!{Z`r1|D*JP _<? $i4ܕ# `W|€u N( HSu>0JE:$-.H'Mx ,qE:I\!нI9O|.HsU48+Iq6mcG:z=m x"gyx#41h}q#\ZY=E-q%*s98鹤8/OzU3= .4EZ1Y1?feWǓIz?w2egĩ^F=9>ͦoSE ^bu #W#XWdNXשe8b.'qu\YaaX~0pV KƣD=i ^7; eocA8_Yx Ibp!29?cr:xHvѺwb3"=^u=xk17U0X\r2`a*b] 7S<'B`UIlGKViOϭ/tpDz&}@ "wi=_Zo>q*s>F_\^kǁzeε)% ح@ӕN^ ȗy\VLyĔ,GKk53aC y^O%M>i4 X737 < lpnġ I{ tzՠ8`q108䃏te/OpIO^5)Fw,X?7psyyK]t20 VC=? ݑvH7 AC$ف'EÑ┹C|NzpwFeŧ 4HċF?^Ɉ)y_|lZQ_zl`D~2E It?.=msqtg z}T#jV?Vvao{{^7 'P4k-Mmݚ(ζocDorfL{o_S_FNjo(EA~M]^hVNgW掮,R;[Z}'8>qF#qMOvo߷m} 1&_{Wo ;C~-v}txg ~rRK=~f_=_Jmo: aSUck۞7Uӵï/*i?deQ=ٽ_MPk@i[Ş/=bw -F;~Pu~(RL9BьcI~-1CQۻ;~zڕ3}9Q.u SQOO֝=EK~5!ukK'/^Y>ǯ ]WN|3̍5Ff<Yo]d9slmؗW+`./:ۖWݭKOcW|T(]ֿ nu-Vdgb'ۊ: 3gp" Kl?](}>noK9._?N|O:\Ɠmx/[5RVwx|K\ӌ_n񬗹^sPUԋ\9oQ~p==Ƕ˹{UWO>Oqu/;ެ6m!|X=^'=qxdgp{+'p+ݷם. <.<7p˸<9j"{mNٟ|Uuqy_u+o^l e\5)]i rv Mh۹q]ks3NlUqI}WryS:W{ [2*b>k|Ct^L!og[:.ww#_b _/,h|* )ˋ sFs}c |~Փm [-ZE'=\^w\dػz7yspuLa8HyG|T)slI]pϕg<,66ϻ/mZqr]elS/gx䘓!?HI1f[c:ێgĮC엣_\?g{(D{Ji?^}[ޥ%~X)$zuHF n'Alh5WWN9]{"SniP3źנir]m5?G/:uOoRl*)^SqK;٦ybϛ?Ǽ r퇤 wzonRI6o=}PiOG^o>o;rs"zHFI;re.+\>_ oq؏e@HNї=-!Dʸa[?N7SCnrG7{é߳[b˸dNmk >{ۙr}&)'J?7Kg;ŏmJE$_ŸO_szGY6Yѕc}بئkmvӕ?(#Cm8~A?{9k4x~)~@l&1$_.k?8 /m~wO?'q1FƯn9~Uw52o'#@M:]5/0;-R~2:?dž_u{Egc2;ΉKk|<Ҷs5ϗv|rϔo%i\ѕnѝ<.-0wiWXHtzbywqR`̄$w2_]x2:CV}eK]d>j) ɗ 6Oxo +%?#p~ yy#gDxn-㥣'R%?[zEؿ_b|4i/8iKn8~/ԻV-o<"y[Kd.dVeyQIBqkvϐ8 ~ze2^8ƉnO~rgJ+}O`)y۽2mX+sK}} uR_#Ǣ_2oϨ|z3 u b&wگ=1Ϥ~{OlW]&xM=ڶ7'~ج1^O%OO2/CGKdr/ۜke}'*Yoȹ{@boΜ;br֋G|*e>)9f?Wp9&VxZbcv?$S+'KN |Wa?c0~K>ng}z9e|C2n.ʎX3`x#,v)Rq'K9Ʒ]«7bS?$ϖcf!Ϝ̇&R?0yoryr s'TO⨯Mѫq>ca? 2?quGdbϐyx.ށt`^<یz_xk{3 XI<&wm+Vuv~u=(Jr)-lyo'팕yfy>e3u<AqR/Z~jmHӷrPgݯdV}T^ʖd'K?J`O߻wU $i^wuǸt|]ɭP%z{Ƶ{ϗ?wmMPޱϗ UL w^O7sC&/ؖ| vT|Y"U7;eWKY >%õ>J=G^RK/AϤ_7 ׯ^+?Gds\Q>/U]lWw^#zzAPxB&5UUל=U&?"ק&sd nY-g^y.^)VUÿnFg5xua YovoAvyqgd7;g͟Fr.q5Aq.y7~,85qyVy=啛fry_--Ij#݆orMY,/FKW-aUP[W]!A&4EnoiA>_z<4Kλ !QyJOo^_Y9UƳ<~đ1[y~v=AgŅ\^LFۺgO<*FtU\9E"GYy,r<|nV۹^oNt~yI+;g^.jn&_Rq ?_v1+aے!_8_]$zߏ<r;mny-߁Y4:&s-'gZw?M{q5 P.!;[6~7͒łGuGmO5rikWs!j˓T}W߃usr?'mڼ?=wҸ^?q WBvϞ~˗"y|6{AO`ūi~/j-7p-ku|?~~Ifc˭1?yX8a]::::rXsW/G7S-}e׶2hUM#m }f׼ǏS %\VignetteIndexEntry{Tibbles} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r, echo = FALSE, message = FALSE, error = TRUE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") library(tibble) set.seed(1014) options(crayon.enabled = TRUE) options(pillar.bold = TRUE) knitr::opts_chunk$set(collapse = TRUE, comment = pillar::style_subtle("#>")) colourise_chunk <- function(type) { function(x, options) { # lines <- strsplit(x, "\\n")[[1]] lines <- x if (type != "output") { lines <- crayon::red(lines) } paste0( '
',
      paste0(
        sgr_to_html(htmltools::htmlEscape(lines)),
        collapse = "\n"
      ),
      "
" ) } } knitr::knit_hooks$set( output = colourise_chunk("output"), message = colourise_chunk("message"), warning = colourise_chunk("warning"), error = colourise_chunk("error") ) # Fallback if fansi is missing sgr_to_html <- identity sgr_to_html <- fansi::sgr_to_html ``` 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 error = TRUE, eval = FALSE} l <- replicate(26, sample(100), simplify = FALSE) names(l) <- letters timing <- bench::mark( as_tibble(l), as.data.frame(l), check = FALSE ) timing ``` ```{r echo = FALSE} readRDS("timing.rds") ``` 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, and uses font styles and color for highlighting: ```{r} tibble(x = -5: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 ``` As of version 1.4.1, tibbles no longer ignore the `drop` argument: ```{r} data.frame(a = 1:3)[, "a", drop = TRUE] 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.Rmd0000644000176200001440000003266213464363736016204 0ustar liggesusers--- title: "Extending tibble" author: "Kirill Müller, Hadley Wickham" 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} time <- as.POSIXlt("2018-12-20 23:29:51", tz = "CET") x <- as.POSIXlt(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.md0000644000176200001440000000717113416210055012775 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](https://www.r-pkg.org/badges/version/tibble)](https://cran.r-project.org/package=tibble) [![Life cycle](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://www.tidyverse.org/lifecycle/) ## 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 chapter](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.1 3.5 1.4 0.2 setosa #> 2 4.9 3 1.4 0.2 setosa #> 3 4.7 3.2 1.3 0.2 setosa #> 4 4.6 3.1 1.5 0.2 setosa #> 5 5 3.6 1.4 0.2 setosa #> 6 5.4 3.9 1.7 0.4 setosa #> 7 4.6 3.4 1.4 0.3 setosa #> 8 5 3.4 1.5 0.2 setosa #> 9 4.4 2.9 1.4 0.2 setosa #> 10 4.9 3.1 1.5 0.1 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 2 #> 2 2 1 5 #> 3 3 1 10 #> 4 4 1 17 #> 5 5 1 26 ``` `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 3.6 #> 2 b 1 8.5 ``` tibble/MD50000644000176200001440000002145313476213663012043 0ustar liggesusers5ad314ffccf6a70b85922bb4dd539a30 *DESCRIPTION 4ac396cdf32c44b3d07b7d6c9fd388d0 *LICENSE 1143361e47602d724bb722696a502530 *NAMESPACE 59c4bf6b1ad71558ffdf04adb8740483 *NEWS.md 9268baf03874a8501ccad6d15e147e64 *R/add.R 139376fe38436fe5398e58f760624dcc *R/as_tibble.R dcb10c6d93dad98f2307b52d9bb23130 *R/check-names.R fe2b083cb49e6a80aedf7695b7b0ba07 *R/compat-lazyeval.R 3b06ee41c6c8619e98933c040bf2236a *R/compat-lifecycle.R 82227b63ea9fb4d720aeec213d42e9cc *R/compat-name-repair.R feaa904f11d6970ddbc1057a30cf6610 *R/compat-purrr.R 66aa312ca3560dbbcb4baa049d2911f8 *R/deprecated.R ebf7e16ece355305528df1fb36f46e45 *R/enframe.R c3664e961a84ee80efec74d9a8f262d4 *R/exports.R a5a1d8d22f4573acc65b45dab50edf11 *R/glimpse.R f20e02292e4da20b9cbf33f0e66aa00d *R/has-name.R 3f6c36a18534a46f68261409fea3a78b *R/lst.R 41c5461cac7db8d77ddbed93eaf51e3c *R/msg-format.R 32233347185ea2e21115f3fd085bca14 *R/msg.R 0f98c887bfd15eb0c4ba0f2c08ab142a *R/new.R 6929f632e9472062ca805d057536f8c9 *R/repair-names.R 2f06b7cf803159dcadd050a4f4418cb4 *R/rownames.R 6f8287098a5b24195016e34b4ef5dae3 *R/strrep.R 5907ddabae3db0ded3af531d42ef12a7 *R/subsetting.R 22232dadaf485afbe71f575ac77da328 *R/tbl-df.r 8787935940974f3730114f08e2d1b27c *R/tibble-package.R 7cf7d246cb792693c748106497b48412 *R/tibble.R 4ce22fdd06343b0b85df542ea7480668 *R/tribble.R 8ec423d71036968d8ca04c3c733dcb6e *R/type-sum.r 8fc9568d28e5a23aea5429b61c21336d *R/utils-format.r b9a720234e0f057cc26e56f99cb1b33b *R/utils.r 47ce1d58c4ceeb2951db1bb356decbfa *R/view.R a7d2e7cc5182b83750c11175747d6a31 *R/wrap.R 90dfff18a062646cd6b4354fade7fa71 *R/zzz.R fa3710b7a73bd48e44831db69108431a *README.md 43b0bc7c17bd6f29b88a82574049f557 *build/tibble.pdf e1c4d24b4d6ba763415aefd44b5f7a4e *build/vignette.rds 5921387468f281e14f824b50ae7a23d8 *inst/doc/extending.R ff797036222f7e131519364c6ee04c5b *inst/doc/extending.Rmd 924e17248d4abc31b27210c1d3bb4ad3 *inst/doc/extending.html 4bc8633ca26749dcd5901440c21a30dd *inst/doc/tibble.R 3c4a4bf9e7fa62ca1397943b9daa91d3 *inst/doc/tibble.Rmd a73e4289c8bf117dbe1a7a7a9d38ec9c *inst/doc/tibble.html b9e1a157cf9178d66a34270ee1c008f4 *man/add_column.Rd b846dc00b6993a1f379774471c2409c0 *man/add_row.Rd 278af7ade4748d46be721236de4305f0 *man/as_tibble.Rd 8b502f9c99c3003d895cbdf34524c3b2 *man/deprecated.Rd 4598fb479f745b00a12370aef53a83fe *man/enframe.Rd cb1e46f469cfbbbde29c8b5113e1d789 *man/figures/lifecycle-archived.svg c0d2e5a54f1fa4ff02bf9533079dd1f7 *man/figures/lifecycle-defunct.svg a1b8c987c676c16af790f563f96cbb1f *man/figures/lifecycle-deprecated.svg c3978703d8f40f2679795335715e98f4 *man/figures/lifecycle-experimental.svg 952b59dc07b171b97d5d982924244f61 *man/figures/lifecycle-maturing.svg 27b879bf3677ea76e3991d56ab324081 *man/figures/lifecycle-questioning.svg 6902bbfaf963fbc4ed98b86bda80caa2 *man/figures/lifecycle-soft-deprecated.svg 53b3f893324260b737b3c46ed2a0e643 *man/figures/lifecycle-stable.svg 2db3b0e7250ce7abb3301a26a21c743c *man/figures/logo.png ae7941f848d203b3b65abe68a7fc718a *man/formatting.Rd c5d31e6a4d9a5b464e96712856a6c0c0 *man/frame_matrix.Rd 029701925a062a8115400f2107357413 *man/glimpse.Rd 0c9be5c64b9706c4006d8a2f419fa747 *man/is.tibble.Rd dd0f0ffd6dd4338689b3cf050eca9b8e *man/is_tibble.Rd 998d02902cd2a2d13d7d1b77b32255ea *man/knit_print.trunc_mat.Rd f02a9775a79da0120627b17658d0ae29 *man/lst.Rd 1ca68b5e82673ca042901883230bc0e3 *man/name-repair-retired.Rd 9b56b6634fba35c31265572525cb65d1 *man/name-repair.Rd b450623602374ec48e9a50c92820b037 *man/new_tibble.Rd ba48a35a30bdd72ceaf1ace959f8eb59 *man/print.tbl_df.Rd 79dc669820e2eb220df1de37396145ed *man/reexports.Rd edbd75130e346c19ae00e283d4d5a342 *man/rownames.Rd 84387e892ffb5abff414965ac814b323 *man/subsetting.Rd 3c1f076a16e2e198e61fc2dc9b5e3f1c *man/tbl_df-class.Rd cc3d4eabeed41d79795a5c059c1f1a3d *man/tbl_sum.Rd 0274315e63319f81c8a26a31495f4075 *man/tibble-package.Rd a85812b7dcc1f2f8686c8367dec3f8e5 *man/tibble.Rd 52db84333852e8b8dda8ae66f3e1b76c *man/tribble.Rd cf3d90ef5174c88c7a01407c6a90ec07 *man/view.Rd 2c4dff11f4ec8cacde5e106a6a82a75d *src/Makevars.win ab636b77551c5a14042179ef87c5486c *src/coerce.c 36c03da56d146ea2acdd05f8130b3376 *src/init.c a83cfe76a64d09c190ac1c0252f8cdcc *src/matrixToDataFrame.c 16ee53d7a39a3dce0ee4ca810132bb1e *src/tibble.h 934bcde5b57357bf4ec7ac5793041f17 *tests/testthat.R f50afaac32df0dca717ce92cd197f791 *tests/testthat/helper-api.R 7842e41ea1b0ee61b0e26f1cca696794 *tests/testthat/helper-data.R a688a6b28982910ef441179f15bcaad3 *tests/testthat/helper-encoding.R dc6ef34d2d434a46979721777a4395a6 *tests/testthat/helper-error.R 52a9152b168121b3f417441ac59f261d *tests/testthat/helper-output.R bef7ba900e98d5198b18e8195800b286 *tests/testthat/helper-type-sum.R 2c7f8255e425a1c9f0bd768438e75e14 *tests/testthat/helper-unknown-rows.R c72ceac37b3a6f8ce601e7c692c0b757 *tests/testthat/output/glimpse/5.txt 1807684276e21424d40a3ecf0947f2b3 *tests/testthat/output/glimpse/all-35.txt 57e93def0ae6bf2d8d4c9e1aaacca2e4 *tests/testthat/output/glimpse/all-50.txt 610dc4f2e09953335324559dd9eb17ca *tests/testthat/output/glimpse/all-70.txt 6627e7526f2de680d1346b80722bc52e *tests/testthat/output/glimpse/iris-70-na-nrow.txt ea747fa082b6f816f6f12236e405f18f *tests/testthat/output/glimpse/iris-70.txt 28482bfe0fe8133ecbfd2f429ac7895c *tests/testthat/output/glimpse/iris-empty-70.txt 6398725d210aef366df3da6d98b0bbeb *tests/testthat/output/glimpse/iris-nested-df-70.txt 582025040c8ab554f8d502bc631b75d3 *tests/testthat/output/glimpse/iris-nested-tbl-70.txt 8ce8a71fc1cc636d140c85264e7cf08f *tests/testthat/output/glimpse/mtcars-70.txt 7abb3cfcde3d7fa037ea8bbbcc142272 *tests/testthat/output/glimpse/non-syntactic.txt c11caac141889d6ad0902749aa4ac403 *tests/testthat/output/trunc_mat/POSIXlt-8-60.txt f117a40efd5eac11a6989f0f2563cab6 *tests/testthat/output/trunc_mat/all--30.txt 896d242bb8a12144917f2421cbd76f3d *tests/testthat/output/trunc_mat/all--300.txt ef2aeb149a398f64377aca226381ac70 *tests/testthat/output/trunc_mat/all-1-30-0.txt 7184a2b9f52392df1a51b97d237ca716 *tests/testthat/output/trunc_mat/all-1-30-2.txt 4af95854db8f3c1216709b7487831716 *tests/testthat/output/trunc_mat/iris--70.txt c8daeea3e90104c003b15180922103e6 *tests/testthat/output/trunc_mat/iris-3-5.txt f3d4c3b0555eb4b0b6b214fcb189c833 *tests/testthat/output/trunc_mat/iris-5-30.txt f8605160dbccffd78299577feb010ca1 *tests/testthat/output/trunc_mat/iris-inf-30.txt aebbb33c60952fd3843a57c79332934d *tests/testthat/output/trunc_mat/iris-neg-30.txt 9ff56a386dff1ee1804ac8d03f66e382 *tests/testthat/output/trunc_mat/iris_10_unk-10-70.txt 8d8d84634830c2a14be40ba8f886f93f *tests/testthat/output/trunc_mat/iris_11_unk-10-70.txt 9ff56a386dff1ee1804ac8d03f66e382 *tests/testthat/output/trunc_mat/iris_9_unk-10-70.txt 8d8d84634830c2a14be40ba8f886f93f *tests/testthat/output/trunc_mat/iris_unk-10-70.txt e273dadaa4d8b14bb9caaf6b40f8edc6 *tests/testthat/output/trunc_mat/long-5-30.txt 86ba469ffe798700967599fe4d192ea0 *tests/testthat/output/trunc_mat/long_unk-5-30.txt b05a03af26a33c062be6eceb8a87713c *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 fe211bb3806e827ff4a7a42f10dee1a9 *tests/testthat/output/trunc_mat/zero-cols_unk-5-30.txt 6321a183d34408746ac8e84f2196acce *tests/testthat/output/trunc_mat/zero-rows_unk-5-30.txt b4557fe57c9221fe381939fc6cfb570d *tests/testthat/output/trunc_mat/zero_cols-5-30.txt f929ae01b6c332dea1505ba4d812ab64 *tests/testthat/output/trunc_mat/zero_rows--30.txt 5578aeacb88ef9a148d2ec64261ab663 *tests/testthat/test-add.R b64d7489e85d99b01d89c709b11e9eb9 *tests/testthat/test-data-frame.R 4d2ab552c3b32fe66d307bc3e0ed0cea *tests/testthat/test-enframe.R dd03a294d66621f19a36264d2884e2d2 *tests/testthat/test-glimpse.R 65296c0e4c36d4d8e94c3516086b5ed1 *tests/testthat/test-has-name.R d3461033057a5f00a8a1ef58ef7f0302 *tests/testthat/test-lst.R f2a0aabb7c7a099bb1c29cc419739090 *tests/testthat/test-matrix.R 559509ecd5865d09f2c78e0833d264bd *tests/testthat/test-msg-format.R ce685d5eb34af2f6f2a919573e31d08c *tests/testthat/test-msg.R bb2c8287e6cbb407bf13a66fe8db499f *tests/testthat/test-name-repair.R 87f79e124fbd93c6237af46f34551958 *tests/testthat/test-options.R 4cbf98f461359d8e6849e2ce533d7273 *tests/testthat/test-rownames.R 05e02b762e4ae5f71f13ee64d4cd5845 *tests/testthat/test-string-to-indices.R fda06166b034b297d550d070432b22cf *tests/testthat/test-syntactic-names.R a9181406981bc897639a20e81645d5a2 *tests/testthat/test-tbl-df.R be9d5b4ce2b894b94330f0ecc6849b60 *tests/testthat/test-tidy_names.R a808c69fc0d0c1da6d1aa9f4d97661b0 *tests/testthat/test-tribble.R 1f18d8b75a38358ab615522921c71972 *tests/testthat/test-trunc-mat.R 24859ead9ba31215eddee63a7eb656b6 *tests/testthat/test-type_sum.R ff797036222f7e131519364c6ee04c5b *vignettes/extending.Rmd 3c4a4bf9e7fa62ca1397943b9daa91d3 *vignettes/tibble.Rmd cede6b401be0ff6a8aeec2b16d3dfd5c *vignettes/timing.rds tibble/build/0000755000176200001440000000000013476204717012625 5ustar liggesuserstibble/build/vignette.rds0000644000176200001440000000033213476204717015162 0ustar liggesusersuM0G . 8qc E6@t$n󾼙y8 &T -@:2c=<giSAv#լ/rI]^;#V>q?\&%)z̦? (X}BF;w[ՠjCu}}߭]sҨD :$0@5(tibble/build/tibble.pdf0000644000176200001440000044733613476204715014600 0ustar liggesusers%PDF-1.5 % 88 0 obj << /Length 916 /Filter /FlateDecode >> stream xڕVˎ6WhW|Y YL)&GMS$DKE'qH)G#+_ ̂_7߻fuO!Er!?V+8 Xz& g!V Ϩ(VgL-Hr5h0'|ӇhCME{}\W\=״vgM*m "Wohq"3b(_輔CáfE jj9nVy|4qjˍ2d㍆"vraEi)Uf%u3\E܏L2# X^=eYF[qEeli}v-oR݁)s1aJv4#uԩ@>{z~O=;gÓOp2#Mهכ!)X+TfZwihp<4=Y4Yk$yrΎ,$[ЁD U}fi endstream endobj 114 0 obj << /Length 726 /Filter /FlateDecode >> stream xXˎ0+X]?yt٪3RUDɠlgڄ4d&bх Ct:((_|[-Q0HFR10i*% ~~cdAi<:0JUGˢkQ|ι4c(0MxHl7UiqP#h|/Z0ÔJuTbEaȟ>6uiPew|rTnEb|o'THf 9_:t@k@K!Z)r#M14CSk'8Ueݪ=egU)=lYgӸFSğtYkt@*-MF nbal*Pl)@nBPu:Rg㐗rTd_e6Ax:sZ/,ϸkbc} ^ykde?x#105k_)#䋮`ij-`Hyz}_S֭yMi7աێ"g/w8|oS?MseLedSD1|.BrsYOJ<1r.FY 'tDz~3|'>')/0G3> )*x+Uj >Kcsp;d͉$=6͢ oO3J8:mFR'Z[WR6U=}BXX-"F endstream endobj 157 0 obj << /Length 1615 /Filter /FlateDecode >> stream xX[o6~ϯR ^t tPlK!) ZR,-rS^$[8 <$);7;s;\ỷQqƈy;s5i٬̦ Onc.( (Zr!ΔLi[:+4 wcyxqm?F#мWӈ [k-ؙH0`֝Ɣ>`,rG3? Vd.'w g0'('Pb6 Ӕ(#!3<=z .ppoG_^O`'Y]}N ?8GΝ^p/ۢkWh@!-(Ɛ8D v@9" g.τU9Zq3L견. + ׳#I C.؞L yAuad,cE|<BcX@"Ł%\ff13mn'f#@ Pv+Gi("=#8$Օ̬,UY2?$Vd+ig['nEe>A9 WfvFhB}% hO*(C.Sl<)dH RJifHDLڥ`>tYkf0a#]۪Pe>rޮBYm_My׺ʂ%0fҦ\]1{m)>Jĕ DYiM 2mﻬDW?H2y2ܫ 2fAV 'v (g3Yˍ (;wvbG4SI޶<9>6B?6`cݽh+b-yJ>I[VD8| uuY)(>cfu7s{A!}9 F,ۼ Ay/;?0#:qo4BYYey`#v(IZ eSCڶ'$y eoݽ}r=m#Gy4WWl}QR/F5bC?l-IJe*dy Z>JB>迧Bz%=KYpl!ny筟)^E⇬7bū0QNM2Lm4\ }$7<74:c'b endstream endobj 185 0 obj << /Length 1418 /Filter /FlateDecode >> stream xڭWݏ8߿"K%ڱU=p`y8:FI-{=N6nKJIlfBG?~HwK#1ϼ٧O8$"M9?w>{E> 0モrVqO8J&དྷBUYV 8\iW>a" kђopJD岒+*Iv3Ċ,WOUK^KjvQ7ODoi;rR(|;<qJ҄}R^*GW_dҐ$4ՇO+`%(³;;O@'ԫwWxN+Q1Jb(H&(8WCE^Ûօ]c]KwZ3y(.HB>jՖlmi|0 hd]ڦaK5Eu״!_ָJ-kޜ\K\Ƅ1'ߜS3x%=Κ4Ddf*2PK6pyիa;_w=~Sϛ~Wt)6FV0͈$6`lSh.w䈫F`:λ\ >PYU0y*p0TJCHjPΒ(8#H=>5yFh  :f*+|TosXPږԁRc (@0EYT2_m5Ѣqw~+H4ĵYJ֛n$ =C6c6yklD @[’ p Z\5 lekӍP~/}37eeL,KGl); $UuʕH0,Ht'\A2!&ii9"̼V:8(1T5:&N)ޥ{n3ÈDI6J&(ű/qZ=c) oMkuӡtU,D: ;:R.x$j\!=!q9 @6O_u 0@b7_;sy%ho71ԃ936xlÃ_)37#wJgbʒxdp7ƀQ85^5|u&3vlujV!X:`vlZ5Un2 !0/#NNjЖYXFhB/[^7]cN3"V Nt?/Q endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 797 /Length 2118 /Filter /FlateDecode >> stream xZo8~_: twѻw"{̓;ʦiqmuջ25}|CQ^qTAVYSdIS1Êş!)kR@#kɍt9\9ńXGCR7'ŀ^ɠ|y}Bʳ 1ᾊ餢MS1Q*fWɉJJ1hTJv*rċBg*/}R91X78MÄ`T^+Œ)bb(e &2f-a'YYƈ)t.`UA "A9]1UQA d쟌@2lAd,x>L&PǰiD ~xwrYyBYpNx F.(xĽƑ@0F"@Wa.Q!'I9pNj/ɏ , n1EH%%<D.y DP2Q \UoU廥~V/.n]]ͧb2^}?ǷSMgF/^ٳǓxnY?`dz 3GfJ֬/.n]<,{M3[nķ3GVn ŷV~zٳo?_5a\YІ@= r=ud*> N͒ҫ[3W4W䦼|ꞆprWz[d=ͦϥf6k73(F]QTU`wfhV(-"8.C}=]Ihg5?.?ڔs9+U+jXB{6Chѓ£e=֭^sYzStQzڂuCL"᪁ꟳşի իf\To_/ߋMs*jfOMkle}[il- <栅oo|]a,OGQ$EMAMЌœ4(jZ=`CooA;JG3|~yD 通yk y*; *ia%/.M?6}x?9iq=Az222r}CcS>2=ąjpQci I8 ZiL`S8ȽRi^ȇkذdnDr<wcڴ? 4e[m\wHiu6\9!4K"Qg# 3<kwNz0({mN4!Yikʤc7_ϻaIXR'TQymOD˴Dk}0| H A[ Hoc! ʙ\3GOax m aTO(˙3YYipXI%al`mbB9 {=27 Q,ϟ Adz NQw@]'sީJ9A^} }GC9 %@NP*Ah"2XdJ RϗZ_Jd|k@esNڡL'I=v B XWAb -5K=4luD.G,g3Ҁ|fymbbq9r|'@٢*= ?]D D-* 5r[H3/,Fkܕܑ{8zlcgRyXizwl`Al[z?y7Ny}IcAcAcASASAthdOҠ @y endstream endobj 205 0 obj << /Length 1566 /Filter /FlateDecode >> stream xڝXێ6}W(Ce I-Ї-ri A@lѶPҺwȡn^ #/uu,~Z/V$$ yw"t"H':s>iUWK׾4$QB9[jXP轞f#xK/jQئ% Ж%pvADw{W-F\ F>mT>(Isk׻UNu|UޕҀf_\~ąu9# ^`;x^|]08Ig)h ;ۻ/#\N$vNf# Q)}b.W> %흥f9΋dl j>R)MYFO4$cG NofKmRYC^fhe0cνW]q> stream xڭr6इH3&BM{He9t"! R-9R\+9s~x}'&qrP#RعLO`o|>CA 2ll^y>=B,vj&Ǿ/0DZ\ECD Wx\u]ݚ?d ]XXӵA5_ܕ';%0?}p%1jLeCZ"OIzZ:$4@SITnVVj0ړRY!|vԺg|ź. nTVusqD kPvU֔&ƅ7.&(@s͕IćسZ˄ gSY]jTETYV*]cRP/$"Oª$-}өj%.x^^ QF֙\aˍE4Y/ި<'ǪxN Z`~fUf}bz_YBuW.Oi}:^5,%7գ^_ξ(`zZ"o$gIGέZ8>tGs·G?l"(TSXxs &#qD{Rzyg›Yb@m%_2F&Me+ Tea{A8&>~uL0=BMWIlfUyUfA34mWca$H싁;` "¢rkᗂ6w`exR Fa%;Z H4ōu #_ ;)YQj*7ywA%]+;8Ha4mAZf@I.~J9?>eƈѮk*GcD0Qt~{7Te[˦yl',AFѣYndkd[-7<2[s]L}hf йi`b~iR]Q6@@SI`}`h |1zNHZ.eC0SS/?Es=3O`,yD1:C׺+8r|7T l+0ɮ{jUj`d]N͡o *&al+c^i>wzFd!%4n.R`)BU \.S0'DŘphP:5 r0ݶ=>zbHT#A,$4bjQWXnˡN4򒱭ʏ8^ k=Ϯc%@ȥmSYSnn!RNt+^P(4\8|U VE opяKs+_yfcf(QX`"><}'}n8(PυO8ti)P9x3UiwLo6.=(S `aكu%!kKbg튋fńk0ۙ?gx,,ܨqw|BHʰO߽8^j'zr'AbϒJ\weStjlpAFՍ̇"+hˋ}:)նLe}6% 2.=Z5C|% L endstream endobj 249 0 obj << /Length 1719 /Filter /FlateDecode >> stream xXYoF~Jry ȃ-4))\\Ɍy<wfgIM)IEpo1͌O߯/^Xb31z;\Ι#:mo6\印:X\vꨋG. e/M}big*<"zDIP$6r.oGGzR-{(-T0|q1k 3߶`i$1Ho~Z3?#@-XrE_w2Z^j ǯ(]I,NXpl(~6ޭV;Y {Vg D2OYj`> "iӱ |f: ܔU?02!i=oQؖ-L }+O 2޷"2Ve~ٱk󔂷EM [32\?uzX{>3!] lrI5{5֔NYbm&}],1թ̪7 Ȉ{`MHuS!HFT/$;ƯN6 +bQyDD2( mdsD9-c%ӲɉN(`EpMCyZo=D<q Ӟ?Q$FRU=lwhIO̳:(=pǖ֊UT|c^r['g$}В N3ZԳ5uYJPO3Eq1 \mf[f!l =Վ,rAZM0 `YNi1fb1OjKeM~І+ /Sܞ?MP6#ByǶd>/GdP={˜Uօ옽I=Fb+˵7e=<&TMbHQuܻ\uԈQsARK,MGEJ2fa|CiC$'dzCC7Ahx ?QkC#m|k28^l#u-$Pa2jT>eUb #[5,{P3: C d2O9&ƍd;v5{.3vn5d3/5Md^ ,_VOO(+z-4XB`:ju5x_vtX4ru+Lf&?wۡHlZ0E'4sh1!~x7@m`z[4ڇT$ NJziRWHhMDYՁR좎rK2!3giPT6A/:Di@=bm'm./=˪i?2Fq}7iZҴvhB3ʼnb6zMPa ,R!q Euê.@EU7_h[p &Һ0R )+( y0Wɗ8S F8 Qo8lγuc9AFz$Y7+8YKn G׎>O ns궩[Et&N꩹%z.c4C ` {OvoJ=K QbbGne66iq)oL endstream endobj 261 0 obj << /Length 1278 /Filter /FlateDecode >> stream xڭVmo6_af+RC 2Zl"zq&wGRۙ[ Ayv~e}g IB.pQJB/Esۻ+ߛ(zQ@03Jwl Ƨg"XzIץwQR-+PMmeB&r K.dgWg+ Quœ~kD 1Fz+FAB`MHnD+3s}iY}!S9:Lj_ӝh͎J}+9lZ u61/R3+,i%L'4+WNl;xFa )1b,i-v"Eq 00-d?ժݝpwټZ yky# <|HO7|JS7|lFMGhyzϷe,?-bXI]]]_GWCHƂ}ׯ6 {Y'lNl hI%nkHD7VbH1R!I#7GA{w/a~|6<5NTGN4M fpcySwYc4 z^|e#noDAonD]aK뿕#;Ynނe)O,4NZ5l'= *s;/O8 v8cժ=!vc3:#/?`rFRV_{;V0|w?9³N8@v\_ IC endstream endobj 270 0 obj << /Length 1253 /Filter /FlateDecode >> stream xڥWKo7W>Is.zp۸hh䰖(kiѮlg!W0lΐC7ghF #~Y(I2"& QbpNcM9{Ftb2c댃o Lqn0,%On(;S1#n Gwz;=g4Tgztv)D "1F8Oi>ٽ$MɟL֪8J֩Of}V G YTv6.!#b>w95׮lW|)=[B$1E_CL*d?qf6)U[Mev{ av6nviE%FGPtgԓQt`HLʕ/[G|HrVq>mޠTC"`jyr0?`8Jpr!(к7(J&mX>~|K]q]gǦT봟P̷n u秉q誰oa VyYV :jԏEAcbTv&G(޷^[ӾuvCq`fɽŕ ר];zcpT;;yg endstream endobj 279 0 obj << /Length 2041 /Filter /FlateDecode >> stream xXm6Bh?T,IQܡ/h4mmk]d'!z w[8'x8ht軫\}m"Ϣ}(%"ɒ"EobFW"P&YAGoڣ2o-/|ss+KD#60dF2ZD՛i"*H%G*z}o: T.(KG쯜J?e)MTsk%$xVh$`_nۖ'S6L~XY@ʜ[»Se)R5콎pTe@yFD3n#$EOTٗBw栅HI J s7fޚ$nC/^4_mi|\;<6Xw-/;p5`<ΧS6xyǣj2QNDfHz}V[ :~аB-yTKG]^ZU=ɼTpkO~+kvӈΕW/m΃_U\rru8|L1e#Ð vjEWtQq);2d݂ e眰byo#'I% =?Wޮ#Ȯgs:&Zh07 @<J(-'>/0RVm6~/~WC]/B@(4}VCᩦJS;wG4CXP@.[QZ p}`s+c/e}oD}=jfllXձLp%y& B%E1eы[DnѪS8￷l ƥ(s |;;Gd.Wߣ<"M@RL|cbBa*)au$_< @Qٕ}h`SsRLtzxRF6lp= 孆{dcQl @x=I0BZ !,Ĉ2#Vp,{WqݗzՀ'|#a&_@sazgkxM0$a&ЩBX$I3> stream xZMo9W\dUH ;,8Y`wg|-%1V }&~^:%Vm,l|,+vb.hc.$4B."W*ڢrE]-F:! [b޶LKdZ_G͏d5e'<`GbzvFޠ`O0k0OZ!fsƜ/77/żygz}:k7+m7O.WSf?0ŸcPAD QbJVB;(fLWv vǑ3r9&/d.fPd}]5Y]{vn;` d2?SK8J3CKjm)8&wO˳zA"o"_,f_-(d/d/63\wKPk9.#ef6'ChD |Ef80'( K >QOPd/a9o0Y_bnt[$!ް#W,dvɘuܼ^.LaAykN?Fz~:j~|HjY^OW-)h6܌\|t*B{=^]W7[3_aQ4(Ͷ4Bmcn7v9"Q(XFVD$j=^JW4,Pb T[@匼Qml7G)k26+2"bqo)*;xSCGT;ȂHCRKό`{ מ#;H/7(Dz0I\/fWyªy ?9,_)0C9=efX^¨szj.y4eja'|'H&Ǧ ҄mܵҵkksז u鄺tB|G2dzi8ELOfM ۋ=wo!SLޖ Z`=3]aDaOjzv6^x=ۡ 6PU_Q X`| dz@uu5)l.*]=3/tK 0cA "Aa3 p% jӸ߀n" vsbi@HA3v4 j;r$f0a.Fc[Oy^@cjw(%kRTV`-}Y\WIn Ppۇn)QcSr/IM|ej^Qh-gW4Bs0Br56b/&ލoCB"_\DILL[J@+{nnu* /,?c-?u +uV*VLs(E FoEvݟFbb<'dOE hB߯N1'JaLn¹T> stream xڭXY6~_!I"EGi&X6mPRvݢ3$%Kh60 "3o~ūPxb{WQJD{ c$w>]G{BHA1\rA}" x;]h+>f'%a~6ݲ-:b(9^jC!;dťG @N [g a/rxL xs $8O("q?9Lx _HH< *Y4}T%v?SUH)_Uk'jZTCbM/m]o׹+tRFhJ,> vs|7cbBxxϜ$5Dv.Hĉ5r+ַ[J[ 4ѓQ/⯀lݨcY(/MMأcdql.w7pݲtQo@g_\a8$)6pLO*d)?\;އi`Qa"_?h“YmE^yNӓ{BmRH f^ =j*#Q-r7@@|`L"|="r :% D^R"}R=gLhF̼x Sا=hx*f22?IQw*76߻]k|y$hWk7|%Kn ELbZmn+%f# d*D4>{@w-/Ο\>ǐq{ۼܣ:qh8R&oeFfaEmץ&83j(}emw؜8X v#˾ l;mT3Iu -ғugױ2u8exc-ezcsKp:X,=q 3Lw҈#pyǴ//]9< F5{dž7[>W&@ޘ#JBtɅ;)M34`"ǑF$L&9C}m}ܨ{lN/DKZ js?POYi?spO:ME #ƭ+`T`RvLƎ}*bk#5<,-pL2K)6[t\˃[[f3XHLx2z !ڴiT=K$ DƈFnmyz"C)-<9gTXU^솛 /UڃP`#U H]l3%$Uf^=h?zzݷg# ccX }C>Z[Кv endstream endobj 301 0 obj << /Length 1312 /Filter /FlateDecode >> stream xWێ4}4%W$ +N݆tg{or2IVZeTq qqnW_nV7g_c "v{{b=,Y|c nGgM?)nk혩V޿#!}@Rj=J} 8s8dLY]#r;jA<ꪶUZKC /8Q'pДKUq ξQ~U#*X><}YMAF}8 ~|QؗYwi?7 mcvF*hʚFd-Z-Pd*X,MAtv:[]4ul8~trpkY%}Q/oAi`"9ˢ_Y_e-23C>Yx}Rt/3E 6/יQGKuI!!!]k/L{0vpfs|zsE qtE> '?I8i✌ b6ϫŨGP' O)% :Cj 懩su./S8 3/<<IZty+%b}e WZ>f=7 %9sqn)К,КQY5u' 4h芶ӈuA O @R:q'$JϽus77rh1== F uOOB@³qUu sUBvX%Y?(K8vFi:)vξbztF}慡M\ I1`".\'Y !2+ѢE^7=9+5'_vGH!ܾ*D[BlNM_~{eAZq(@r_k$jr:8|;4E?Sˆram)b,zP%C ' bg/M-Z-&!V0M&l,nHXJnuWX Ob>8lwJ*aGM^,hҎsy]u.G ٗ}҂ɺnкg i[=h6Bo{{Y Q U:>Hg!#1T/KԺe'FҶ6HIf xlRVTFe endstream endobj 320 0 obj << /Length 1225 /Filter /FlateDecode >> stream xڵW[o6~$1˫.bɀae֠K*Jhb}([' ,RP88inx{Y4Q1b< bBP` >M?a h 11w-WTRݾ:qT%8w,AQJw^XBY_nMNժ-2z5Um;Gݻiթibzݦqpre'>*PN3jGq*rIlUPegT+  @MuS&W PHIbD4,0@9Bnp! aJ5YP%p8#bʸ[ulw( 8T˕84Nf!b4ao.0|pkc;߭=c a(Mzܱqu5s/ʑ(!$Ȫŧ8K4 Y*42m p"$D1-G$Ei2zP&=4?U_j+1CmlCy %tw]OPܔ&ۍd%"8nufIqwVJ&-+ CH_q#p<عXmRxt =[Z]F&D@Edig*`<,#^U 60^|Ç `r;@@ظOIpY uPC*ٖj==7sa1x,u/ d L헆dWdM-".@s_` endstream endobj 339 0 obj << /Length 1639 /Filter /FlateDecode >> stream xڥXo6_!w?DIm+KZM'dɕ4_#%GqA@:}dxk.Ioh.SJ$OƻX|\J.9TKSf;j!?t"WMSnFۏِM&D&ȇr|PX4aEqRmq-XgEp͈ՐE؂MzYʹtg|n:ϊa!#,sCd8U`""U"i }'Ukl~BYj~bVk4/uz?xQ/N= K()\Yysya?=e><+Z㏶a˳1PvSG8#$0r:p Y=XIJ'|$EIL8n^& <Df&p"j7bgJ`RaC1`H ǿ)Ø"# 3i7GX|[[[I{;CHLm˵+ xo}0zq27'-ưFˆ~UO>rYΏ0"Iȏ"2%1O&G_-Ě fݣɠH&3fZ!?`%ItZxJی# ~"W(vbK#&_FюJUy~XǑ8v?GQФӚDl7 ul)=&HxLCK>3Xyhmij0_g;p=ŨH#d.cr[Q35Kl7RjfTiTkPݨm^h!!9tUKnpn|k; ,O㑐fF 68|BZwpꄭ@Q8R'' ۂ}<">{4~IBX*&5@/ԅZ͵/'rz?8)TN+sHVO]tl7WvaڴU Znz+ ;(qĆǁ|~g2cl2cc5YD*?5nǔ wSOnSXܤqNFCp1|lzR|vWE7X(jPSo] |Œ<5/&ޟ?, ppS3+ endstream endobj 356 0 obj << /Length 2591 /Filter /FlateDecode >> stream xڵYKϯ0&9@Ç$JAf `Aڦ#K^=fڗTi{7"Y$W+?߿z>TW0^i!Xn!(޼WdH geE"[6JjF*YʹrMx+_;Q@)&CeF$j'>4 d/~iCi/wSv /kyP 7j#dRعUРNGm͎ñ=72t*wFΏEͤ d7 g:gMGWEQឿ♠zN[/U{zǼm`^>de[a L$J;*VwEވ۪e%c/vk{ѶDOLl}3 8?|xc^9t4 39nGT&di8}NDL]7 4ee/Ktx_gγJ DY@CWîxtft7S7^ 5SR-w n$_Tʬ36۶4y_L[z`6xd/xPn; G83Ӏ.- ֶ%_Ƿ>!сF;fx [3z`X1`7L[pRQPPp ܛELRゼeC?9x_& Y]8#Smc M/oc yDCH|ܦLzU$P<˥7ju-}q4]cHZuOU11.wY|H"mJz-;=2ǒU@͟Π%<6v A uD.k>]jNim9&F`@AZSYOޝqDև4 ¤u@?kBJKZ5 ڵL^?bfN sj{] *[i[d%Dc4Y,vzyy]%bf$H7dž3b=yc\wmڮ.'䙚S.|(Lִ^owXI4s8`袞6-9xN솯2_4dlLuf4LryJS9:! cv,GrTv3`"+1XL}VV?dz ZG eR:>#b/> AeD32̥b]TBB"7~?Ì3 N+.?ߕn\M'rܳ k p-)Cdh~yKmIe 9ǻ hi^cCӡ#T!.~6 xhl#åVaǾҳƕ]tQu\ _>톉embr?dzLڕ?^\f~"7:h34%䯝:^c$CdlmAJMw jl- 8T}cY5v%&p ΰ $tH J|<#QrY2 ό޹:pLH(,=]q!2 5v0D ׼tN <$C<Y41e01l4]a1m}f~<'ҭU 60Sv@M,[Ġ cӸ g!bN=rͣ,QSVhQؒ/K8Z:TP7}e,"XZ˾(JVDPUi;BJ+m?]ػ]wWRUQelfX NvQ;jvKy!1X<#˸T<GZuzǼkQ=eN=O<Z2QJ[Ԓêd[@)RdqeҚ+yxNUG Uyknݍu814x׳ 70&\A{"+ *&kM*k]XjB7T/\S)ѭ5@Z2W9h v|qNgqI흤 fX&7V찦u2,~]n8zLPv@>j}_|*I3j3% oL$/,c ,> stream xXKs6Wh !>5m6N:''B"$@ʯŇ KJ::pA.>!oy/~X\(AIHb=ž"QH"Np8ՍO{4(>Qb>w wL58੃Hpb0y +f -3 ŖTKf:[]3^[>d?X vx`H0@K|OH0d70$|y_]{/2eVsں,vk !' 8l C3"QDG Ϩo *3mlj뤯0%7}ߘBuIQ #[B<䧢#dDiD҅HB@.Nmv(n幤Em0e6ό!nic+ x5y~pD  QeAXgejk@8GI Fpتp%QAՖP@!FryYi*yV.pAL; W-" Y#m-p ɣA ok6xTJnMU$K+^LN*xX–h.][p+ ڋ&Em F M+'E-qHs} `_˴ rAdo`'( ۏl%/5:ԧ'q #s5iê+ʮBVN'RpNrvlDW6adcAg~`Wsw4b,ӄ~/M& 1U)Ud<ă<\I|+GKL% /<6,ȸ@|-?QM(j $"k.n~{w3 {*xܸfD}ǍpFVLls<9'dm%.yݔri5T!_|Ual9ȫ1ng]&YP &01d}WHa&3d7]E̖roj*Qq˸ҽ V'w]̋db#WHf(rRiCF+kY/^}#''IP6C@B$CF9g׬ɥ{Iy {=sK~`s-,H^|`ԵHm--ф. t2XM1oUh3MFp+9*c8z좥ycm>i|ʓk֛B#5w3OkNN#-϶u>vg$ HpL,CcIMsu"ϥS3 O'_OXӐܱNcގ- Ϝ==_Od0Cm2 endstream endobj 381 0 obj << /Length 1536 /Filter /FlateDecode >> stream xڽXY6~6`+F}HsEZ[Zmuu8$C{af7Mp87 x/g?/g^Dqp >J .o^25NEQS⦼Pׅ?VWۓ[)3^z=|n@8?`C(Bс'EQ%!jZOE"[V}IԹ3.lyj›}Sx?0R.57T`:bE3UCP+OH8羐7ڴMvb}aO؀$i#TtpʭJ咭=@6[F7+݆zE_ElR;4 v\Uw+6o^: rg4Lő5ЮX =fT\UB?q(wy.mp⢻X ga7DqH{E={1pPgUZ{ iХ~wx2:@$^8pLQ:JPa[E%ĦxWȖkB_jV*6Ԅ_cqoY85NyX{;8ȃ1X`W*;^6ۉK3A6ɟrFjGsmr<7m=zNTTTX7h$/wL0MwUR YhZ'ئ bOK52h'w-7=Tlkczo UVun`=?rF1ʰb3%n3$0:!R+pL2"װ>4l>muNJR {䁝5] o q3&&phrU]Grec|BP >șSN }-Mцρ QH ͏>0 !bQ6ڴ˿a_ӦIXXqin ]m8[w,Q `Sb<5bݝ ̫S)׏fؔ *fcL& WYq;㨦W$o -}Jk*=j(͘&YaV0~(gѽxoPGk?ISH޲*GQaF| CcLT=) }§2L '! endstream endobj 393 0 obj << /Length 2097 /Filter /FlateDecode >> stream xڭX[۸~_a/2sE6YXdi!] h YJ3BʒGz"ssWꇻūBJW C*RQ߭>2_v>dgIΐvp]d鱍?QLF|/mv(mf'\fjp^ |Z&AkYM5'Sײ1nk0 OY6vi"R XiM`kxQTJ1GAcX/wgW ?͙n(d}_uI59 $WtT rYд=OS~Y00μ?+hR soÑ19Ux0ؓ`\i5ekQ$"fyZ ]9{ϘW>m;dEdZI>ͱjw?M5e[Ǧur0Y;~sZYGkqqԐo!Po)H0f7~vy9RF5qvJ8P> :Ѝ a/y7v%#TNi@Q]rYBЩ"dh;V?_MnxzjmkI$bS%˄,$3usxzs=.5D|.N 5۴! ͟ڭ0w sYS a+u$pJUw*<-j5O~OEM{m$,ǐʺiIj=""J[_;'r$ҾyG6gKU-V8j>g-S|.u/\%4@f|(Ne{5z/d3c^3ds*[uB|C\31B$~K3~yEmMMr;I8 O婈d*w W;XEEˉb"¯^ryO}X4+(G2G\lvPM{ڶ.*Sk0<$:>4-b۟$Yr-+2%Y忚neP&'0$%2@\0VKRehģ2$/8|q~oLM])K̜howzfͬҫY-Z(#/v2K5 'c5gl$zl3MUPhu]L 9ja =O\gxfdR.T: ,.~s{r~aJ)EQ? ƭ.dƉkOM,qۚRq)l(E`VwUIZPɅPyh˃쩇OBmO]G}rS9*?ɖeS-I"'@`KBVK sq|g*ʻyp (dLt $ˑO[x`)-D&kW%Î"?,[cjA z iSTYTz#ЩV_6PEnU9ӟ ^gn|TWeCJFB%v>~bJ/+_qD7x(R w"xCgfbЦ1aB3!)TLĜUy`zXbKDk3IMt /JuݕsS:sXhtPTW8Q\B:gk*kA? _󿋅>%9~X@pq endstream endobj 287 0 obj << /Type /ObjStm /N 100 /First 880 /Length 2088 /Filter /FlateDecode >> stream xڽZr7}W /b4 Trn4qXI陑MI8F~ "ƙP^L Ƈd ڃP $Ѥ\L+rpI(db~Lpi!փtl<$>h-5l X-m:Ϻny\\ rתViHixܖrO\'WF4/j =z=2Bxr]Ÿ"g!%՝K}`PRdHty} n2vzdz.ugmyp?\yAl[6zijka=߇/Nɂ[ݟz dž|Bo 2D^"fΖzU]gsfuqw 'ĝ];A'$ 9 T ;i/m=X~Օ+竲=XF:3`ȨRbKg7ߖD7di {bi&K,T=ijV %f=ilo=Лwktmك gp*A&7- endstream endobj 410 0 obj << /Length 1319 /Filter /FlateDecode >> stream xڕWKo6WA61"EQRRtmXݤ"ef!K^JCFᘞql(8~vsG G9#,_8PLYbXqڥZjv]L4(@eŹaEj=sHRȃ1:wܑgeNϖ~NQlt|Hbcۈ],tTezED7W^ƣJz>:caf0D1uO6 7NTZ],YNkdXO)CyFz]$VRF' F^Crgx½Vh]Ui]7hI.h*9u "'s^-p9yZz䝓4 }1AC[趩z? LjФ|ڈgI1(V/M7>"۲m '$qj>%*b!?忢|G+.Y[F}).eO!t:;]F !G|[6ͼpy|lIz%$x^8tSNMU>p|ote/>ϾL=G(1,(voQ/5YbYwMaGA|u>1h!RD փZH(*X]Dy_xj 1PE#i <">uE!rPR]OqGۆIrS@]欋Sk0:qBEnw^Eg9sJUb@ oZh%wa+%fHʂftgh'0P? cD3~Q:ͅ\F 3\ s03yfVbMXw%FZ4Lv=ȯ&7yq 7jFLe+%$Ce3DSrvsc;&V-ڻ'XQfEeWqr1 y7Zk!.- vs ^iET30 N.apId;'v֫v-V&.MgDLK2~EӄualhQԕܖQY`>ms%a[ze|ų^I ]Eܨòa;ҽ4nryƳ:czta,08(uFZgY+(Ir:#ȍl;G"\xD4ELN~A8g>NBVp>3# o! endstream endobj 427 0 obj << /Length 1175 /Filter /FlateDecode >> stream xWK6WN+z.ö R=lcDȒ+ұ;)Y;>9pfyȱVc>>R׊Pߚ--8`|YԚO3]}ti$ 0łK+uv )jOxOzHp8l8oLmq&^7\Te7I΄xN pc/HO= t9D"k86v#亰byrJrOxcE7I6gE%\M!"0ƽ= Z&7C<&GKw4O79Z h[G({ê(+^A]c¾o^( nqUqMN\&:; fdgB&aW\ߕ~l0­v93/LWQgTWCՖPnI`ŝ!t-+)4Irp_ Wz>"{ʎ,1U.=r{ȩwQ:"7tGyU.Oێ33"i!b\XlϊS4< } ~860 Wی\7TSMUh֛5Yp|U;޾H8FqLǯY՜a[c6^uG HOܘCj4*Bt)7ds.& _LHg*{z,QU>rVޙOr9vmULY(Gn~ܸEixD endstream endobj 449 0 obj << /Length 1750 /Filter /FlateDecode >> stream xڥَ6_!yDRǢ/I@Ѵ[}-ѶYr(:[;7%%|B@(f\o?Jx@0ߥ9܂yWXigZ]Xs1&Ǵ}%MI߯zƮ TlzwkI 8awrlNQc~Ns##E\&"Cq8QL|WH&pHIʅpUYyʋjyvY Jsn`jթifAIS8b5ZL(ԟ (,׶dvVԇix?9GjF;'BXOgjw,#Bo+領Q7)EvFܪj[F^A҂(iuLhJ{X1-rHZZ/L_Hh24ܚIBSxcnEVj87GS(jp{!`Q^ݠø7QڳnoD [^/:= endstream endobj 470 0 obj << /Length 1682 /Filter /FlateDecode >> stream xڽXKo6WЃ2HRI@ D*իe3J6EQC㛧wُg/^ $, йq<Ιy E\Εx-ŌRD PH]yq{<2f^, ~8\mݷ*x{ElM]ꐶ{zi:Z(UZ{(vlɆ;[/d㧦[B禝{E5{K즥>4@Uܾ'E}?ܓٶM;V9l%WU-:'|آNdKth"ӛ7rĥላ^wMG[^Y3t) D6>wMzѪzsØ;{gED&[U, bC\h4ضSmZtGGxoG!oR!buްgZP, K K/D Csg<܌4ԇTvQ4(cA >3ukSmݑU_a"kY+YD`$:LnW%Դ7RtHW<4B44V}ʤJ]Ӓ0r޽Zgr \9PH]FGH<( 20FۦX%ف^ƃ߭X ȟ oJ[m[אϐ)ڄ5q-zjmOK0\V$~Q ] f74;5.a*ESFP\w*=m S@UR 0pQ]cљ}T&8 Hn/5̈́ef!;rP &Gkld9,2+z5m&P>j^ʴx1mƪ-GO5o[LIGQ XY.ʾYm%8,4pR{p 2jO(}R$Υ,ɢ$x.KݝPJ [ Gq_Uۯ3M#dD&ع3#!#FS:X|s9 äτ.0Ds\7xq} -"!ˊ:[UWﻏ uSx WF:2 IIUuEktlk$&'(_1Y+qw]nhGۮk0y3! /p ٖ߈$ƤfCzdva +s:Cn J4Rm߃(;(BIaSҪ>S؛sw8-WU*hdc@%Gn.=A+}ľkv }CD8%-}@T6]4BaMCGHcۜ{3˗X֋% I"$*h#GOZHp\/:~  ?=e(8Ffi/&q)8:F>;8hǎ/?*;rpIc> stream xڵX[~_K)pIMd>؁1FcguR$V3s?Lw7^D$A(RY{fSo?}cfGgi[i")77þI4^qy[ma'bN_o17Zńy$^g,Fg+AtL<ue]E>[:jW<[0J@ss$KfHxBge ]ڲ'Śj#:6cL}\q=qhOUnUY|5.zeZ@VEhC@@٨h 0SK\gcjҴ뢩c=-s1t8]'9tCdaܕvc!d7[FhW$ f[~s%o:hΙ e)$6 @c9*AE:&lP[o4tWk]lk]fL@wJBr TYu Tej53VcQ9 :1HĔe{}B܆1#b.H޾>ju)p⠊O{޺%Ct6˺`Ye>'. fӰ $l zdWeOns U)'.r׌9TmXyu6q]zwk5%h/n0bө-5vm2ˣh/њZ@B|{{HP8zp(!ZeZ%gӲKibY6]"ЯLP4Cv NܸLRW u+iwإk*'5P 7q(KocK#bY8}GM_sYA*ԚA| T! }hV.H( gMG n@ vvXLTS*T G)yHL X4F,1orizP hl-]Qqarj߁|Y 90,T T`+1FZ8=]to<4 Y|. _4,"W/T07lmı܇V 5K|[ $Ga"L/EvZC_U/F<.ȾO.2\傮 S6+x9J.R>PsG tA95+7"hi:1WFL/m> stream xXr6+4jRc"$HJ943=;q! P xwA)Q>u<bv.h.^_~F<\/0 A&a:^ nF8(lII(=j j ),fcBBPQQS%w1S4S[ ύpc.8R0=# hKyL93;A*hʖ;F5Jf#Q:((\>S\h##86: jr0tCraDriU$/s*;MEvhzzб l5"O1aAZ\Xv3Ee=9IC4m$Fgό,ri7Ofz#]K2Rak5u4cAYuv42H@:2C~Ef1 EDw E=r.} An|MQ8^^%) e2axYEI/y|M endstream endobj 405 0 obj << /Type /ObjStm /N 100 /First 876 /Length 2276 /Filter /FlateDecode >> stream xZ[SG~ׯ/=}9}T9I6Yh-KH5D}t}\s_2$`U1ʗ(1pU.)oy#1E*z1´-1:e͸|"Z 6884u,&r"D-'Oቃp/q8 t8es)\@ln$2\I>uJBN\>A!S zN \>puʸ w`HATYĖ"a[3` KHSH'oI4B`BpԞY)fщѪ3V@y8P"fO.`@y21o*F 5' ,ȿ$X$^n4 ɞO0M|SłǒL" \GCHBB¶W)Y^ r*Nj2u)xZ H.*Ldsι3! \lx@|P ;yvJą ٍGcF_7B8@Wov9ꀍ> ?vY>>XWj_58lB|ToWW`Ua L.N^OVH5?p7Wz7.&|2jǚjvx}Nd"Z诓2'ye-E0ꨋҝܨy}y25-I-a5n~l? AJ B;,]S2:$G]{jxPPón'痳qֈ9%54Ft&" BʭKMDDvm8tvPngWFKi0­%Fd׶HQPEOa fvQߥ[<5`2!O>hԖ\ou z"$:kZ:q?Mvso>w 5Q/aT]B'|f{B"]Y-{=g_Ouu\zutu R0_റ]]":h$F=!ޝs>r8epGFbGdPfti^w+4NVżyGuX5ǏjzIE{\yp( 2+(vB O O@6ktpwt /9 |Rk8UEK/:$OBەzp>`1~: UU',1f0. o(ft@cW!*!?;dbvmSB (8Bda,lɠ|5^Sdz[ń|cSs}'L}'l\ [&ٕǤyܹ _B3PLz|&V>+:_C rKёY5@ ~{></E1yHkmB†K۽]|\F\`_4#^Kx<^NV|i =:!xAϾ.RrbÕE!Vj8)] (K~Bgx`,5 GGX,k$'}D~"Hq8Ҏpr68C.ACA՚ؙ@]|yE;x6y;D黏C9M?\,ox]Қ(j\Lgq8wg3o_}9|gÛ |(ZA\\y Z $=MN&[k&Bҕ6pkC?a$A#=GP\Oaҁ_?a.ԆE$%"%J c%\I^$/W+˕4*i̕4J|. R͊:"F{F8@T3؄{6J!aU:t=H*քsI$N9}QI d.#\BWӑNB+ӢEFDgAcG?j {{\,6q6AAZZ9!g\aGgyÐ R#``PkDI\r5 9}4{Epr /_N<" S#zN^\,EL ԡ mS[\gu^%R?a`MߕFU,RK-e[ endstream endobj 516 0 obj << /Length 975 /Filter /FlateDecode >> stream xڝV[o"7~WTHqj_zɪ*̓C3S2IH؟;ֈg8B.0E(NQF)N͖qK~4!18A~F(lklag}m2`ԕbl7gIEҮ/JpjD:AUsv9ɢ9ֈFJM[k& 1: `VwvΓ[C HM} Oӻ!* ]tPak^xJq> stream xڭVMo6ϯ@ #eۀH=dɪժRw'{'M2s^LI"U#_~G{׋ R2ʼ# d^LbAsl}m AJaXv!˪Yؼ Y?{Qj5bt($ފ$% !4U>,f(MhoU( |ULn|gB7m=V[89el#ǽ-7Bld MQ$= -WAKB-S{["z㮷U_Y &)FidcB}[puaA%_x] F`xr5z'0jjKklFy=h;y5I|ۨ~ҰˡqEyxLϋV̖δ%sU2o|_|Mj;1Xx246&Mgǟ8]-26rץ?60Q!D ʛ1Jzfjꑸ9wYPY#vo9T]VE/['gO]E/_9MeGU S3 q163ypIEW@/n֋`rAjQewAAxtf\fc-x@]1v/CD; GL0g2}:]]j`3.( l$TZ˪m9Ԣvbf۴F(uEΌI+f}Z- uuuoblcqƮhKȲn5fD#̞+h80Jn̾`Xֽt ~tDedDԿ0%88+Dqtڲ<3DM֟Iԟ"綆3[%=nRg8~]APۿ4/l \%+'s5b94Uz=lFlm0y[)yj١nRvz*(>jJbؤEiWRd?͠\VY endstream endobj 645 0 obj << /Length 1631 /Filter /FlateDecode >> stream x[ߏ6~߿>lƇm{ԫZUtZUDKB_HƆ`wV378|͛w{(Q=xG4]/uyw{pX l9=p.kW8"PDD L`_ɷ*Kf<kL p`'PwD >9?!Gl&%-\jtB v]w%r۷c >8JQ22 lxj_6X65U!KJ4 i89*F ؉wT^-ޑ`J!*QH90B4ڦj b&4 !& %sJDznoYT*nT2/C$p,V IXI,~np+u2qdUB@㡊*|nf %px!ܚm$۴j0]9H_n rtҜen)Gۨ{0 kPbr~%4N^ G~Q,٧YRHSbYbmÑq`uKO櫿aec{Ք$bOL2i5*y dH>Xq𡯰:SvߟWuYCTyUi3o`" dsu6ةkknZ0H@zAS$)ѕJa@+k4M2x xO7?IOI<4KjpȢݦ&.unõfs.wP{ L<967iMpXW=u򉼠 f9W=B i\OBܢ:}Xdt䂊ڭٵ:j u#ַ^FgBW&ղJg#g3 6p( ]ߡ. ֶ#"尮Kwj׿i<4R@q٭H).dom۽o湁a!5{|ʔjѹ# ЊTⵔ&NFZ1EG-p;qĭI=l҄'D\Ӎp;tO;lS'sOw-џ]AH‹}~6Pc Lak?Ч5 {H&t?U\ endstream endobj 509 0 obj << /Type /ObjStm /N 100 /First 905 /Length 2656 /Filter /FlateDecode >> stream xڽ[n}WԣRSwE x HFD%M )sA=lJݬ>}HtH"x%-UV=:Jj{ԩ4N8Qi-QD̸hx=Q\(0X vK_&&ņ 7' ln?&jF%UЫI$a &KҕqQ %%ä') 7jOL)iMmm.>.J.>᝛࿀n. 38^>ƩCh13MU0^*sà޽Hb?ȩB>ZmնzÐR/>ac$VRN 6b4A*d[M}P{i F,G>W~:,`DIwT P̺77Wuc\ 008؀.DbpA@\5GJ473 |""7XN>=|ˇm|}qqysyyfŏ'o.o^xky/o_tsy}w^rJ0 ʐ=ΙӴy62mK_E>/n۷/W_O؜P W\w_?O~8=Z0ߥW,Ekd4P7L\0v~vyq3Oz2-n8x}3D(7y~uJ=K?ߤ7'o͵GTe|}y{n{=߶N9MZWm^]~BUOmSoQG2]|,1@Dq{sv~϶8 <=tp~dgJQ6>l&*~<3,Q?3\r9^ Q>USD֢Ѷh{;>ڵC < < < < < < < < < < < < < < < {vmW^ x5jk^ x-Zk^x=zxa|iawm7vx>{ٵ-G+jmEۣ < j\5TD])¡|k/ZV9‡+^G 5X-UIQ<́ƒ$z& E2MA٨E"$ Y$0CYuHװf>Bn'_6BDr-PW  "_30]f1) ңlb5PA\"b0cC ȡ8Tn@JY7hN rBQt 6owF-ՇȒ^U$3PJhI{@r*ț{Pq f-=əcz:ԏ`^0a6ƞ'h@DTPc(Rq(˦(,yڠA(TC:މ9|({Θ8QWTea1,˧N#cZCʐr ZT2B'A55U@m0M[(s)%fYZI#aQK:gC G&ŏR`Z>ox%*Ym%QBl.HtsZoM|S˗<bCi`QsD= RgjJn sf :!,rOa*jX2Dv 0m NJt|\J#.^4%q@TOL=*xV=`%dY=',]i SE> Z>CB r͝;h~htȤ~%z* :m'0?A\̳J&IpMN=(RojС}e9\S5i9]'Dzu2b/5K@T$myƜ|O!WEyvY3-Hv¢1 t1 _RP 9_H[Kf-Fƀ_,u@{D!cYg #]}bfC^[YҦͅ/nױKuϕ7N~f Xth|!i endstream endobj 659 0 obj << /Length 441 /Filter /FlateDecode >> stream xڭUj@ThƹsTK袄REF Jm"騍 sgNFaCA,+N0FQ(BK17i}B$Fg}O,ox1>8$\?1KKw+5dє =ԐUJ_S>ԚcJS] +7$psR6?X I~P1i֪խhUn'H?5<6@,H'1OcuiRp]T> stream xZMo$ϯ1pX$H J$»؂,bHV 8>q=X\lrnwUw[$%ES٥fil16+99 Ip"Uw&k%9*d'E8Y9UQ0Ѥ3Nb*Y .E1X @@E ;GuI ;Gs)).ȱ $k9j%!8rh^䈥Ms"I>\9EOu6Hi:"PQܐ>f|M4Q̀ũ?M8 і98l)3ÕFJQհTՕ@"Ot<1bd @.W %TJ;qVɕ29!2C HݥCR TY*CJ],_He7&?3AO5윱O9@Hm+K h)*!Rp]jʻd"@'PRASD@ Tv+ jV3Vr1bU-Wvw~_Ϳvo~ po._^w99y!W5{QüܫWn|_?>/ܗ_ZgJA#'S^L y; Y}bB[BJ|s%y |,Ķ@@=S(LT=DvĖ1lYƦ`JD($Q7+F)f7HI~ÖPQb l 9B l)a05 1nzXCOd U=)Ζ-i tC [tQ^_6|F*b˰ 3+E'ȏb2xDyA@~*84J9m)jb@^ ^'4DB"zkda|C8lC7V@̚L `Q0V*D>pNu+˜ (PsJV/:2r2'HD*P = ] SX_ ` B/QG 7Iy\pTÔ\bpЈ5 b0+-s1L:2l3[>HҞb?GG| b˰f>H*EO,.b\3Zav4o} '\~zj'k5o^/Pk."]KUhXsw5ht7//!ހs}sa9݇Ot?1{k0KNsbCL}f>5?|k<:m4A\of>8TZTĉf8(22t \&G̨NVjkoEhPlr`ByP ֡j|^<,fG  BC툠|%A6W-(V:-6 /A\D w[>:l =BYK0DK^{^%q/f@bYR:=9EGtՖQ*vGs$ CI}粁 %`!)N .W+ ]0˻~4@61T`9OJ]>>c4o)Ǐ5c~MB'BjT;~՘<=H50/im/؃ٳ3^{73RF׽*EBP,] fG#'0 !a3çqg$@I~M^/2fӸ> stream xڜyPݲ% {];8]%;}Oyoo^{}UP(2%@ ,<iӒAhbc#PPY:;/ oQG3"f SuM\Vv.66+3 y&F@=B™#ڄf[䀮@пPY::9l6F|25a4YXIzS{/)_JY B.&N@Ss4)*-0 v3@:4{:3 p:h@mlW_KNf 3 Xbq- 018G)X`'}v  `qL*R:bZtM,"b ``3s>Tb( 2+ySϾPhN` @ٙMX6=:X{h_>=0_>,s& t!#?B&wD68+a&K' Kw O_XJvNݓ`g55 Kk _K@$ d`e9:y 0` fr{31!{goM;xt2qD~#No`L#Nfo$9~#0ofQqY~#VoTLjoA7wq=F,`#'Kؘev:Z:Yo&.ƿ8 E? X`? L;g0'mkV _|@y;V՟[* vY2,Kވ$M|yU?03WqW2dl?P`Iavr*D[@06U K=:Λ2nQ{RWSSPIbKs9Te&]'*MCCwV)?{>9Z{2<J>\Cr #EDJY5^t*QL7(a&mWHlllcEv#G &bGKo7U@Q^ )[L"^b[`W O>eTj[PwČoWKV§=;l0+gQi0juu=:(7Wt䧧lNAoZww4Ghw1-\lVd$ I=5B Z٦u\\:TbgB)|wEq|"~'zmq%97Der]16'M$,Wp3oRi0:; QfNjuٖa6#[5ƜWĬbӷƃ:6{H+W7=cj#GGFF7*_Pu-U#Fx?)VMWGϚ)J’w:xFbGAAm{Zu5gk &F<[YS*ZG,̈́-;`>}d*J*uQoQIT[.VLU?tEyG5go$3杬ؽ鄨& q.(1VJ\<MD73ՓH!eaz}-š tttZ묟&#~j^eslj遼m>u!=; >& Ixo4U!%!)#NBb"1og<+>qlA2ד1[zW&Rmx513uO"+x~e)AH<0Rh͋o*<":݌wrPNuۥ:2Ӻ §̰kȒ)i:{y7h7Sv/:ӄȒԍ_6hDB.Me*gh8>y&*#z qTe%mO]r8BA_Kj,g㦋*@`TJU}qZqHd./r{:}Ǻ,rTPjt",Qa>soz{8Ò~i{?-o\PEG* ѪW} LTv(JxoYk~$Lׄl+2nkV!-$.u$fʴDG.٫CO]͔/݅+[{ܬhg=Xzmq#O6ZrDrq 5F̤%:sA^!=Ggu"%n_i-ĺU5Oڃ-OYk۬_bp2'>1|:lYa:C=>?Drů\MQ+Ը:dufi͗ C]6\`){S5-IK\1hs|]}Eͦ^VX|D= H ]knf,¶A7HK;n)+*Mk7@ # +HڛesP|: 'mp]5^whK{F fL[9wuH4#r:[ v1H퇇AgK$lڡr/Yʻ=1ESY.?<2N5A//6q1H]oTQZ+m|B-VmgPdan@smPI|JSQuK j~:}u㮃[\57FLAD,u:c;E9R-كl}a -sȱgt2k;7I "Hv;of_mߴ~5$. vV[խ9fi42v[902l9mq5YN=:3b$?Xρ*1A^͛TmtbƿEqP-]Ë2Lc@KO3E|.譡P0Ehw#:(m6Yq9(Z$se7?>,&^xԔ;zѦnD?Xd=}-mA @PX0;/hk{;NEZƕOHȭ$87xph5{)+= zj:v# 9H).:=b 5l5+ὟB%Zeb#'V:PIR̳xZ,NnN.ΌpWvʅqFFV&8RʴO#{=-Kmn _ƚeAǐi=_G3|PP 7YJ Ga]briqݨpTzsvۉG/4t̤bGﬣΪ.IbdY=Km^x!(!Qn&PEdNN|n/դ(\S2˱r}qJ<>Ζ_RD:>NlC=>!#INvH&{KYeng'Vq?\>,u`Cey'ƗИ(,gAoѨhю51 B p# 0[}#%D7@)&DPؤDALKfl" ޷kۄuZT)֘QPuG›v2iM81dl"CG"9Zn! qM>S)O&$EmZK搳&AY.w2s:QG7 1¨b3P_ p&;$zbN^Ma繱m%[tAfAu_쳷sV)<(gI1:N}.$`hKT*VB<&96ϡ(&#N5NHF!WH*'9YwIl\I+JW{Ty\3e .X$\mG;EbKc^tLAӧŃ|T,v/qՁVhg4xEχ^hKMFYXsðѝr{m,DN{0hL׈DY ݲ]' #{^~ V ^P:B 7RۥWC"QH )EZ}sY6襵wЅ[ˇ3|b򳃮칖izRP|q;S9kDC6o&_0YG3B2ӈȘj&7m^ 92J{z&w^1F<*nD`)=}q@;u1)%bH}7h q\/qZr؜|k}GPIe$dF6qR0*NoQmNcdI➲yI9n4*Np3|gQ&3@wW4⊔Җ?>u)rmlN ~ C#e o"0\! >^,۩L5nӾmUqR܏xMgYaWJ:JiW;?1P8gkLbE1ssAW~1GKYPvmV\y^Hg1c5\ڀlӷ բRH#ߚ^ v I~ ۝G"U L4<FR E潞Q$aԚQ$y?TcmJ9yiF"9?0 ݓaG걢+LӬ;oxrBA߱2}c<㗶lA4y.ڢQę`_o#8Ӵf٩MIg꿷5og>F?1QqJ7&iʡAJ_ 6VQhpK 90$ >ٕrTN;Ўh'mzHp ow2i{nO+O )+~kVȎܼ02eoBxeƦ% շ-_Rb!=9Æ`\ӧwawq"!$=lwIu -IƗO S"]l$>!z!뒧h syܷ>40(=(}]9=;%|hRPd!)M]EF{~1!r&3Th&SO_I0(?i߃|c0UqKa8ڝ( z Do0(3 Es͹ ̲ Ah:GYEMak}ND 5/Yqj?m.$iw;y}7{xm6[Kg{L[fbE0Kz<߬w p^VW45q ]y9elo|FBѲjqXu3ƔEa$$:!Pxz. de- Yx8j sLUH 3oˬh_C>=hLؽU *ʽۦ|SD_#ga$Y.R%E!n]H_͇eWR.zi`C@=iH!hhO6z'=#ź'7s Z=eܾ_)gc/6O23q)F,8ni1Lt<[q18lv}C3u:}ԋrPWj;Uv=UU &8R1q5Oo@ٟ|c\pHyԆ O[TMOZ 2s~ąP㬸.JN{LG${^YrN.#$v6  {&zS FVQaF\9B ȭ7\fXʏ߳37.9WQB:POm=?to.nF8+3}6D?V>"x _ =RlHr{lw߹6CcQ6 3icYiV_e}(%DW̘sYuA+AfyQB8mDۢwJGE_ޫ>GQGXV{D@وdԧI=!`ޅ Ef5Δ 6z30t(3j&  _U.{o-ǎ,?҅9Syb!!zH{Hl`7LOnR]mMFg:9y<ǵ$x)ZьOQZ?r * v6u vPsnMc 'Egiv[QD#xpx>[QsJg6oV~2؜@EkFg>2>,vl| RK~oA;0fgZ6lTLڻEr7$喦=T&ˉŴUͺWxb,QIߪsPc& A;%=1/2yؠR|U x,hؘ<ڄǁy4 cРY!5"NE^U!? u{ZVN!7i%Ǣuk&^ 7)o%ā",LC ȷ3Ppw3 :*ϋ9}ޢm,[l NM'l&^Zl{^K+۷8BS|gGIy*La!o1tLC[͊$N^%_c@tUh? K=_|Wr|B:юw<շxQ|:sE!4i1\pH#FYqt%8/8;om_& |0U6 A.ζoF:G>`FSMeIWU}{X LyJvUůT~nQhO>T~Pbs#dfԙ,i3aanqO9P}6?kxq0] I[V%4W=c.S֔ǸkYfL! 7^1v) yĪY-%E vϯL~FC&g64тpq(/ӭ.D]Rk4mNM`|;࡫LgfU%؉cgzQ΅a4ĖFp@u$_$KA# > &W%CcZ:1kȾ|ґ SEZЇ%L+vW$w[GuX u6_Q @]r;NX{䭹]!ɑ?.}+;6+9oqĻv&TV&es~T!@klk /rRUE\f+OWxQOZ2];)?Z3 *' !ޢ}[ 1O/j;0(_~z`]Z!Pf"Y~  rwcr5q{zfM%^i@S|DR(VVXE]3d]%MeZz|+pV][D@zBk/2+cvG0%~3Tnf:JёFP Ve6=5/֖m bIlD{EqVi8$\j!Ki #ˠKF}eArͷ</aߍ+[7D"8}"W*)jQ)?&ֱ_`ivRez(5[Oqux)_WNZ>_H"Ìɻ2H&$(YCq 3[O!M%cR3>N{t@:iI{>_~JpF)2ޒe49?%[d5d&M^@H-rARGž%ctE9BU_Df@8/&S-J/g٤oE6SB>G#]mV(qi]H$DM5TYd%LְS1@("$ͫ|t2 ۑOt:8*˝_3f5"0 i9Hmi"aHO[`ɱ M&]ȕ%Qk#Wد ˀxyhۂ9 }y΄k~NE]FG Ǣ~~3[ءhbB;|hX)1xog8eZ{T~ng{ i]x.ƹߺTl/7FQS!#A& \$ٯ5I8oc}Xp:*jE %w6x>zI_C9\(n 1@!ztsXe e 5锑cۧ ](K5'4'c|,JUE5(qܿ>7>lm-zN@F+>x PR_Lbqm`J|0'E?P[LA[Bg|X:E!\vQXnIM8#{lYKHGOE/c 'QfM!0QlVaXM"#tWS$ 4: FuT "f]ږKob#1:^]-)~J(9~Ih$#EOL^O K=tjlCwf܍ȡQHz %VRg WXw-nu}|?r.JEKdIӰ{^lh$V ~jmK9r;bOȫ#lm}sꆼ RS7V%÷q 1#-ҴA'ˤ%3`1sـ0Q ]>k>;fIvfo/k٠%׋܌'m#DӛxhIn Jz<[gfl]ߦÄjXa-'~s«NroA* }"512)Z /|iFH.4]WbG{0]l~4xِ|,`$HxIBr+|ZZWFȠQT]ӝ`H!dEǝlwyDPd`nxNC6,glԒ'()XqՈWz^!(Y.?ooXY+;ב\$s1$ˈ}MTY*yO&-OeoQͱUxUl>5ucj% 8]2 .Hn0(~,J*"-/ ˋglJ?&|+.OX%,Za}u>;+QmY!Bm59uDٓiX"_9 UWjyzwICQNj7*v}Hy2-[O'/Ztef _~X GdtJIxӉ_~SJc qp4z"{"*#  FY̐ImR71$d~ẈPjg$6DA|VE1+kK[%$*փ]]b8|E}l.Tw"l*T+r!?&Gzz}&>1Qd| ReOne1G8.V_+ld8Zܐh^זHob@7W:x,G`BJu(m-=k_ 7-i?`2S4.Ǝy0lWgmB@hLWbA2^ARn W?"4m*F '."CFb FX"YŶV-a 0:~VRڇӏO&bLPEzoR>'5{.:{\\OfdiNմ9xb|8H 5aec E1 c~a=Cg6GFSTppN) gu9ϬPK{bGH6ɭCC\"'F"қzzj_ +<a"&FЅ:=nC@*RDeOIQpqmHavC$05d)+DD/ށh[Wؙ T9Zlwȗmpڪ2K1<3Z^b8̷,AA6?).-ٚ `O:#d1 (GPQŭ?oR 8@kYH CwP 6`#r߰L18o6y 6!sHQ_3U d:|11lS`9dqYA OsÁաM3T c64dƐ꠽)](K@0S#MX|͝#!]Ǧ0fʂ cidAQ#)w@-2aog%Lόwtٲk$%v(%⬦{_0TT3a0^%"t/crAa[mro߅iE K`w}!>;=5{]™3PNK6<fT‡g6\\vwz~jnqV PSZ2S3\`))(p˄׎RӠIݏ4lӪU) ~ZaFi΋^awIfyZ 3:FRn7PodFCRϗ)B o:>o%]=wlV/IQ܏Y-G]LmО+8B(J[~^2WH/3֕nMå2}VROW`)AiVU+yqgL_=<TBв||DXT|0Unop'SS ho?`C!9Q[6|-H+o`kxD_e.!]1N#(!s@)ݣ\Wnik)Gef=ETeKvg2> _v!k"! {yb/23:vV25Q@2j Eέ|IQ7M6-k6Y~v$a;lֵnv籦)KO*i#k21%gdKl.~lӻl,^|̀|}7 7\J=/f Z^AEJ^J:ѡY||p6Ɏ ܏qd7XχM 4'e"!fxTP3aP$Ku1b,>U҅xwfڦkKEgH6 '2?դjxw|!kO!ݹC$[^/fh6>W]׻B =-1ldU'ch QEɶrRDX2`CS.wPro1*?||lEmO$2ʗI22sz7)OxaQE7LY{jt\=j PO/wzUc7Rg 8\ʩRF ;Y3}"VD{*ve^+ C2ؾqh90noIa־bn$)M"xT!4P7ǛӚPF*~#vEIV2kJ ~u?'rTT8{G-t+(uwܠT($9kwæ z'vIUҥWr->BWA?Sص&^>,RhE<;R 94H(Fifr-tԂj W9,xX"ܩ8~UJa%cw} O~Iɀq;O㑰%1K9bۧxIQ86b'9[(I#;of{mpL?ҙtѣC$ZqwZ0:uh!i'P18 \w٘pֺ4|+ďMBQec儿z[ZBc- C-AAv{1#xٰ iG?ơy6ttTfBY/DZaCꂺW|_iݓ5mϷ1G>{'{BX0~ O6O;p8x}'8E W=D:m7nvw'ϱmH4׌&lDg~}aQ&E/Cʳ8Y}(Y*dmwsè;R5p\g3;{j-*㌯wYy8+aחp:Qh~<2Xӕ|Ƥ vO,no:7Z&"PnuD3kX^{( FPGJф,U3E&)^dBlt|+Ăkj1pܛmF$tF0-G4Y WsJ 餩4bJDt9vG/ ٸoK!:)yٛ!]n=FE,>,49JʇSTkٌ9p6@:x;xHQMvgZuӝ{M~5ndZ0Xt %^|d+_&asЗFc|%˓5N2hɜv,^LUu~Dwli ==eX^˝0}} i=(ղeGG8~8`*a pUfsjɧHsn{ Α| w U_v1Fu%)L@zn[oBjx›ΰ=Ѻ5qLoȧ%ޔ5țG͞&()~"1O2ᑎ5{\rmz|.cpHm-zDFD/}Q  xOEtE՚"f֔&qLH̊b5&Dle"°HR;}i>$uMf lT >տGLd6sV )iyy¾%\` ]ѵJ;oiϧ@O xſ4_&Uv5)ydBsAƓE_ % ^^$ o!Z&6'JGMĠXԏQ(Yu/Nk/,XOi3 j {,f]3_zz:IJgߪ!iFMB]_k)AYg x~ .x;htERi]Q"^iT› tS s-"+G⭡g„'Ȼi~`UE5[creFty4&Y%uwdpclʶaP$3[<*DŚ+9rcr f9!Zpa'0+t  \r*b)iLHlĺޑ5n:AW EWV OhD 6Ci)E wox2tM8 :9"1)!~f@F2oʺĊ#ڶ7ehV(Z ␎]&F(C2Ga'Hbb/G4fNa AZG=HVn{dU?#YjyN+b ܈=BCKBF\BP\1ePa'JFJ 1A+gyZ!oqm3Uw;.akQ4B" /NL;'qӴ=W!U&mSf@h^P{6MuqFpDkgy~ #nݑe]^6B5 6lS%EEDT ̂{fk5hMH{Z{pb)MKGLT%{ZLxR@w=)u Y㈖LJeT9QOe/Wal!շgl䳾uF:"n73`[%o,s0Q+ܴhg *!G#IX|'!=ڒHUK#v O67qR X[^E߅:dիCߜN\nĂ}vؿ\fCn<_ܛqϧ%/C{JSyw1͵Mk40c$\ʈd ^aL&a6=mkj:tx U6x9T;Gyw i$Q *C<'RǔI~NK@Ke/%2+|[3f!zO r58 9n6&K$!T (:ac&_ԦS#$&X¿ 8|{ rY8c&[xV;oIOLiȂW'-`HkY%E ) m:4d܇R1Q'nj Lxz_3WkOۛ+|i\D}e!Š)Ȯhdx] TϸD1\w&u !$FUdqQZ]Fw :Wcj >N@1"y%JBEGM#i}fJp 8s\6;WaPԍv6;ݱ_:mq`ŚIJ׵V;6BwD莈3l%<c4HRGʏw;G4N1(!ɝVLڻު*hH6ZMϯ{wR!B˂]7ϯ]Co3&*)@F_񉸿~O@l` X_=`>dGK89Q(%_/wƸ hAxv~&x>o[3gdѨze:rυyaghLpCVT7Hni<QkΏw=!XgIѕwZ~f@$|qbzh|f+\v/j9Iq #̰?-wO3؂ HtZ+x 1s#b͌ KO[wRjaHpBͨ<(Jx}Wv#!Bu [a.H* קHn& .eJylP}% `ާ~jMd|'na h$.`Ws ^X:}$Ȋ}sgO~ixp;yV# roCGjp-"vzh+հ -t4T'˱y>;עiv0zs;JčrvBfVI$Է›S bqL6)"5]>i+OX EoI xO0~ɂ{LѨֵl#T?4j#zR" ߻ؒ(CM9R 8WEa.WD7+Pd^6#κIY NwbmAZ(!,i}epH΄ 7gb`ijbX ^0ϐQ  HE*Sv=3AU H < O \  HZW~D2Nz/`]WhرMOf$`d<+bQw";$50쳪N+ ^t4-w\Huϯ@ * a2Pz!Z) =ݻ6Ά#0>G eQ}1yφzi[D57sjյ^(ޜ0jiA=27H<ylrH[ץCn\o?gmP)`k#`UqVR{Ӻ:oMf{!TG6E,-& QU#tuַ_ LZf*s:JDzadf@*eEd,/F}t|EJ5%,ʫGշ(Wˋc:؛񽯗9@\n.XGqq5sS#oj}F$y*ermjosW.7Opࠚȥ8 ׇn@@r]`7睭 ݚ]B?*.MNCO7BI0Vn%S|ԟx1M~G*}郮$+VY #yx[W'Ǫ,#0kRa}`rοO´?#"-wJډJ?k`WrkT;$Hj}b:*qy'Ψا#.^DT1jW &4iawC%B̐ly[iYxɛd0Bܚq_^0}FA3,8Fej+pT+HWo)fvuߠ5Pxi%sk#hB;Ş-NvD#5<s󞳯ACj"al@1Y8G,%@MH ࿎p_ e^uQH$~=i'?*_vwjʚsiTvau>T6inYC}'β@P$*NvX9> =HSϭ#Am7cAZ$v|g;Iw,VWl "VÓce`"mA؈']hZb܊ln/->X d!aFe[߅ޓؙ[wE5{~~Z bЊC9G@U}⨶fc7a]msȀh2bKvFw{{ho& C\\8:At/wvSrT GJ>[q"h,G@H-Wy9X><5H`U.zB l1gɗߛgyS|vҥ>%iZ>~Vo0Qj;L-Z-UA޼G’A iCn<!SwŊX TU=EцU?Gmo!E!;1N R̬ìσ/lH1!D0/J7[a}~:d?;3T=z|%ahXۇχO*Rzb#}/~x~f"zpҳ3}*p1RXsL:p=.Vd5l~+ &框c|L$)1HdهFe*%,ՠeB=z*#6z+AMhwBKIo'Č&B9w>]RVX;udSd3AgW|c}('9[is[4gE!5Fq'o)Ƌ窫 SaQO;r0oq'q`]֧rpT"fpT~ɱ^Y=UdP|SFgNI$; {N^KPؓ"qnF^juTfѸO"zK2W͒/ShlQۮ'%GN6}!dPqTTF+u:sh&Oki}f)~`6"5R2]9[Fwlɚ"g~2G6⯠v)HOn%r:,.hhs(ktJ7fo܄ *tڢ޾ ^s'#5hN8ئ{yaOFuZ>DžiL X \(9:rHƥ`yzd+Ν&zLlZl6eeF}<‘J ictvjȭTIQo¤a"rNkĨYhάEr0@3wS0(>0 5_튒]&vbMc:0q{>pj8OXEϲ!|I<-e&ȻeJ2&= b= ( Ź{<߶)Y&[ DL@kcw.,%3Q%LãEvF- dXXwe*n`LLB7fZ \O]_d3sc U1~ɘ}L.lJWo6=jVٗ`<װjٯt0!='¼jXIbH?!,T.w$c].>bjLN!V0&%k`yv}Ό~'*F!5$ؒ==bw%OhēzmUm#L E+a ﰎ y^_Li*muiSe1kʾfAtboAg3o4\IWu^f|RIa~++tՎmA xcsZ u͹G:__O:Z"6cxl5y1Nz#Te}Pm]Fu*k"29|!ESJ3V#hs⢷K5i&+XR A5,G'*K7ύ^X&Tsu^VW_GEYqmrUjF}jSKiQxA",@'@2ju 1:~_TukTLG rYWN<:& }*WȜ}1hI\qT6fG.K Y&5%\q*ql W/%2D:.X%Ul]V(l[/rD]tr~xru^Zb7`pss9zXe]Ip> stream xuSyQa"AXHx\dDg"B+1+|&WY#]AĆ#t rt&TA>Z4s:¢gBvP#X4L,SB ]3i̜!>@͝[q?,fδ6Ptw'alPXp+c62@gH4Lx`Ѹp;џb B;E`B !@5|SGa5 V ku^(o>H0fn_T06x)"o1WB;Blľ  îWALd3Ep?5wO-47˝dq\xӽsiiWsYw! 10uL 2)5,fμ87 `px.1"`P @7C0sN0aB0 Q̯4xf.=eςAp+P/AIg'ϐc0nYXm,Zn+t^fD6r)m`9o9L{c" j湥i0=gCT~Ф5EkcϝWFWO;T&#񺓛Qz|%1͏(u#%[҅S.x^Ѡ[ꨂJvU}E*&6޼d(۴dzt̬]ӣ뫻5S^ّX}Dkm60dx0t~zli^Kɚv󶞆{k'֩#%ILf=?x$6wjVurhu(237k<]iu4Mтָ'" ^&?S^PZo#fn=q-ޞ'IS 6Ɖg'v5+:+E-%F#/7삯O$1w_H\W8PAݓҨ@BT9>2hZJ?U7[qf*L&\꺪#oXl-Aih\Fѹw)}ʭDءx5{b 2+: M%w:~uxe[ؤ=j*/ާ z:V]q[e"Y)sa@&YDtd[~Lwp[:eMY1uX|ƹڪ~9qluL,a$+o[{$mr>[4|x~p7>Qi\XZT< 0\8e@<2}llDUޭ\Q=D-)p#1ve9k|U\3)J)}AؾގWuЉ<گ4kli3[}!FW7=81&A[%E R9etI犓%?Hd)g֍{}:drވ>~s@ҞhReQ? {#nq69WxKKԇn7r겜p=*VmI.xu$ #c|?M>ՙe:Y`{Yt2C eͺiۍ{6i8U捞5 K֭^]%+ ڍ#VE\~E"Pk~%lLs+ęyoj UVHF`iͶ8QO 6kKZ$M sSC] ąhv~B1Ja:`:>LcKRa-4&w([nR(UK}5*a㧬'R4>o R:`4V̷(2語rnxjo \s͓T҅ اPPhy`#qRãvEjA fR[SiNuC%eNy՝թsG9޷h{cdE>!Gm,)hi|-M7Q21dՈDZêhEm 쩒\h endstream endobj 676 0 obj << /Length1 1626 /Length2 12638 /Length3 0 /Length 13480 /Filter /FlateDecode >> stream xڭweT\. wwwwwiq!A;}gΜY3w~Z-}zk&'QR67J۹330@&* r@3CON.4vۉy@3`';x:,,]T*Դte0daxp;\>BU@%`D$T Ijb2ȁLv@jҜ>b ;@SЇt9;<@ 'c;@v6f CL Ȫ$&..v}f#̇d pz09;{~3_N@ c'3Gu_uK6{m@.@sxf.-@v͊=r3W܀N7ꯙalfog 03*ػ|PXf#W#9/>{h Wcۏǎ|,c;ǞZ4-֚1wGK,>hab`,)\L-6[ngt?xzf&өYL"*ٿo JbrPc\<>G)fy++=3}`oR_gyc'@n&濫߿NF쯱Qu136uur Q?<4_]7 JLwc q(mT+*K 4z ahm_`ˆ7xOCF_AI{hP~ΔA+ L'?[?ƗGd_ԆX̮M`hugOC#ý79pؾɧ$I.FN_8]tdVE͚;2ͫ7h2iv~<'kG>)/K:B k )~Q{iv ?|dbgakC8'*`gaO- 7eWx08vr_@igx\kULj7u.LSqyQ]oA'Pk}6+~$-|塯;^Ǟ-alh[To/2L>|/ #" d 4|`-OXa0ImEK4pmnQ]}gǔlq-ϦZBK;ZW p&Vt/u[lRt%̊c?u??Vs@v*;ӻ sp+'sٗY1qUf,Ecqc>D=?X9iz…4t߷Ґb{2 WHsа2[yrsp zFÊl?ߦX>! ƕX>A%js1>9ې % ̉9x`p[FĕYRѤ/ѺءDTT?PWy4924=7fgCNVw~ӹ֠*t OVg_NŨZ\] $k!4we3s?]]`u] Ҍ([hذ`AL!HT&A]XI$:xT"1uCa !q=rj0Z f +̜v8BY,:܅ڠQlMϔ64윣 j7KuOpJ.B3FnXKeCNgη&󊭮ʼqJ.E,?a̒m#FcTN2̧nѵ4Ԟ$up=, v.^C|jpbb@FeB3-S|L8F/&t;ݲ;[ۗ|vl}f Ii'st(UŬCē4.k' 4QEn: QJ*wi?:*3saJˌV&s{\Q+V.XPtz*RF&޿$Y.d0rtbKA_P*՟ o^˒b!ٓzuy+ّWEM̀&≑.P+y"a.=ߦ/X+IF>nDs[v]ި{H$@Uky~HqFYCXas_.Q6f% ƟDDZe[Qd}7UM FmMuV~㩣Gp͆5`np)xm:{E𚞐deXQ^԰]x@ mu\0՛pk"P|jl~lATWIX2X0$y#׷/jC$,7^NO҉H7L>>{y`#vyc7dxZm-BeFiAhx0~R/uGi BRhbLSyUn}Ev*rlڤ| M7[KKO?Pd*=<}۹pXEr1E+s72J 5d]yϓ/bU3Tv+U_gqn#XkmN֩o^ݍl_xڨt95U`z&^1f Fe:ps8x-:[8ٻ3,_FJjJ7"16k$hƸJ=q$2Zb\da'F1RyQ$"ԗQ# kAaQԄ-ǑU鲦a|{z[\lm٩+WN%0sj{w:+N_nWy䨝b+{PU]!4RեbMAA {1iN /HHTH9ЃoL TP"0wc3S|2'$uS}ɋ_׭(˚@/5W|214h8W9VcmdW6@=]Ȣ}?<~*7.^Pg wvӑϯfZ)5KK|Fb0B {STmA (FE>P[PŹo}ҧ{??T8EUYQ!&`QL)&ׅnK-v*Gv9T]DuT=nҨK 3fh()\py1FͰ3  'a D 3)w~AǁoHcH(|;N a1j,jF }ᬮ&ycx=) [A%wCʫRLugtf4mvj1t\z䚼ƭ3{XYs8mMVBaw0vP%Uח_aontZCY USSxTǟ߆# ГSuGy|F"S /v;*)VmXZ^@=ˆ[4,u,ط'E?^~ZS q?_!Gl9G2߄\{_YpnTa}6fUXy \*aİ}@,oww DLIQ `cTL nW9+Ei/8`Jda BRAv8Oߓ3>Ls0I0 'XS^j'$W(޿6%nVxL=i.ƃ&5jD9RNX5P6 oi{mNLrx}kuʚ`hW$L. mw;gOtWd3RpK!25{)t{/tO09QRL Jةs10ZGDPO{>lȜCLɀ.'5DE>M[7m2e<Sj5) Ij5T]?:[[Adw~/Aaŕs"x7.wzy(ץG:@LCw:]N!@U6`0w {LdfYq,/:1–tM uhWf0 F\H\?w,սrFcRYD5!Y:*v}/2 t-{H2$+Տ:>*6hQ@sulņ18@>Adf  b_DZ_Isx@alj< AI`&})SBy1uwn]ؚ}Q@ .gșR,籜\15J/E˺ŠS;w.Ve܅NV< pZ ,@Gr(%z`HW8+ίY+B ۜ3VX($9"S{{`VQOʝB)T4J*rWF0 ~˼ڨAf}|<3`@(ٻSSr OOj隐H`Y(4 |U 91Y)WGf>4^V`DhQӐ- 8ǫ)FڠJ&5dsWuGݸEEbԹ)W9{!6Sw]W^$7murTr~Xl&z8kZ2w1M~;3ئǯo5-ąjt ҫjQRES#\-rYzБU^q ݲ" U37,5v^+%`nTT <';8T#e904_>gZB,5s$I6N4mz Sݫ\޴PUN(^F'V)Q keg?+P}zD-b+mʸݟeWAN8W|Y^TC4$5+UW:PzӖG{SF6 !ߡf9;Iy0cacGɆ{UԼhimnHwK0Rr'bs,fg>/4zzpU3Fk[Y$1*dAZGq`sPN kS)gqBl&&~0g=WWˋ!weҥ>3'k1 dNaŸ*IwlaeI(Z4]ɉJ basE/R!,LXCL>>c7YTkBT}NS畴Mw'|ǏW:Du8;\ W8RN^^ 䗵˫uDQM?4Z^@^zf~J 9Z΅~n%[ʸAيp"Ia[f~ԠX}T7/QiL~>DQG:0XSH/Oն6W=އo{0|b Un zDnMgR 2ΌG%S*g\]a2|,D^(IJDߍNT!7I(-2}!FD[˭1bu~4'cz MKRIc:J 2waAևGē}4/-V۳BMJ4z1]{<>v;9']=)Mݤ|X pYZG0\u_&.Tx g4Lm-T/?^*,ͩ"xSKW)=oq,ݎ+ݾԢhȓʴi8G/!zٓġsk{uC XR ?|.EoSy:PaǍ+9jtw=WuT|g0V>~o#V e!F JKU.d1ʇaݔdr svrBGkeAyW%.̸B'M@vnP3t|@AO{ukkDT&H Y:81z <9X/g|^tO2Es!MWP#^cV*ձLNc]#2,N$axjۂprY@xe'^RmNPZB_Kn|- NR>޴B䬼Bs~:Q$ *CX t0=zbx~uR8|w/eXK>Q447_7S=F5]îR/j,-g(RrBv(x/{-ܻ+[K:d7YHv {w1L^P Yy C(y1zd@͔ݡPi5ƕ?Y)KX)M.v?غ[~.+VX72<~eHWaT޻\']C@U*1m/\1cUƄ 3ڪ3yWHW@*B1(9-8niS'5`=t&d })LI=AYYxڐHVO2HDrT<#◥k\ ѴJ U:lVfTN6N;{OO&9&Jxpo+H[(D$ 0)T|DMJ2|@"(N!frpsQj]oLP*KZטPxppf4]PNDR~,!a, [FII]^ohfZ"7,ANL wۨO BH͖2ZԘ NKH_Zja? j ,1ڄ ΤOBsR?+X k,}A4; H/Ugh):BjAG)UfYO2*i?V T^8~51v0=HGKs4PZ{Ҋ zؿxMVm"c 9fh1m(>%qg\UX~ƠGj^E9oRqNMjwEvB"|epff®,j%;XgE tM^2@y}byӸ3e[QD *ʗ_ғOr_ .f 4t4DS=YZRAWƂ ͥPEp7djx >o=|ty(?>IKUmR{I:m0˃60z 쇵E*i7~6J1hgV,^ w_]P Ti謝N솕4d+(c0Fgjz86>E%O[BW>k5#c ._USۂGś⊃l!>U<*/e T]K4*ߚj 뒿VםD)ገ!.0nRyAR8b7ZK"kb6#SRfHSɌN%C{1 וOͮͫŸ, H;f;]&ٝ~2Fzij~4PؔNw%S3$h)\,cv#9bը^&,ly0R3J(RS(10AUѮ;d iv\>_\~24'GR~r*lFAsȍgKS0Ƿ^Xokqxdui `,B; y>hbh\`Ll8IcS$;t& =/pQCT!`zrj 6#Nj~*!OS*')q_'D0NWCD/eѓko\Kwy?p7pgDh`kڮYlPU8"`Ad@,N/~yG[Q=5d!I/Z5eWϔtذ1OS\_#j }O篍J\]O,B1Z^C @:]ƻy)^cpSE1;xgj!&C}RCߣE+xp |ֶDžE*":DVwVq6,J?MsWK(oe&,b/W-c/hn~q4WXDm8$ [XtJIwne1tH(=Tv|O|-A?72BV<"6qqgQP9ȟD\,SW1tv^먌0eϘq;5T a!Is2$y`fTl{ng;Ο -0'B%>ݴj>I2G/oPxgd8 :>Xdbok'B>NltM;LHcuMǰ/;(AL Y>ryH֣b٧MDÇxyM=K[[O@o|r ' c4{&r{׭>N6"5(=?)Z7[=Q "i ze( Ul+uE:hZUX`#5)':ML5vnD76f=HK*K zD$#-m,3)D[`*~g85KɑoI/TރԜJ7y1Gx?Ur.RĬ;oNP-T3b?]o!Y6ajK@[ ˇO@D tfY~x꭫({A`'f$HpԌ\{Bj*œr/Uo>e.>asW0W,HvυQ 2"=1wS:K*\T\P}4\Xk%a;VՊ ?S#c69$߲iI|Kk 7B[Z:#;>H%ׅBGjZʟs5f j<{5#.Bek`1d@'ρ/U`z7]J~Xd}+ Shn]~N& ՜0>e#=r=W _@USS)s?[;Uc'||_p('su>m_,66^f+ZReӼi5VWB|*zokpLSid9*_5͹yʼ"4,O_Uj\ߒHQIr0#,iUŐ3#C?^e\Z0scfk4F4c%al;wBoitnt:W-HBIn v6k r=6*%ܿ%z5rPBR2eAeND? I60xMոG2bxⵞ15(W;)Va[/ .MS !vv^dT"C$#aH ~  7 L6ƿ_ k i3^豓3{>dZ&}Z >dVgVa;ӯ(No!*7WBOYΩ%M ڧ9 UfǞy0 ʹB `"nZp{{KEv݂MAͣmkP}؆y㜜dۓ 6JrA<Pȩ endstream endobj 678 0 obj << /Length1 1630 /Length2 17714 /Length3 0 /Length 18558 /Filter /FlateDecode >> stream xڬctf]&vaŶm۾c۶mbTl6*y>}zOk⚸{lrbE:!S{c =#7@YVޞKNh +g#'qXۉ@S( `#;x:Y[(Ք5hhhS ?4=-_܀6@;׎*@ 0D%j jlci49fN&vLK`pvXuzQNs'#;=pXڙظ_rpkaWL7t0r'_5쯥?%Kp'1`j`c7_0'ligFN6@g0 _7rpg.@3z8&1M\6cgVL: Q33T02]P߱LG-FB%cdg_5N&b-BvagYhhbb03۳LN6v:&FS4vt+ my ͂ApQtFx1s9޿ q1oB ?rF.Nu32Iٙ؛3:*.Fv Q:9%_ oq@e{LzIQ^&PM%E=\UuܟKgGX6{ҀWT}E[4GA ?35bew Տ&ޡ;X`H݊0L1;QA)O ;ħɋ%1K=#Nq4to2|up^iըEMVs[vFΔyBd%z(l/~\Om\dFUZsY|};:{+9zY"mURPrp1[;,TR%SIK=oO\)Z>`2eO4VŗF5c!\n.=ޑQPP*<U5N`,mKrʪz~x Z % ]ꀜ7Ur˶wT>]~kNWw[₀ILgӰd%H ,|kҢqPs3Nn~/(l5+>Za8bG5BP=9oZMFOv4Ysa-Xꞿ&?XJfAC4[RBA~ &AGkow*(\CSTFZEI-F(R4~Gl҄=P\#GƇF”Js_T6W60 ԣY#HED^END㹆2T $o_I ̴@~1IEՎu/F6~ÜϊBkoP̎tL^/l~ۑq~Ej|;BVo.'=V%oS&MMm؅UR[,2%gSM' OڦhՌq8`ӟFq>$F?85k@DJH $R W>Tx9'RxMSU[ڳMU%01ql|u8n!ufdMIg'7W:l9>pAֳ.Ҕi1ߢ^ܓ0G 9% 66r}3q o/M7=SVRR%8=:F&o;&{PN-@苹&>/fvw,jv_.jR|KD$0ijEWÒG'[t+'%SIU+|dBWz${ +٫ua4菻b?mmlHZF Wwg#F'8ֻAਭw~u+q L'-X9iIΗdD|H~*I:2MlxP1vJ9w~{ \@mjWU:C2؇9jduڒ"3g3] geNrSp M2 /;V%nϐx8E0.|svfmS#ar9X:GMR9_=ZRi3vGG ds>:Y^ H}}88?SGt ἥ#^YJi>Aw0LF8'/C9Ң[W5{DK5~Z꣔IvPq+^Hj2Dyx*]W+[a2³[/K#?)+}`o>+169WtEFwu@bM6I+=Jn'+HbUjpp?˨’̀HzHkR 1zTڥeCBZu-ty@h)9u2;[9f!Wva <*3{:Q<,[4'|m6w|HdVWsL6#*@ %szqdf HA݇HM'M0?UzS-XfFC#[ ֣ Ya: '3,̛ePmpm*9k89%Ry*{7_mӳj̩$뿭g-ޖ~!2bHg}0"0HW|5B /e.Q#{DdrL[wzX"_ +5FI{%(Ԇu!!Q?$XHzkJ;jQe1e*nRJ|}a~1>e=RMvz497Rni7Ձߵ0PsɅЧj1j]bqy{cjT$•s%J$z_ #sf-\}e_Pnd[i'T)Mo ^'[QG4nq\Ljؗ@hXqny\ǣ_ ժ8Xn6"ZJ#ii&ZT9Y>rw%A _x/ ͹N7-b ;6a i7Kړ6k|6Ql?&,WDݸm#q0X-"`*e4QEwbK*،/?؅r<JcAdNA[yOM'Dm.Զ&5Ev _* V+7)_L;;Z݃46Rh Wh",J5 S ]ab6oˇC*h Q6xXju'(g'"Vk(cUM=G,(X5)EM^_~5?Fx4Kw+8ɨ+6#z=:ƞ#.XG8oys.CR, N\/>rÈ1^ xb 'JN9-Pͽ?+]h|@J,KsMR1 &7r;7 N@@UUWZQFF@Zl5R"xѩkUmXpmuoGb"jiDɬsz6$)u!ť$`X Ƹa%^mڑ~ef2}R7sZEt$zőIU׀Ul\OoON4'/Fo"Òw^#&Zutϡ3IN1#щaHz;Y4^u: .U3=` H z+cH[Jx8#zث1/rCg$F#-֝ ? I͟swsT= 6" NYIשrm-_Y˷>#YӔH}u//PNm}*b%otQ:A#cTOⅇTbROp(|Pk7cZ轅4Fʕj]Q th%Κo45W-zuCQe9E!ijBk<@(E*sVx{3m5B]Gi |aY8^{ua-v~jHϠ*ҦH{^UٱjkP;` ;=w&;V Y@ karwClgSBZ_T}5cYǓnSĚfYo3'NDc< z-2 KEi"v}cѿmWLN57\BtujtUgN*RW(W 9ri|YaUܮ?/sfWz"NŞVŵ;++GCFvjaMK7WI9Ev!#$O[8 x[}JQ-/8O|S2+TKG`tGMWbZ=4$@};%g⮂EjWb8&àqd\Y{c DrFT^0|<\ͫBp!ld2t(%W$䁙&]etC󌨅D臖 x6c)T)\ءm+҇2Ŧ0J/~ x՚l)O|z3ơNpoJҕS;B'-Z껈9L? :?ӄ >0yL8 jQ F" t"%8;Q{S eaNjA=AݽRD< 0`/P#(`]?d](kPQAE@T{E^ =NP X}=8iBw:aЈcHdނy@W* A["6̉7Y/-d / T=xn;yً"`,^Agk2^@FLoi9O2fOn>K94M4 E!k4 33KJ80FB^7ƔB5l{iN>K{#j*8wFPT(uvJPrCW[y#F"LHՍTR+/b.ً~4j}[@$|N#/u:Ƚx 3|xQTod.OxIRɋ%DKl8LG+sHlMAydOg`OQU9KMFP!yejC7F세 (!i6Kֽ߯VUǂ2307!OF=sa\6qkIM5` !ŬBjEEFyX|}K28Iջny9H?E5F`K &\[ԈRhAaP=LFߵMU0{oFB;zHiX^? | ~n>qQo3i[ÆU}(Ec#,PwAm-ܺP1Y8wta+&QEX5D*골ҭe$P0}` 5'MEd 8N G:FX0\ NKK]6_f -GӁQgێZ"Qk _KD{iIfeǮ_Qx[V(7z$@w'cf aGkI]rDJ U1\"*ˋv--tS2-1/gpK ܎QoM1sa!ExM=ui ,ׅ[H |R߼B 2evlR)}nD~̠U.L>% g١OmSLG|oFH*~=S|J#'1S̄-huzHc{,$`þ鞴%Ģ3K頍*x5 %3'9?Lךp{ x Zكo~K W4|#@&0eH%E:!`)p,mr؝F_l$oIz^RYc[:{y-PܓZ)2z#1U#ԱT5GXz}ŋA)Q36PʠOOK e[I2G]9 v6rM ڒ*8^h߈&Q9B0XQNPR9h/>cx"h9=5yH|a^bG2i)'(XcJ[>4DSS56!:!#W#_~O1h`a@e HBdӐ5f|+RN8rX,MRtSK p,`\ .d)p#&z) 呿©ն߼Ź \}{r#6=Lg[͍VVH6>9,ې_(8YO[ݍQ.efs]~Qh`/hH7gyu TtlWIc̫Cnߡr4IJl /`઻sUWg8͘Pˤ@ԏBWF8zPLD=`])vhM'cxFJ^JK81fhBȊ{ӄòE%K՝sz*4ڀSEbp isK\A,Yi)@8U,e%mT5"{tZYT"&cqWbRzDR6 rV~V=̦PBՈwU"bg@y؆l+gyZ[dSY%j`H,㋷5Y2 'Ig\Ή,L'\[ 6)y)s,DGI&Co1Oveg\XaHs=nqYf]b!W2IJ):=Nǚ\8EP{1dئ;t.!phQGߞԅTu XSاj{ɰ$Qx¨{nʃacQ1' INEQ_orlӝ}QmwS©CwdL2̛vT)3$Yّy,QϞ=0'Ay3]{_A: -a0LI5];VZ"?Nz#CYR46(@/o8z B39_ʿEJ@%mRFVCclP.Z~m@ZZ JҭhoWvIȰ3:Z$!"PuP}c;l"I{ǽnv7~F,/JT_8Ʌ/,ogRiqrjO21B ?12~P|[p4]τM¨憛L}T aV ;l͂8z!sk0nZLPH&JˏP-]ی T=AoT@ni%=tsTXS,'Tí: riJWK\t;"Y9n\3uOL 2\lVv!Q2 O+\j-e}k Uԏ'ۅ;Đs_BV7y$U`)֒kkk/L[>WһT]k9 q1.$˭X6N}%$~OI[0|o9z[ecRC3UD>w3M})şyL srSgK MvY 8{yDRͧT٧e8Yz܍sdOBf?12F _`Q B&n~@hp4j1{AՉp0trpsAP$uo<()J՟xݒn ޘ c]RBU~Q" *X=G(IE\WӁY%_ ( ɷ !`5뙡AMneenn ?^^%bL= Ĝ&f,H;I#1#7y74hZndő 8 і~MP=vp #x_S ړ`2Jqrc5چ 7]|d=].kgc7TeX$>Y֜d"準:T$̰&fhymzWw[bh]d6ճ<p'o6t3 }=OSνQ?yU -6g({A$sM\plY5=PӍO eҒl򳻑># :Xޭ<-·Lub/ ?qsX+4X~տ.)Y6hRcR9OJ%2tBF!3ULoby]˛nמiHg|6AɤZ3b:dV_4i:RfFv=.;'4}XON1t2U\o.*9Dgv̐d,IF 8ݣ21բ ]Q&=kWҐl2R1roo)w  ܼv픢#( Cұ?ˑ5p-$9ZX0c~SoPI2wk)"z^G8{0pk|5OTUȾ\ԑB,I©3X!P#(lTΙ5Jc@DGZ3i40t=5Tn{vہ8|U=3,]yWܦ0c z1hz2ejP0@"Sp( ^h!g83Zӳ>$z!7xelTd.>`‹ U Kc U!ٱ/T^l冼 #ʗnʎ\ˡb@ qƯWqbZ R^ָ(Y^~grO4G}oXEQꢆQ{@u/|7zǴ[}y9)}nT!_I&%sPhnזe8WNr)=abFȕ$h|v;>oNg\Wu, 䩢Ã7X}$Γ}q+sjAKc J/g>'v, Vvn$s* 2C0Dg'N)Dn[L2$SܴeM"lML 2QmeG|12CgYVGVH=S^?S+zf7uBaN}*s xi"ݽs>ډҖop/ DB`+w~m32l{tMA?6Ǡ"<~|(S:9}o>h 5+<ˈO=M?>Arń 婂MNJDZS2g?S-oϧQ{T7[{RG5[O^]I4V4ԝʦhZ4SQ %mK).9}JxWlo) Z*b"9*P?u乇MmkV1_x#<-eBl4ٞahyF?G-30A#&ʍkNi`);p-4{ˁѾ`oDT QfJ fH5S/)='`>8G$@ܬA8Ol%1F`t,ib:lHW움^͚ӑBJ0*l^|qP*sV>ŗeDs&sU$+_WCF,i( DZJ&!mԬ;X)b)1sV m@R*ϗ#A㽒6'.bli_[%xd|[,C{P5+T&erj=Y1ցmVv뒂RByE2 *J껭`΅܏41{ k;=]D[+D8ʺYhɹ>2n14aT,?mhf0 {xi9~5??́EW p^"TrR0r#:O;g+Z*aᖝc\GJ@lݬpMU 9WE!]'7y*UAޛPIłDȸ%z;/Ļ䶗:ZUp#G21@$b;-\^?%`YWy{y a'x;05L~OMT}"FyAPЌdnBBJ4WBtgʎ~qo#4nPo ] =):]AB&?Ok=v C` _֥D%?W i(pȘJ#<6k TOR榲K^I.DlGA0M^\Mjꋢ`ܗ*xdkޣc8EQbO Yy%cw@V|t lwd"߇WLX') P7rK%[0kTj0$4KoÂ-z+Ҫ٪y鮣W!Pxg&ru݃ 8x*jc3[>Xn*+>Vko?-ߜnTY) (7~ Ljذkn kU1H[z= zAQ<tqqQs8?~CWj E߽6jX袡ׅae79UFl_(ZX} Yag,ZiU[rLtW.'_}7GԂ閎&뼲.䫙uT Y34B}!b~<u‘x&bgh=ubPT%JV~%,C(( |wKmC6QO(٤ FˤZldOSԥ 7#+OhM'_M$0{@(cyӚrt"&%Zr[SqF745@Hp􋹗#E$B?jk$ f<'IF83 Jy\Qp$/SzۑRi_S.K#QvD;WꑥGߔ73VZֵم yfaGxtm`{E?R&D]Dd%leOpٺBJ;wh4Uk_e BaFۯ8eJ! xN-gk T,(8z|Mfv# v A(Fr~ŌXe=&Ks jGktxU9A8hP?gF&[O:)GdSO{' оIq2;> OGIH endstream endobj 680 0 obj << /Length1 1644 /Length2 9998 /Length3 0 /Length 10837 /Filter /FlateDecode >> stream xڭveXے5NpkݵiݸKp,Hw !$$hn9{3gwڵJVz^ϐ[R<|WOoS"mr<م@pWXJ @@/.. P@\]6cSvNNZ\8 suX>|@' _;@ (ꙫTu 0 hA`x}!`G?xa{ >  yy`OW p=$dw t {"Ӄ0+xwp{0'qzz)/ ۻa8' z?~"z7 ^ g{/G D;🪷B=u9a ',~@SlgW0YQ;A|j۟aJ8xu <> [_5OZCi1%c<Ϣ/>׿6@jWQt8{? `ד+@@d[vnͧ%}ȟ^@˚Jj!ٱUvu/x$7486H=X{3AGEK,6e9SZ+("|&k#6h:0}ž1]BBY/IYw.Y?~i%&=YH+EGV=fZKn@uÛW*1Ρ /5}bJd*i4tPߟ?hvϝOvjNX"@h&q*":Q̈́O G$Az\TRYY/A>K5$Nx0-tBQ@C'iWd$-R|rrnBɲRHKͤ n?͡f$wjd!T[lHT|takݓ,;)k7Y'sCrMLd!B,vV:2s{E_I.HY|d 3FŻM&i|Ae籫QkH tj.WDz0u?xdwm;43'w:ƟݴӿZ3̿ZAr>hy ).%CZLDbQn 7>~F˗Zyifgo#c`ZcVR'gxt  _$"=Ay=@au 1j+mT[uiokn60[+Zg~7NL{ǵBeL *]VT7b+F[L鴳+M˶Ѱ!HCvB1'gw?D.),= oڞ7p$O@&3E{Jb/ 1%EP,]/S{Ǚʂ_"˨><`m$/" 9vkVRYj%'UX1_Z_݋U_ ) WtQmxH9\Q|Ib^/~Ә1"E36Pi9|F*08 ZT@ +6:upC7j.GsvLNüw?W\Y%7IoJKȖu[,Vj 4r52a_Q~J樭 Sy\%1~QFiEryu7VYzl]=5y3TCyr s"^7V( tbv$s}E=JYh&srfBYCyf9A sS=ACyMfC D.f~3`12Ԝ6.O D[7V;i> {<4HnؐJi(b KY~6b @X,]Ӯ;]yV-W"exX*͚Cd$5Lqۢ4;W""?se,Lzf(^6Mb|9أ# KwTz_#U3]13K3RhR{$+ohh;X/{F*GrXZATVބ{]ɥZwtt6: hظXۊ !OLjߔ59ZWݵ#קT M0Jԧ7~p'90]{s#.%~YTI$ yW<-[M$h^bF!ZIDH!y(?T:W҆}`Omy&2w"yMq0`OTT@~P̛耴CƩN&l[vlĊE*Ȇk OeUa'[Lv;WU7de &Y֔яg]k9R~0?Oѓ@C*x*r]N|q]Zw\hF6Fcvj=~j9khin:j"$˿**%)I#4hiPJoP_Ϭ 2[, }i~/`7LEGQ5 ]e;ݿu6m)J,C>鷩l(@x@}#dhHYT?-itG.]!&.h:8OuS`a. k}$*EkԽi\g\գ˙9o~(R(HG_#Ia8GO`1]sıU^'*),EKm9n ]8hfr/=| 7Sů?4Xe'L쑉{!TNѳkD7*q[!Rw-a*r)oǾv $9 MJf⭪ j "_ P} 7EMr RX>>|c9wD,1zrE\{O#Alzyu*e~yCzwj ͮ؆.pk;|U4_Rz\Xˮ-Z_?6w._-Ne{ncU9.4ۮۡB,g7/=wEE5Fol?6+"\ypk ?5 0cc.iiTMnW(JbRwE3pURLy$h,OY[AUr'W5L,f=Vi!P˅j :jYOifqu5w[HgaYb\Ю e)h -]kh! rCRTRz?|fT`r)[c_X;K옆{/6}yS%N$2;e #<󈖖 wiCG$dyԊ`nѹ%bǺܵ}؛v5]u0s& !uǕf[)7d;HcB{듶*-E٪YK|8uF1lsM$#Mډ24BgVQy%1d:g7D+DtFVpCabj#IZ+sM7X%.ybrNkp$~-DD^)ĵ㛝!>W[W.KG; K 8 Z~YN]<U(!w+Dbf)a.!ؒrNf_ZgF&۪wQVnvpd?G+/(42=%$ZMIigLdc%o'Ur%IZX=z"%VhU;[ND{XHS*̎ |v|j&oocˈ!7P;Sf2p}M)!f3>ˎrAɛ^O[4sΜm^\0El;Ӹ]:Tv`ػq"':zbPGߩhuLhb,'IH,Eͨ{i|d Y}(­7"0'f!jHhg_T8um96Pkj_`@ȈA姜 sf}롓Yo2q6w[h }CrMŶ ܍T&ٶ0ߞJuVK׭\H?Y;EXhrP~vS \ l/9UKA:èMujEWo;a0йWS,GW8QM{&@O8p9: C):bh/s#4dy!\R}^ك?Pq yyߖ*ko=.#dqxZg^'^ZHf$)-^N~l{F;>?V8lS/^FwX챁+Y;݉Vl͞~D/M+OYǖvne bUm/)p Qs?(+p`tiS6Wͻ^8&vN=m|}a?DNDWB;篯+|6{JfCxN_]T:{0aF Ϗgc} ;eǵgn| ~KqYTŶ{WNyb#92:鉾Y#_o>vnǻluFXubdA{D~@9˦S8λWkɌQrQg}~>p-T|-M_/>Te Q3wj"Y>i1bk#Br%KN dJ?^%$.b+NƢ\}1\a(jɆ Jh)P=g+ dtc6khz5Hǻ@ Ċ*&nEmU6yxъJ & )YX6K!ˬ t|vG_3d{2RK\f@F@J;qaR%5l/BkVwE6RShڗ U_l{ϒR:Q XTA׃G AWmuO/.xu}tҚ*۷єiiR(c[R֒HC;neSբa2*>3KE2M׍Z m1ruճ7Zն)7߂9dW~\y"3H~$jBWםCea-aO}kP x[bA+'R'6Zuݑts*) &%MUN&)h~Z $3c #AWZH(i(}f|@nmVi:M&Fg!(Snu6O_-|&w>$f-AY@Hz*3 aO[CLņNL]S G ]vPTPv![_3xLJ@Y|%j|ot܊IlIvvÈXJf2u@ Ǫ -VK Ԧf<{Z&HXZJtNlC6qhFEYdE9dd*18k~~vxv;Ge?wo̺]: { vʼ>[[ uDMG ?;mZezǃ.XUp,Pg2F^ܲNJ&Q%E乼!} XO0f?[P7ӁEYFPZlPy 'N#1Wauq`}Zlϻ" &.q{wΥ-,%~Ex<hr!A/ܧ5lxF.|tr w+ϬAA$ {i:Hv}ygn}8|)6 OiRvʐ_n9;N%HxgFY'ڊsʎ$ttJQ;wy r!^ RT>c|2ᅸ{R/;NC3ku:p9 ii]^UVOqnT[_-SEgZc4P O7<4KXdwˬŏCUeZ"iR(7ê)MJEл K,Qu ÚI+2^ 61 ^Cݷ.f1{F}J_xL0*Qgma1+Eeq=%b;=_?X>0s6$R5XnѥׁNSCT=h4fاYhTqc_~D'vYLZz1Vt[˫01&Չ]t(0#ӭȿL\ Y>9%Ŏ"SOu&LS$OSj^|([- kL iT=Ҫk27vv9.dUj@Y٥4nƲrlqF Mj^lRLѝƃBMDS~??O0\%iu|TMLL4JvbqQ Yv%#vP3I`x%\H͋0f&N e*xHe+k>~Zw,x[5=Z5ȏT43oz;Zn򒽀Z5o*ɖW7ӄ,Ҫݾ݆1#p讪,E/@sV3V xm*M !Ta>Kܸ6a)eKq)>4X\y.vn,n3.Jt22jݽYcdI6ҚjR|ZS\m[>jHm $}btȿ*UΌl$Irix3qk[dA 'c'̨XU t(% ퟫ1La~8ꌲOMt[NI+D{kE,IXL&$]t"qwd;RHE(Cge6zAGCɋ2r ry 鸯m6K[Z| N}cɞrE'0u,{WzA% G4#~Q;ݮn/2Ź`4dk#@~lpӛ.b& (OXo~R~t0, 0qoc:HgVSRtX[9%j=,3'RkⲹUdu;ɧ=mä@s>qO;w]5T? 4P/I >àL~-]b Y5M]{.鱈S#XIi|!"k-I"l̒DHyw#)6di:I*socAz摋T4yjq4r\ghRSC~yA/A~z+f-`˫FxdקuI¤1 ?*N|v?#$m;_J|Y;O׋jWmn/zIMH{拋*ÿյZ?[䵒~_ e[*ͳUd_J;YdY4R¹#!9Ò_PQٍ8J<E<ܵX /X=7B!gwm>{Kƭgt{k4$z^Ԏ MU~%itLb$6K}7H >6 h_ndFJjG@3DŽ%:O7_7F;ճ*+J"w}q] endstream endobj 682 0 obj << /Length1 1647 /Length2 13171 /Length3 0 /Length 14023 /Filter /FlateDecode >> stream xڭweTܒ-!!7݃kC7={p !Cpwx|ߝ;w}ơݫOSήLEQ(`adeb(L]jvJ j@KY- Dw@@& @h(TqGg@MKO/_WD< K{@[G;= V@WVёUH+i@"T\LmAf X88lq9؛* % @3Л p:ہ`lby{dofbWov rtvxa8!`3g#UEByBL `Ms3J{yC!& {0t0mM=s2K?Ԏ:UXbSU3,~B tzKOEykZcMO7}Ã]=ۄٱT&Ȓ Wf/.n0ӟ](k=gi\M若XG&P+{<&&y"[| msU5Ԉw6b(Rw"1E1#WAz]wMJPg$Cl8 QSa Ҧ&vURj-ص1YV0dkڣ\_l5ą ZEa<ӂ.vd!nw^g6K C8$.Hp7oX71dhîOOi bY>.,DЗ-,r^z8 =1ԓW$Ƭ>djQ+YE +x:Q4XY髺ä)KIqU{ l|ŰhM1LBNakƤdy+F3㓻<9ԯt񺇡B)`L_~nզ0t|]~I ~wY?D< a&r])}اFbjͮZq&SY?Li2<ʎOdp cG)_$G[ @A"f8 oE%~7o-Q}bXVP -,6I@F(x;$|~M& a8g/}uP۬n,ϫm*ad ^%/Zd3F1z&D싉(f ƘfXyDGb ̓E-%(i7 eSbЭ`GΧ2_SWdj{"!'ڭ0tϥ zɎaq~E%f@ ǫO}2G}Bۚ=v=-Ujng%^QnCnZkTȔ!/%bFDڏ:']3#U{ݽ H)N8@ fnVܯgg&1*#)HQn_]_J$i ͯ+@Ίa|'gpq-)v4'ZE D)岯j'"b Rqe~nTQY)dtewNJyABZXZl0W&5,47F|RBK:J іn_9ټJ= Q{9єz&&:ee}.i"QQSxafeWD2g.Yl nX|E{Ϙ+FNS-TCfGQ4P8F3z}TOF +2/ 2bÕK~^m&V`od)Xv+>r**9433SlۂfJe>qR}(u?kۗZَj(4esz?4ذ~%FFqA>̝nk)WU\ |A:7źYD:+HbPkӠaʔCdj;.&Sk|4zoE@(hu}bs[',K@2H*~T"WQg:R,cG3݉Jq#z,8usPOiJ?E8tSnChᘿ`Y^ aJI'mۭ|Ci[q?`غ7Id@BTc'ؕljcs &ZsqΆe+Hl1zR|cLצ$GJՙ΃utt|AU%y!%e!J Uj>`/fWN4/֎Jڤ\oֺfCEG! |o/Gͅ~wn}v*Lͱ)GNH3šsM-6{4Ik2ɒ?d՞eJG7YX{TB ,1mt[8fE9D3)ӠcnR/5Q訝UVU\sJT] 5#HNs&h+ گz"@ #hlzoq=93^J&4Cp[] p[x)CY cІbn9$mo~'kX)SN52ɫ֣I/]kg?]o&w"ITqae%QInNbL" lZT =塿 mbO>p]ZGe G&Sv՚/E^ ՛+ֻ`L:^mNliN\;Y)KOe*,aǍd䈧oa~*Ty w_Gn͘F.@0Pd,lr\>E[D;Wν'/?,32)9'u:݊j@8t^pO3"i7m]B\azY DhU&CH_oo9*1uHrvaUAY]ߏ:bQG(C`F#ݥP-Ft6N[L(Y )?"F^_.:q1A-ֈFsgRmMTaz˕r*>HA{>}9yKԖRnGQ>ȗ/l3/֖M'aO0{\¶͉"7 \pbT;"ȎrBEǛp.dԘ0 .P ?:HuC'/)wPaay7=s8{ZgےHBQXހ't︄ Pe`2ej RTkO㺺phUߓ]7qդВ0~ ͅC os^q]gow,cMfg''6Q/ٕs<ZI|yMK3Uhǘ(l 1kQ6`g4rXI>(Iױ o'Ϛ#K&lSL o,v bÈcW8Bo/O0 ߕ80=&KaHFgЋ7h+nwz (T@@W*anZJ$?L ?V5 *BK!I> &1d1qm|ڲx([0 _C+XJTf }1!jplج]ώXBDKQ=5Gڃ!| aEݑ{ 0U1uDwHx~wMz2~z_HpLȮ!gVvn axJs\َF1*vOsK7嵣$d[i eH*T8K?ʇ+a "UnSf54 $(}_7&U`x9EoWŨG>dX65m#~!ͮXوΰ#T7Nh.Y%(=q<[#ŋijeKIat\.o[8P;nqY &Xq4i'C".c}6RPf:b Gѐ.[~sp\[ WEN7$yGZ!R a^ڌ~^jۮ^`!g|fD4)1 em¡ߗ@|6%y X3ؒr2!0W/H̼+H.۴ɥ2Cvؿ̔+oW%SX>wg-.)h A|,[G ,S cJ0- gloNЯ-tOmIX l7E_{)y/C&ś4at'*:` 9~G݇J='[fu $cփIMWx C$ 5H0tgR+PT39=:`gX*g ̶{pzM*86Z!+*0"hAM)&zpъxq:ց[;׎-UBW{qNәZW!i,*CG^Zt=JW/x}ڐGTrxI8:JN#)9o4pOEcj;fI[AJQ sPPz裶6 yG/]' =r +ٖ0VrD zĜ8؃TBd}I׮iU8[=s&D.?L#䭋hcONxqJ;C}Iq*Ѭv=ݧXDM46_`{\Xֵ DJNϯ3/fe}PîOT@y^-yO%4tLԯjxI 4R=%٩Kdٟߟ%]l&ZGg.ҘB_#߶'{E؜3}^:Ք)4L _6 6 Q[ާg<=l,.|t[p&@ޤs'[b8QE'!ψۣ-9ջ+h9sxDx W) <7e `kp*xԬW~wCdKW0AF4YOdҨsY,d.(/~9fC{3AAWaa؛|eGOl28sa2w#" 9<7@t1#_$"1kq 4͠=OWc*G{`+EbQL/~x_^C^u0c xc8?U5뗎˾)m-x/iY^Mւ_v~~YZ|OkwAK:?fl'd1cb~@D؝,$̰ph}OY(Q̞2*JMr?ƭ?pv֝{1yEJ`}99h8[F[_1GZm 9b+__LE:HQrhG܀Kr-bbֻOǯ*Wk M\"s>)%n fёϰЩ}kT&v-} ЁaK2.KvSM:ML2(%کr7N3bX/3c%!mz6yNÖbE֍Ο8ƕ uEmA[ Fg>嚿P 62 KUS1`fKX=ǐrO|Qԑ]xEQeX?ʕԗzJENOЧ)Qk鯙f;!\Sw2G6ǑdELR,5oJߜW4MżżrBLu.Y0JT,蔧kux[`ydUóTNf?6kn&ҕ*>&0o_@ g|99#nљ`,5Inyp-}|Ps~Z^r9 nM_K|?H3Q{G+wm KT{hI@"8r3 c%fPYt)/ z~z2L2l.$p7F( NEkwF ݱ\MnH~#l+[M0+#<.$9IG+AB I )^f@JVdR3bRJ8nzE6T0K7*-ΝajM-wbxKIɍ`y$WwH0[`P Xwe"XΡ|k4JgkǙuTQq8F4t( b %_/.;ࣁ]Zj`ޅ ˧1NV?=I+z*Wc~XFm; |!P[G x)0VEXܳyTg\_\}Wce2.ߖZHXwcj&~S\mڐ4;?}X.eliD/̌K=tHl{A4-SHxI1rxC=Q~䩲Gj5DOdG59#*a:W_1a eHO`pQu᝕nPQ"VOj^gE,-4uɺpYg&y:'ܞE59U=d_psCgs̞뒕 APmȵIJภPu +e av.S-*5I 0'a.ѝWzUˉtOe5AzK }kT!F]äЭ(C JR+׊}~ sr]ښ9 ζuō:D .l=寣 LO5[~-:Fq.tr#qnk3?`sԋeAc/RQݝb*"d0aCD"ǧ>huw0ٲ{#nSEwuhS7hy:ePd2$ 746J6 FYi{ ~%k}jN;/v dUlޟgC>HJXMj/̮=ߔ_$Ħ%zB/1BQ׹.p+ jk5h|}׃LR`^Hό]>raEEw5v64!n8sN(HE:SS7yt!: wfN`o3""F6$>˓AxH+dʣ؆Յi^:x34 6/_2!cz{ ~_"Q(RC>kI 9C_GW%)1<\7ՑUh&t$jB)vL>itSPu'hC׌1ˎMmHc@1{Eޯyk #*_3%9^Expl f}/Fۘ'D;]o !tyf\%-j}pǹ_qLպjBw\-*խ: cw)>Q/܁.@==+lh0Vb7ГWb3\qGDy[u#7DRh: QE<[c/qf'Ӑw A3\M,v])l"h'$07~ +7݀кif)2d`.}U H@+bT|-= 1wDǨ fϦ'YC.IC:u`p~M@1B0a?F9߳ e]q5cf x4k8ݼ$@?Ohf#HXQ1] 9ᔗ>1wyCeErLvHOѡԣV"PKęS_%ᄅ|HCfΔɛ_"r rnijQ1` ^{',e5>Q1xnDž!/^8Gҩl D\Q>ڰz9kn5űCAqҸVEəK@_سA56cJ\XX:;Mj$H%)Y5V}XZo W#]gPݽHN0E"ҥ\ݥ h`:p\]sumvH]7Y{%nvS?0[Y8!*%&M7?sfT=ٻ /-Ysjs շjs4FaKaFK)lL #5|Dh]vj;a۔edn(le|DQ~y>i`AiDz~ߧa{YꞰ ]Ut(t\)U8Da1Aǰ=qJUPlI8&ƫ6[pYmq/f s^]OނXn4e+T+_̋ԤM }|}Cs3G~08if0fWLKׄ;>mIg.NPE;:_&9"ufh 4ڵ>f@I]g KۅsrJ$gilLrD0!4F2OHϝd4F,TH endstream endobj 736 0 obj << /Author()/Title()/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.18)/Keywords() /CreationDate (D:20190606144045+02'00') /ModDate (D:20190606144045+02'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) kpathsea version 6.2.3) >> endobj 671 0 obj << /Type /ObjStm /N 94 /First 852 /Length 4303 /Filter /FlateDecode >> stream x[sܶ# x:&qȮI;%>$Owy R'w<2y%uR:Li *3S7:IfЌQ170~_mWmm[%N^WMD7ɓ]PbGq*mo}Y[lզď qD~Bj}]ԯ6<&Oȷ);<#g<'/KD^7-B R4jͺ۶)ZrA.ՇfS4.V妼lsv}7"fon &h %)? )?6 $]I.w\+O߀U]\/T?ِM4lɶږd(릺ڒفuup]涬@V5|r}n Iuפ!My6gyߒ.K~ڑ=oװjW|"w~W(8]9{Ͼyuso^3;93<~AA?0|>N!#1$c){:/ONݜɏ庚 .hV r~v/Ar(NL!9^Q@qݮ1.!T!"11wsa ]'<88~o_ Ql3ӳD6#%Ez@:W'? 5Glmo6aM] PgfPX&*R6m0$:ЇUuU0yh1'@~9y)Qǡrb+]J˽~DvDeeC֛'4A3G564IMq o"Nw$ 3Ϡqٚɍy0>&gY&q&Z5$ R]^BoWec.u7ae\ _m)ejDŽwKaxsqǿcqdh}J_ z{ҰA#?}pև!~8aMRd jZ>U*}37-moy9JC9U {nSPU޵]rlpG4,ӊAuۓvDqz2f7>][ٸDžnVD(>}D!T'ESB:m:yDΊj^7P 6g%Kf3Ʀcl(G=8zA?}']6i#>oa Ld!LG@9T@3?YbC|lN(:;#\(grWFJ];ʜ,l_mw^n;9won N;w6*5,56 vGX%5v%C%}68wǁ츊l=߷8^_(fVp0g}?7/.hbiflv;}b;;)<}dڎ9aKv2 ;rZB;bjG<%eȳJ,"Y&xbg,̗xf!<3xfKdBjJ.`U؜J[8XWe]栭V@N0zh4o~=F:C‘ECI::& txPnѬWA8w`w9ePB!cTWB-if$I9(ufvm (WO.g/w58ҵ#|Gx gh4Wx8ܮ!°Mus8D#j-tgەn.oXG"4P~`ܠlmoq=TݕvWۆwq.LΏH]÷ZOܥ eoj듌͏io4H{_SC`pu{INfwWF!%@gbpSw ts)W }'AX"za&n~\';'36TtjQ#:

LtWfaRbPO Xn֧x+!2qeHzj [Às;黛'U&+'};*bکdVI*tf{XT䴿h7z WfHŝ=C+q:V=$4 :vz |b@oMћ {ͻbSA,,`&¤FK& gLY]mYYw]Os0o}D(PP2ᢃZ7тm P"(y(8k7pclê 0i`},#4Dʐ~; 3JqVzdI$S( =*=J"v Ұܦ CL,F/ߒ];A4S@Mz?w!G} 1G'bHb)÷$:rX*P:apgc}w*N#lRRI]dyx<3 fs EfȬac1 >|7 Y= dVO8DfMx9dŲhF 57((s+CM6d!1H{`ظ;*8>wO$ ń |dizЌ#lB"R(1nsԊYt9kHAjEm1qLHVN7KGAfu.s*ZNbjcUfqzt[|o09-Cik.>:ЉćϘpP:Ov騷MM "Ӈlk//?*C~_7QjAj|}T"*ۂ^zW|jG횞6hw[gζ_RӾ#Ӿ>޴0dI+5X|`W,>_kG[S0ӌ?43Ԇ_>E% %K t:hz`iـ~[fwu};s4\Їo\?%yݔ/=-' endstream endobj 737 0 obj << /Type /XRef /Index [0 738] /Size 738 /W [1 3 1] /Root 735 0 R /Info 736 0 R /ID [ ] /Length 1686 /Filter /FlateDecode >> stream xeK᪯s9vss9Μ99 X4 ѽܑ#ȝ/8^ɏ]]}kڥR&J-ZzL =UB#KsL[#Ss;(Cs/+J3y0jL `rm`K`-`I͚+`cM`TM4Zeb5zI bWkfr|jV5̉o[+C梧vcbX;[{ZʢTk/ޝaCpQ8SpY82\Lo ͅ% ٿ+W\pnm;鵧Wz=Uca<`Uc0tZ90ioe˟rIΓ';OvhlѶ94iuK;'pX;rVrmwh-ctոqI%-t@9G4]c&5>h|=~ EY Rd·;9.i钼x#R fll3kyM؃ૐRPHA!oD^‡b""d~P?rrA~P?!g:h4C*. &h4̓AyM_ӌZ{36lȌi3d3䇓 3X`1 9{+7eis YHEp4$6Hwr GQO@ 6(kCϯ>W'# endstream endobj startxref 149320 %%EOF tibble/DESCRIPTION0000644000176200001440000000334513476213663013241 0ustar liggesusersPackage: tibble Title: Simple Data Frames Version: 2.1.3 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("Jennifer", "Bryan", , "jenny@rstudio.com", "ctb"), person("RStudio", role = "cph") ) Description: Provides a 'tbl_df' class (the 'tibble') that provides stricter checking and better formatting than the traditional data frame. License: MIT + file LICENSE URL: http://tibble.tidyverse.org/, https://github.com/tidyverse/tibble BugReports: https://github.com/tidyverse/tibble/issues Depends: R (>= 3.1.0) Imports: cli, crayon (>= 1.3.4), fansi (>= 0.4.0), methods, pillar (>= 1.3.1), pkgconfig, rlang (>= 0.3.0), utils Suggests: bench, covr, dplyr, htmltools, import, knitr, mockr, nycflights13, rmarkdown, testthat, withr VignetteBuilder: knitr Encoding: UTF-8 LazyData: yes RoxygenNote: 6.1.1 Collate: 'add.R' 'as_tibble.R' 'check-names.R' 'compat-lazyeval.R' 'compat-lifecycle.R' 'compat-name-repair.R' 'compat-purrr.R' 'tribble.R' 'deprecated.R' 'enframe.R' 'exports.R' 'glimpse.R' 'has-name.R' 'lst.R' 'msg-format.R' 'msg.R' 'new.R' 'repair-names.R' 'rownames.R' 'strrep.R' 'subsetting.R' 'tbl-df.r' 'tibble-package.R' 'tibble.R' 'type-sum.r' 'utils-format.r' 'utils.r' 'view.R' 'wrap.R' 'zzz.R' NeedsCompilation: yes Packaged: 2019-06-06 12:40:47 UTC; kirill Author: Kirill Müller [aut, cre], Hadley Wickham [aut], Romain Francois [ctb], Jennifer Bryan [ctb], RStudio [cph] Maintainer: Kirill Müller Repository: CRAN Date/Publication: 2019-06-06 13:40:03 UTC tibble/man/0000755000176200001440000000000013473044414012272 5ustar liggesuserstibble/man/add_column.Rd0000644000176200001440000000247713407176030014675 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. These arguments are passed on to \code{\link[=tibble]{tibble()}}, and therefore also support unquote via \code{!!} and unquote-splice via \code{!!!}. However, unlike in \pkg{dplyr} verbs, columns in \code{.data} are not available for the expressions. Use \code{\link[dplyr:mutate]{dplyr::mutate()}} if you need to add a column based on existing data.} \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}} } \concept{addition} tibble/man/figures/0000755000176200001440000000000013476204717013745 5ustar liggesuserstibble/man/figures/lifecycle-stable.svg0000644000176200001440000000167413407176025017677 0ustar liggesuserslifecyclelifecyclestablestable tibble/man/figures/lifecycle-questioning.svg0000644000176200001440000000171413407176025020765 0ustar liggesuserslifecyclelifecyclequestioningquestioning tibble/man/figures/lifecycle-soft-deprecated.svg0000644000176200001440000000172613407176025021474 0ustar liggesuserslifecyclelifecyclesoft-deprecatedsoft-deprecated tibble/man/figures/lifecycle-defunct.svg0000644000176200001440000000170413407176025020047 0ustar liggesuserslifecyclelifecycledefunctdefunct tibble/man/figures/logo.png0000644000176200001440000006500013415444210015377 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/figures/lifecycle-experimental.svg0000644000176200001440000000171613407176025021117 0ustar liggesuserslifecyclelifecycleexperimentalexperimental tibble/man/figures/lifecycle-maturing.svg0000644000176200001440000000170613407176025020247 0ustar liggesuserslifecyclelifecyclematuringmaturing tibble/man/figures/lifecycle-archived.svg0000644000176200001440000000170713407176025020207 0ustar liggesusers lifecyclelifecyclearchivedarchived tibble/man/figures/lifecycle-deprecated.svg0000644000176200001440000000171213407176025020516 0ustar liggesuserslifecyclelifecycledeprecateddeprecated tibble/man/subsetting.Rd0000644000176200001440000000444213407176030014751 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/subsetting.R \name{subsetting} \alias{subsetting} \alias{[[.tbl_df} \alias{$.tbl_df} \alias{[.tbl_df} \title{Subsetting tibbles} \usage{ \method{[[}{tbl_df}(x, i, j, ..., exact = TRUE) \method{$}{tbl_df}(x, name) \method{[}{tbl_df}(x, i, j, drop = FALSE) } \arguments{ \item{x}{data frame.} \item{i, j}{Row and column indices. If \code{j} is omitted, \code{i} is used as column index.} \item{...}{Ignored.} \item{exact}{Ignored, with a warning.} \item{name}{ A literal character string or a \link{name} (possibly \link{backtick} quoted).} \item{drop}{Coerce to a vector if fetching one column via \code{tbl[, j]} . Default \code{FALSE}, ignored when accessing a column via \code{tbl[j]} .} } \description{ Accessing columns, rows, or cells via \code{$}, \code{[[}, or \code{[} is mostly similar to \link[base:Extract.data.frame]{regular data frames}. However, the behavior is different for tibbles and data frames in some cases: \itemize{ \item \code{[} always returns a tibble by default, even if only one column is accessed. \item Partial matching of column names with \code{$} and \code{[[} is not supported, a warning is given and \code{NULL} is returned. } Unstable return type and implicit partial matching can lead to surprises and bugs that are hard to catch. If you rely on code that requires the original data frame behavior, coerce to a data frame via \code{\link[=as.data.frame]{as.data.frame()}}. } \details{ For better compatibility with older code written for regular data frames, \code{[} supports a \code{drop} argument which defaults to \code{FALSE}. New code should use \code{[[} to turn a column into a vector. } \examples{ df <- data.frame(a = 1:3, bc = 4:6) tbl <- tibble(a = 1:3, bc = 4:6) # Subsetting single columns: df[, "a"] tbl[, "a"] tbl[, "a", drop = TRUE] as.data.frame(tbl)[, "a"] # Subsetting single rows with the drop argument: df[1, , drop = TRUE] tbl[1, , drop = TRUE] as.list(tbl[1, ]) # Accessing non-existent columns: df$b tbl$b df[["b", exact = FALSE]] tbl[["b", exact = FALSE]] df$bd <- c("n", "e", "w") tbl$bd <- c("n", "e", "w") df$b tbl$b df$b <- 7:9 tbl$b <- 7:9 df$b tbl$b # Identical behavior: tbl[1, ] tbl[1, c("bc", "a")] tbl[, c("bc", "a")] tbl[c("bc", "a")] tbl["a"] tbl$a tbl[["a"]] } tibble/man/deprecated.Rd0000644000176200001440000000157213407176025014667 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/deprecated.R \name{deprecated} \alias{deprecated} \alias{data_frame} \alias{tibble_} \alias{data_frame_} \alias{lst_} \alias{as_data_frame} \alias{as.tibble} \alias{frame_data} \title{Deprecated functions} \usage{ data_frame(...) tibble_(xs) data_frame_(xs) lst_(xs) as_data_frame(x, ...) as.tibble(x, ...) frame_data(...) } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("deprecated")} Use \code{\link[=tibble]{tibble()}} instead of \code{data_frame()}. Use \link{quasiquotation} instead of \code{tibble_()}, \code{data_frame_()}, and \code{lst_()}. Use \code{\link[=as_tibble]{as_tibble()}} instead of \code{as_data_frame()} or \code{as.tibble()}, but mind the new signature and semantics. Use \code{\link[=tribble]{tribble()}} instead of \code{frame_data()}. } \keyword{internal} tibble/man/enframe.Rd0000644000176200001440000000255113407176025014202 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 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 with one or two columns (for \code{deframe()}).} \item{name, value}{Names of the columns that store the names and values. If \code{name} is \code{NULL}, a one-column tibble is returned; \code{value} cannot be \code{NULL}.} } \value{ A \link{tibble} with two columns (if \code{name} is not \code{NULL}, the default) or one column (otherwise). } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} \code{enframe()} converts named atomic vectors or lists to one- or two-column data frames. For a list, the result will be a nested tibble with a column of type \code{list}. 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. If the input has only one column, an unnamed vector is returned. } \examples{ enframe(1:3) enframe(c(a = 5, b = 7)) enframe(list(one = 1, two = 2:3, three = 4:6)) deframe(enframe(1:3)) deframe(tibble(a = 1:3)) deframe(tibble(a = as.list(1:3))) } tibble/man/lst.Rd0000644000176200001440000000357613407176025013377 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lst.R \name{lst} \alias{lst} \title{Build a list} \usage{ lst(...) } \arguments{ \item{...}{A set of name-value pairs. Arguments are evaluated sequentially, so you can refer to previously created elements. These arguments are processed with \code{\link[rlang:quos]{rlang::quos()}} and support unquote via \code{\link{!!}} and unquote-splice via \code{\link{!!!}}. Use \code{:=} to create columns that start with a dot.} } \value{ A named list. } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("questioning")} \code{lst()} constructs a list, similar to \code{\link[base:list]{base::list()}}, but with some of the same features as \code{\link[=tibble]{tibble()}}. \code{lst()} builds components sequentially. When defining a component, you can refer to components created earlier in the call. \code{lst()} also generates missing names automatically. } \section{Life cycle}{ The \code{lst()} function is in the \href{https://www.tidyverse.org/lifecycle/#questioning}{questioning stage}. It is essentially \code{\link[rlang:list2]{rlang::list2()}}, but with a couple features copied from \code{\link[=tibble]{tibble()}}. It's not clear that a function for creating lists belongs in the tibble package. Consider using \code{\link[rlang:list2]{rlang::list2()}} instead. } \examples{ # the value of n can be used immediately in the definition of x lst(n = 5, x = runif(n)) # missing names are constructed from user's input lst(1:3, z = letters[4:6], runif(3)) a <- 1:3 b <- letters[4:6] lst(a, b) # pre-formed quoted expressions can be used with lst() and then # unquoted (with !!) or unquoted and spliced (with !!!) n1 <- 2 n2 <- 3 n_stuff <- quote(n1 + n2) x_stuff <- quote(seq_len(n)) lst(!!!list(n = n_stuff, x = x_stuff)) lst(n = !!n_stuff, x = !!x_stuff) lst(n = 4, x = !!x_stuff) lst(!!!list(n = 2, x = x_stuff)) } tibble/man/tbl_df-class.Rd0000644000176200001440000000606013407176030015115 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tbl-df.r \name{tbl_df-class} \alias{tbl_df-class} \alias{tbl_df} \title{\code{tbl_df} class} \description{ The \code{tbl_df} class is a subclass of \code{\link[base:data.frame]{data.frame}}, created in order to have different default behaviour. The colloquial term "tibble" refers to a data frame that has the \code{tbl_df} class. Tibble is the central data structure for the set of packages known as the \href{https://www.tidyverse.org/packages/}{tidyverse}, including \href{http://dplyr.tidyverse.org/}{dplyr}, \href{http://ggplot2.tidyverse.org/}{ggplot2}, \href{http://tidyr.tidyverse.org/}{tidyr}, and \href{http://readr.tidyverse.org/}{readr}. The general ethos is that tibbles are lazy and surly: they do less and complain more than base \link[base:data.frame]{data.frames}. This forces problems to be tackled earlier and more explicitly, typically leading to code that is more expressive and robust. } \section{Properties of \code{tbl_df}}{ Objects of class \code{tbl_df} have: \itemize{ \item A \code{class} attribute of \code{c("tbl_df", "tbl", "data.frame")}. \item A base type of \code{"list"}, where each element of the list has the same \code{\link[=NROW]{NROW()}}. \item A \code{names} attribute that is a character vector the same length as the underlying list. \item A \code{row.names} attribute, included for compatibility with the base \link[base:data.frame]{data.frame class}. This attribute is only consulted to query the number of rows, any row names that might be stored there are ignored by most tibble methods. } } \section{Behavior of \code{tbl_df}}{ How default behaviour of tibbles differs from that of \link[base:data.frame]{data.frames}, during creation and access: \itemize{ \item Column data is not coerced. A character vector is not turned into a factor. List-columns are expressly anticipated and do not require special tricks. Read more in \code{\link[=tibble]{tibble()}}. \item Recycling only happens for a length 1 input. \item Column names are not munged, although missing names are auto-populated. Empty and duplicated column names are strongly discouraged, but the user must indicate how to resolve. Read more in \link{name-repair}. \item Row names are not added and are strongly discouraged, in favor of storing that info as a column. Read about in \link{rownames}. \item \code{df[, j]} returns a tibble; it does not automatically extract the column inside. \code{df[, j, drop = FALSE]} is the default. Read more in \link{subsetting}. \item There is no partial matching when \code{$} is used to index by name. \code{df$name} for a nonexistent name generates a warning. Read more in \link{subsetting}. \item Printing and inspection are a very high priority. The goal is to convey as much information as possible, in a concise way, even for large and complex tibbles. Read more in \link{formatting}. } } \seealso{ \code{\link[=tibble]{tibble()}}, \code{\link[=as_tibble]{as_tibble()}}, \code{\link[=tribble]{tribble()}}, \code{\link[=print.tbl]{print.tbl()}}, \code{\link[=glimpse]{glimpse()}} } tibble/man/as_tibble.Rd0000644000176200001440000001166213473044414014513 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.data.frame} \alias{as_tibble.list} \alias{as_tibble.matrix} \alias{as_tibble.table} \alias{as_tibble.NULL} \alias{as_tibble.default} \title{Coerce lists, matrices, and more to data frames} \usage{ as_tibble(x, ..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal"), rownames = pkgconfig::get_config("tibble::rownames", NULL)) \method{as_tibble}{data.frame}(x, validate = NULL, ..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal"), rownames = pkgconfig::get_config("tibble::rownames", NULL)) \method{as_tibble}{list}(x, validate = NULL, ..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal")) \method{as_tibble}{matrix}(x, ..., validate = NULL, .name_repair = NULL) \method{as_tibble}{table}(x, `_n` = "n", ..., n = `_n`) \method{as_tibble}{NULL}(x, ...) \method{as_tibble}{default}(x, ...) } \arguments{ \item{x}{A data frame, list, matrix, or other object that could reasonably be coerced to a tibble.} \item{...}{Other arguments passed on to individual methods.} \item{.rows}{The number of rows, useful to create a 0-column tibble or just as an additional check.} \item{.name_repair}{Treatment of problematic column names: \itemize{ \item \code{"minimal"}: No name repair or checks, beyond basic existence, \item \code{"unique"}: Make sure names are unique and not empty, \item \code{"check_unique"}: (default value), no name repair, but check they are \code{unique}, \item \code{"universal"}: Make the names \code{unique} and syntactic \item a function: apply custom name repair (e.g., \code{.name_repair = make.names} for names in the style of base R). \item A purrr-style anonymous function, see \code{\link[rlang:as_function]{rlang::as_function()}} } See \link{name-repair} for more details on these terms and the strategies used to enforce them.} \item{rownames}{How to treat existing row names of a data frame or matrix: \itemize{ \item \code{NULL}: remove row names. This is the default. \item \code{NA}: keep row names. \item A string: the name of a new column. Existing rownames are transferred into this column and the \code{row.names} attribute is deleted. Read more in \link{rownames}. }} \item{_n, validate}{For compatibility only, do not use for new code.} \item{n}{Name for count column, default: \code{"n"}.} } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} \code{as_tibble()} turns an existing object, such as a data frame, list, or matrix, into a so-called tibble, a data frame with class \code{\link{tbl_df}}. This is in contrast with \code{\link[=tibble]{tibble()}}, which builds a tibble from individual columns. \code{as_tibble()} is to \code{\link[=tibble]{tibble()}} as \code{\link[base:as.data.frame]{base::as.data.frame()}} is to \code{\link[base:data.frame]{base::data.frame()}}. \code{as_tibble()} is an S3 generic, with methods for: \itemize{ \item \code{\link[base:data.frame]{data.frame}}: Thin wrapper around the \code{list} method that implements tibble's treatment of \link{rownames}. \item list \item \code{\link[methods:matrix-class]{matrix}}, \code{\link[stats:poly]{poly}}, \code{\link[stats:ts]{ts}}, \code{\link[base:table]{table}} \item Default: An atomic vector is first coerced to a list and, unlike \code{\link[base:as.data.frame]{base::as.data.frame()}}, the returned tibble has one column per element. Other inputs are first coerced with \code{\link[base:as.data.frame]{base::as.data.frame()}}. } } \section{Row names}{ The default behavior is to silently remove row names. New code should explicitly convert row names to a new column using the \code{rownames} argument. For existing code that relies on the retention of row names, call \code{pkgconfig::set_config("tibble::rownames" = NA)} in your script or in your package's \code{\link[=.onLoad]{.onLoad()}} function. } \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(as.list(1:3), .name_repair = "unique") # Prefer enframe() for vectors enframe(1:3) enframe(1:3, name = NULL) # For list-like inputs, `as_tibble()` is considerably simpler than # `as.data.frame()` and hence faster \dontrun{ if (requireNamespace("bench", quietly = TRUE)) { l2 <- replicate(26, sample(letters), simplify = FALSE) names(l2) <- letters bench::mark( as_tibble(l2, .name_repair = "universal"), as_tibble(l2, .name_repair = "unique"), as_tibble(l2, .name_repair = "minimal"), as_tibble(l2), as.data.frame(l2), check = FALSE ) } } } \seealso{ \code{\link[=tibble]{tibble()}} constructs a tibble from individual columns. \code{\link[=enframe]{enframe()}} converts a named vector to a tibble with a column of names and column of values. \link{name-repair} documents the details of name repair. } tibble/man/tibble.Rd0000644000176200001440000001160013473044414014020 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tibble.R \name{tibble} \alias{tibble} \title{Build a data frame} \usage{ tibble(..., .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal")) } \arguments{ \item{...}{A set of name-value pairs. Arguments are evaluated sequentially, so you can refer to previously created elements. These arguments are processed with \code{\link[rlang:quos]{rlang::quos()}} and support unquote via \code{\link{!!}} and unquote-splice via \code{\link{!!!}}. Use \code{:=} to create columns that start with a dot.} \item{.rows}{The number of rows, useful to create a 0-column tibble or just as an additional check.} \item{.name_repair}{Treatment of problematic column names: \itemize{ \item \code{"minimal"}: No name repair or checks, beyond basic existence, \item \code{"unique"}: Make sure names are unique and not empty, \item \code{"check_unique"}: (default value), no name repair, but check they are \code{unique}, \item \code{"universal"}: Make the names \code{unique} and syntactic \item a function: apply custom name repair (e.g., \code{.name_repair = make.names} for names in the style of base R). \item A purrr-style anonymous function, see \code{\link[rlang:as_function]{rlang::as_function()}} } See \link{name-repair} for more details on these terms and the strategies used to enforce them.} } \value{ A tibble, which is a colloquial term for an object of class \code{\link[=tbl_df-class]{tbl_df}}. A \code{\link[=tbl_df-class]{tbl_df}} object is also a data frame, i.e. it has class \code{data.frame}. } \description{ \code{tibble()} constructs a data frame. It is used like \code{\link[base:data.frame]{base::data.frame()}}, but with a couple notable differences: \itemize{ \item The returned data frame has the class \code{\link[=tbl_df-class]{tbl_df}}, in addition to \code{data.frame}. This allows so-called "tibbles" to exhibit some special behaviour, such as \link[=formatting]{enhanced printing}. Tibbles are fully described in \code{\link[=tbl_df-class]{tbl_df}}. \item \code{tibble()} is much lazier than \code{\link[base:data.frame]{base::data.frame()}} in terms of transforming the user's input. Character vectors are not coerced to factor. List-columns are expressly anticipated and do not require special tricks. Column names are not modified. \item \code{tibble()} builds columns sequentially. When defining a column, you can refer to columns created earlier in the call. Only columns of length one are recycled. } } \examples{ # Unnamed arguments are named with their expression: a <- 1:5 tibble(a, a * 2) # Scalars (vectors of length one) are recycled: tibble(a, b = a * 2, c = 1) # Columns are available in subsequent expressions: tibble(x = runif(10), y = x * 2) # tibble() never coerces its inputs, str(tibble(letters)) str(tibble(x = list(diag(1), diag(2)))) # or munges column names (unless requested), tibble(`a + b` = 1:5) # but it forces you to take charge of names, if they need repair: try(tibble(x = 1, x = 2)) tibble(x = 1, x = 2, .name_repair = "unique") tibble(x = 1, x = 2, .name_repair = "minimal") ## By default, non-syntactic names are allowed, df <- tibble(`a 1` = 1, `a 2` = 2) ## because you can still index by name: df[["a 1"]] df$`a 1` with(df, `a 1`) ## Syntactic names are easier to work with, though, and you can request them: df <- tibble(`a 1` = 1, `a 2` = 2, .name_repair = "universal") df$a.1 ## You can specify your own name repair function: tibble(x = 1, x = 2, .name_repair = make.unique) fix_names <- function(x) gsub("\\\\s+", "_", x) tibble(`year 1` = 1, `year 2` = 2, .name_repair = fix_names) ## purrr-style anonymous functions and constants ## are also supported tibble(x = 1, x = 2, .name_repair = ~ make.names(., unique = TRUE)) tibble(x = 1, x = 2, .name_repair = ~ c("a", "b")) # Tibbles can contain columns that are tibbles or matrices # if the number of rows is consistent: tibble( a = 1:3, b = tibble( c = 4:6, d = 7:9 ), e = tibble( f = tibble( g = letters[1:3] ) ) ) tibble( a = 1:4, b = diag(4), c = cov(iris[1:4]) ) # data can not contain POSIXlt columns, or tibbles or matrices # with inconsistent number of rows: try(tibble(y = strptime("2000/01/01", "\%x"))) try(tibble(a = 1:3, b = tibble(c = 4:7))) # Use := to create columns with names that start with a dot: tibble(.rows = 3) tibble(.rows := 3) # You can unquote an expression: x <- 3 tibble(x = 1, y = x) tibble(x = 1, y = !!x) # You can splice-unquote a list of quosures and expressions: tibble(!!!list(x = rlang::quo(1:10), y = quote(x * 2))) } \seealso{ Use \code{\link[=as_tibble]{as_tibble()}} to turn an existing object into a tibble. Use \code{enframe()} to convert a named vector into tibble. Name repair is detailed in \link{name-repair}. \code{\link[rlang:list2]{rlang::list2()}} provides more details on tidy dots semantics, i.e. exactly how \link{quasiquotation} works for the \code{...} argument. } tibble/man/print.tbl_df.Rd0000644000176200001440000000060013407176030015137 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils-format.r \name{print.tbl_df} \alias{print.tbl_df} \title{Legacy help page for compatibility with existing packages} \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("archived")} Please see \code{\link[=print.tbl]{print.tbl()}} for the print method for tibbles. } \keyword{internal} tibble/man/add_row.Rd0000644000176200001440000000367313407176025014212 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()}}. Values can be defined only for columns that already exist in \code{.data} and unset columns will get an \code{NA} value. These arguments are passed on to \code{\link[=tibble]{tibble()}}, and therefore also support unquote via \code{!!} and unquote-splice via \code{!!!}. However, unlike in \pkg{dplyr} verbs, columns in \code{.data} are not available for the expressions.} \item{.before, .after}{One-based row index where to add the new rows, default: after last row.} } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("questioning")} 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. \code{add_case()} is an alias of \code{add_row()}. } \section{Life cycle}{ It is unclear if \code{add_row()} and its alias \code{add_cases()} should ensure that all columns have length one by wrapping in a list if necessary. See \url{https://github.com/tidyverse/tibble/pull/503} and \url{https://github.com/tidyverse/tibble/issues/205} for details. } \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}} } \concept{addition} tibble/man/reexports.Rd0000644000176200001440000000110513364701553014614 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{obj_sum} \alias{type_sum} \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.Rd0000644000176200001440000000340613407176030014414 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(.data) remove_rownames(.data) rownames_to_column(.data, var = "rowname") rowid_to_column(.data, var = "rowid") column_to_rownames(.data, var = "rowname") } \arguments{ \item{.data}{A data frame.} \item{var}{Name of column to use for rownames.} } \value{ \code{column_to_rownames()} always returns a data frame. \code{has_rownames()} returns a scalar logical. All other functions return an object of the same class as the input. } \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. } \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 head(column_to_rownames(mtcars_tbl)) } tibble/man/new_tibble.Rd0000644000176200001440000000464013473044414014677 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/new.R \name{new_tibble} \alias{new_tibble} \alias{validate_tibble} \title{Tibble constructor and validator} \usage{ new_tibble(x, ..., nrow, class = NULL, subclass = NULL) validate_tibble(x) } \arguments{ \item{x}{A tibble-like object} \item{...}{Passed on to \code{\link[=structure]{structure()}}} \item{nrow}{The number of rows, required} \item{class}{Subclasses to assign to the new object, default: none} \item{subclass}{Deprecated, retained for compatibility. Please use the \code{class} argument.} } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} Creates or validates a subclass of a tibble. These function is mostly useful for package authors that implement subclasses of a tibble, like \pkg{sf} or \pkg{tsibble}. \code{new_tibble()} creates a new object as a subclass of \code{tbl_df}, \code{tbl} and \code{data.frame}. This function is optimized for performance, checks are reduced to a minimum. \code{validate_tibble()} checks a tibble for internal consistency. Correct behavior can be guaranteed only if this function runs without raising an error. } \section{Construction}{ For \code{new_tibble()}, \code{x} must be a list. The \code{...} argument allows adding more attributes to the subclass. An \code{nrow} argument is required. This should be an integer of length 1, and every element of the list \code{x} should have \code{\link[=NROW]{NROW()}} equal to this value. (But this is not checked by the constructor). This takes the place of the "row.names" attribute in a data frame. \code{x} must have names (or be empty), but the names are not checked for correctness. } \section{Validation}{ \code{validate_tibble()} checks for "minimal" names and that all columns are vectors, data frames or matrices. It also makes sure that all columns have the same length, and that \code{\link[=NROW]{NROW()}} is consistent with the data. 1d arrays are not supported. } \examples{ # The nrow argument is always required: new_tibble(list(a = 1:3, b = 4:6), nrow = 3) # Existing row.names attributes are ignored: try(new_tibble(iris, nrow = 3)) # The length of all columns must be consistent with the nrow argument: try(new_tibble(list(a = 1:3, b = 4:6), nrow = 2)) } \seealso{ \code{\link[=tibble]{tibble()}} and \code{\link[=as_tibble]{as_tibble()}} for ways to construct a tibble with recycling of scalars and automatic name repair. } tibble/man/tbl_sum.Rd0000644000176200001440000000150113464363736014236 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} } \value{ A named character vector, describing the dimensions in the first element and the data source in the name of the first element. } \description{ \code{tbl_sum()} gives a brief textual description of a table-like object, which should include the dimensions and the data source in the first element, and additional information in the other elements (such as grouping for \pkg{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.Rd0000644000176200001440000000433513415444210015412 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tibble-package.R \docType{package} \name{tibble-package} \alias{tibble-package} \title{tibble: Simple Data Frames} \description{ \if{html}{\figure{logo.png}{options: align='right'}} Provides a 'tbl_df' class (the 'tibble') that provides stricter checking and better formatting than the traditional data frame. } \details{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("stable")} The tibble package provides utilities for handling \strong{tibbles}, where "tibble" is a colloquial term for the S3 \code{\link{tbl_df}} class. The \code{\link{tbl_df}} class is a special case of the base \code{\link[base:data.frame]{data.frame}}. class, developed in response to lessons learned over many years of data analysis with data frames. Tibble is the central data structure for the set of packages known as the \href{https://www.tidyverse.org/packages/}{tidyverse}, including \href{http://dplyr.tidyverse.org/}{dplyr}, \href{http://ggplot2.tidyverse.org/}{ggplot2}, \href{http://tidyr.tidyverse.org/}{tidyr}, and \href{http://readr.tidyverse.org/}{readr}. General resources: \itemize{ \item Website for the tibble package: \url{https://tibble.tidyverse.org} \item \href{http://r4ds.had.co.nz/tibbles.html}{Tibbles chapter} in \emph{R for Data Science} } Resources on specific topics: \itemize{ \item Create a tibble: \code{\link[=tibble]{tibble()}}, \code{\link[=as_tibble]{as_tibble()}}, \code{\link[=tribble]{tribble()}}, \code{\link[=enframe]{enframe()}} \item Inspect a tibble: \code{\link[=print.tbl]{print.tbl()}}, \code{\link[=glimpse]{glimpse()}} \item Details on the S3 \code{tbl_df} class: \code{\linkS4class{tbl_df}} } } \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 Jennifer Bryan \email{jenny@rstudio.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.Rd0000644000176200001440000000157713473044414014216 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tribble.R \name{tribble} \alias{tribble} \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. These arguments support \link[rlang:tidy-dots]{tidy dots}.} } \value{ A \link{tibble}. } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} 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. } \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/name-repair-retired.Rd0000644000176200001440000000410213407176025016413 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/repair-names.R \name{tidy_names} \alias{tidy_names} \alias{set_tidy_names} \alias{repair_names} \title{Retired functions for name repair} \usage{ tidy_names(name, syntactic = FALSE, quiet = FALSE) set_tidy_names(x, syntactic = FALSE, quiet = FALSE) repair_names(x, prefix = "V", sep = "") } \arguments{ \item{name}{A \code{names} attribute, usually a character vector.} \item{syntactic}{Should names be made syntactically valid? If \code{FALSE}, uses same logic as \code{.name_repair = "unique"}. If \code{TRUE}, uses same logic as \code{.name_repair = "universal"}.} \item{quiet}{Whether to suppress messages about name repair.} \item{x}{A vector.} \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 repaired names or a repaired version of \code{name}. } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("soft-deprecated")} \code{tidy_names()}, \code{set_tidy_names()}, and \code{repair_names()} were early efforts to facilitate \emph{post hoc} name repair in tibble, given that \code{\link[=tibble]{tibble()}} and \code{\link[=as_tibble]{as_tibble()}} did not do this. From tibble v2.0.0, the \code{.name_repair} argument gives direct access to three specific levels of name repair: \code{minimal}, \code{unique}, and \code{universal}. We recommend that new code use this instead of \code{tidy_names()}, \code{set_tidy_names()}, or \code{repair_names()}. After a period of use, the repair stategies behind \code{minimal}, \code{unique}, and \code{universal} are likely to be exposed in standalone functions and this could affect the behaviour of \code{tidy_names()}. \code{repair_names()} should be considered deprecated.\preformatted{tibble(..., `.name_repair = "unique"`) ## is preferred to df <- tibble(...) set_tidy_names(df, syntactic = FALSE) tibble(..., `.name_repair = "universal"`) ## is preferred to df <- tibble(...) set_tidy_names(df, syntactic = TRUE) } } \keyword{internal} tibble/man/formatting.Rd0000644000176200001440000000772513407176025014747 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils-format.r \name{formatting} \alias{formatting} \alias{print.tbl} \alias{format.tbl} \alias{trunc_mat} \title{Printing tibbles} \usage{ \method{print}{tbl}(x, ..., n = NULL, width = NULL, n_extra = NULL) \method{format}{tbl}(x, ..., n = NULL, width = NULL, n_extra = NULL) trunc_mat(x, n = NULL, width = NULL, n_extra = NULL) } \arguments{ \item{x}{Object to format or print.} \item{...}{Other arguments passed on to individual methods.} \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 \code{NULL}, which means use \code{getOption("tibble.width")} or (if also \code{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{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} One of the main features of the \code{tbl_df} class is the printing: \itemize{ \item Tibbles only print as many rows and columns as fit on one screen, supplemented by a summary of the remaining rows and columns. \item Tibble reveals the type of each column, which keeps the user informed about whether a variable is, e.g., \code{} or \code{} (character versus factor). } Printing can be tweaked for a one-off call by calling \code{print()} explicitly and setting arguments like \code{n} and \code{width}. More persistent control is available by setting the options described below. } \section{Package options}{ Options used by the tibble and pillar packages to format and print \code{tbl_df} objects. Used by the formatting workhorse \code{trunc_mat()} and, therefore, indirectly, by \code{print.tbl()}. \itemize{ \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. } \itemize{ \item \code{pillar.bold}: Use bold font, e.g. for column headers? This currently defaults to \code{FALSE}, because many terminal fonts have poor support for bold fonts. \item \code{pillar.subtle}: Use subtle style, e.g. for row numbers and data types? Default: \code{TRUE}. \item \code{pillar.subtle_num}: Use subtle style for insignificant digits? Default: \code{FALSE}, is also affected by the \code{pillar.subtle} option. \item \code{pillar.neg}: Highlight negative numbers? Default: \code{TRUE}. \item \code{pillar.sigfig}: The number of significant digits that will be printed and highlighted, default: \code{3}. Set the \code{pillar.subtle} option to \code{FALSE} to turn off highlighting of significant digits. \item \code{pillar.min_title_chars}: The minimum number of characters for the column title, default: \code{15}. Column titles may be truncated up to that width to save horizontal space. Set to \code{Inf} to turn off truncation of column titles. } } \examples{ print(as_tibble(mtcars)) print(as_tibble(mtcars), n = 1) print(as_tibble(mtcars), n = 3) print(as_tibble(iris), n = 100) print(mtcars, width = 10) mtcars2 <- as_tibble(cbind(mtcars, mtcars), .name_repair = "unique") print(mtcars2, n = 25, n_extra = 3) trunc_mat(mtcars) if (requireNamespace("nycflights13", quietly = TRUE)) { print(nycflights13::flights, n_extra = 2) print(nycflights13::flights, width = Inf) } } tibble/man/glimpse.Rd0000644000176200001440000000242313407176025014223 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{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} This is like a transposed version of \code{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)) { glimpse(nycflights13::flights) } } tibble/man/is.tibble.Rd0000644000176200001440000000060113407176025014432 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tibble.R \name{is.tibble} \alias{is.tibble} \title{Deprecated test for tibble-ness} \usage{ is.tibble(x) } \arguments{ \item{x}{An object} } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("soft-deprecated")} Please use \code{\link[=is_tibble]{is_tibble()}} instead. } \keyword{internal} tibble/man/is_tibble.Rd0000644000176200001440000000070113407176030014510 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tibble.R \name{is_tibble} \alias{is_tibble} \title{Test if the object is a tibble} \usage{ is_tibble(x) } \arguments{ \item{x}{An object} } \value{ \code{TRUE} if the object inherits from the \code{tbl_df} class. } \description{ This function returns \code{TRUE} for tibbles or subclasses thereof, and \code{FALSE} for all other objects, including regular data frames. } tibble/man/name-repair.Rd0000644000176200001440000001402413464363736014775 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/repair-names.R \name{name-repair} \alias{name-repair} \title{Repair the names of a vector} \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} tibble deals with a few levels of name repair: \itemize{ \item \code{minimal} names exist. The \code{names} attribute is not \code{NULL}. The name of an unnamed element is \code{""} and never \code{NA}. Tibbles created by the tibble package have names that are, at least, \code{minimal}. \item \code{unique} names are \code{minimal}, have no duplicates, and can be used where a variable name is expected. Empty names, and \code{...} or \code{..} followed by a sequence of digits are banned. \itemize{ \item All columns can be accessed by name via \code{df[["name"]]} and \code{df$`name`} and \code{with(df, `name`)}. } \item \code{universal} names are \code{unique} and syntactic (see Details for more). \itemize{ \item Names work everywhere, without quoting: \code{df$name} and \code{with(df, name)} and \code{lm(name1 ~ name2, data = df)} and \code{dplyr::select(df, name)} all work. } } \code{universal} implies \code{unique}, \code{unique} implies \code{minimal}. These levels are nested. The \code{.name_repair} argument of \code{\link[=tibble]{tibble()}} and \code{\link[=as_tibble]{as_tibble()}} refers to these levels. Alternatively, the user can pass their own name repair function. It should anticipate \code{minimal} names as input and should, likewise, return names that are at least \code{minimal}. The existing functions \code{\link[=tidy_names]{tidy_names()}}, \code{\link[=set_tidy_names]{set_tidy_names()}}, and \code{\link[=repair_names]{repair_names()}} are soft-deprecated. } \section{\code{minimal} names}{ \code{minimal} names exist. The \code{names} attribute is not \code{NULL}. The name of an unnamed element is \code{""} and never \code{NA}. Examples:\preformatted{Original names of a vector with length 3: NULL minimal names: "" "" "" Original names: "x" NA minimal names: "x" "" } Request \code{.name_repair = "minimal"} to suppress almost all name munging. This is useful when the first row of a data source -- allegedly variable names -- actually contains \emph{data} and the resulting tibble is destined for reshaping with, e.g., \code{tidyr::gather()}. } \section{\code{unique} names}{ \code{unique} names are \code{minimal}, have no duplicates, and can be used (possibly with backticks) in contexts where a variable is expected. Empty names, and \code{...} or \code{..} followed by a sequence of digits are banned If a data frame has \code{unique} names, you can index it by name, and also access the columns by name. In particular, \code{df[["name"]]} and \code{df$`name`} and also \code{with(df, `name`)} always work. There are many ways to make names \code{unique}. We append a suffix of the form \code{...j} to any name that is \code{""} or a duplicate, where \code{j} is the position. We also change \code{..#} and \code{...} to \code{...#}. Example:\preformatted{Original names: "" "x" "" "y" "x" "..2" "..." unique names: "...1" "x...2" "...3" "y" "x...5" "...6" "...7" } Pre-existing suffixes of the form \code{...j} are always stripped, prior to making names \code{unique}, i.e. reconstructing the suffixes. If this interacts poorly with your names, you should take control of name repair. } \section{\code{universal} names}{ \code{universal} names are \code{unique} and syntactic, meaning they: \itemize{ \item Are never empty (inherited from \code{unique}). \item Have no duplicates (inherited from \code{unique}). \item Are not \code{...}. Do not have the form \code{..i}, where \code{i} is a number (inherited from \code{unique}). \item Consist of letters, numbers, and the dot \code{.} or underscore \code{_} characters. \item Start with a letter or start with the dot \code{.} not followed by a number. \item Are not a \link{reserved} word, e.g., \code{if} or \code{function} or \code{TRUE}. } If a data frame has \code{universal} names, variable names can be used "as is" in code. They work well with nonstandard evaluation, e.g., \code{df$name} works. Tibble has a different method of making names syntactic than \code{\link[base:make.names]{base::make.names()}}. In general, tibble prepends one or more dots \code{.} until the name is syntactic. Examples:\preformatted{ Original names: "" "x" NA "x" universal names: "...1" "x...2" "...3" "x...4" Original names: "(y)" "_z" ".2fa" "FALSE" universal names: ".y." "._z" "..2fa" ".FALSE" } } \examples{ \dontrun{ ## by default, duplicate names are not allowed tibble(x = 1, x = 2) } ## you can authorize duplicate names tibble(x = 1, x = 2, .name_repair = "minimal") ## or request that the names be made unique tibble(x = 1, x = 2, .name_repair = "unique") ## by default, non-syntactic names are allowed df <- tibble(`a 1` = 1, `a 2` = 2) ## because you can still index by name df[["a 1"]] df$`a 1` ## syntactic names are easier to work with, though, and you can request them df <- tibble(`a 1` = 1, `a 2` = 2, .name_repair = "universal") df$a.1 ## you can specify your own name repair function tibble(x = 1, x = 2, .name_repair = make.unique) fix_names <- function(x) gsub("\%", " percent", x) tibble(`25\%` = 1, `75\%` = 2, .name_repair = fix_names) fix_names <- function(x) gsub("\\\\s+", "_", x) tibble(`year 1` = 1, `year 2` = 2, .name_repair = fix_names) ## purrr-style anonymous functions and constants ## are also supported tibble(x = 1, x = 2, .name_repair = ~ make.names(., unique = TRUE)) tibble(x = 1, x = 2, .name_repair = ~ c("a", "b")) ## the names attibute will be non-NULL, with "" as the default element df <- as_tibble(list(1:3, letters[1:3]), .name_repair = "minimal") names(df) } \seealso{ \code{\link[rlang:names2]{rlang::names2()}} returns the names of an object, after making them \code{minimal}. The \href{https://principles.tidyverse.org/names-attribute.html}{Names attribute} section in the "tidyverse package development principles". } tibble/man/frame_matrix.Rd0000644000176200001440000000153013473044414015236 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. These arguments support \link[rlang:tidy-dots]{tidy dots}.} } \value{ A \link{matrix}. } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("maturing")} 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/man/view.Rd0000644000176200001440000000112713407176025013535 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/view.R \name{view} \alias{view} \title{View an object} \usage{ view(x, title = NULL, ...) } \arguments{ \item{x}{The object to display.} \item{title}{The title to use for the display, by default the deparsed expression is used.} \item{...}{Unused, for extensibility.} } \description{ \Sexpr[results=rd, stage=render]{tibble:::lifecycle("experimental")} Calls \code{\link[utils:View]{utils::View()}} on the input and returns it, invisibly. The RStudio IDE overrides \code{utils::View()}, this is picked up correctly. } tibble/LICENSE0000644000176200001440000000005213204634213012513 0ustar liggesusersYEAR: 2013-2017 COPYRIGHT HOLDER: RStudio