Binary files /tmp/tmp_i327gk9/mq1L8dcwt5/r-cran-tidyselect-1.1.2+dfsg/build/vignette.rds and /tmp/tmp_i327gk9/OIIwI3fmri/r-cran-tidyselect-1.2.0+dfsg/build/vignette.rds differ diff -Nru r-cran-tidyselect-1.1.2+dfsg/debian/changelog r-cran-tidyselect-1.2.0+dfsg/debian/changelog --- r-cran-tidyselect-1.1.2+dfsg/debian/changelog 2022-02-21 17:59:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/debian/changelog 2022-10-14 10:15:14.000000000 +0000 @@ -1,3 +1,12 @@ +r-cran-tidyselect (1.2.0+dfsg-1) unstable; urgency=medium + + * New upstream version + * Standards-Version: 4.6.1 (routine-update) + * dh-update-R to update Build-Depends (routine-update) + * Add suggests from DESCRIPTION to Test-Depends + + -- Andreas Tille Fri, 14 Oct 2022 12:15:14 +0200 + r-cran-tidyselect (1.1.2+dfsg-1) unstable; urgency=medium [ Andreas Tille ] diff -Nru r-cran-tidyselect-1.1.2+dfsg/debian/control r-cran-tidyselect-1.2.0+dfsg/debian/control --- r-cran-tidyselect-1.1.2+dfsg/debian/control 2022-02-21 17:57:53.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/debian/control 2022-10-14 10:15:14.000000000 +0000 @@ -7,12 +7,13 @@ Build-Depends: debhelper-compat (= 13), dh-r, r-base-dev, - r-cran-ellipsis, + r-cran-cli (>= 3.3.0), r-cran-glue, - r-cran-purrr (>= 0.3.2), - r-cran-rlang (>= 1.0.1), - r-cran-vctrs -Standards-Version: 4.6.0 + r-cran-lifecycle (>= 1.0.3), + r-cran-rlang (>= 1.0.4), + r-cran-vctrs (>= 0.4.1), + r-cran-withr +Standards-Version: 4.6.1 Vcs-Browser: https://salsa.debian.org/r-pkg-team/r-cran-tidyselect Vcs-Git: https://salsa.debian.org/r-pkg-team/r-cran-tidyselect.git Homepage: https://cran.r-project.org/package=tidyselect @@ -21,7 +22,6 @@ Package: r-cran-tidyselect Architecture: any Depends: ${R:Depends}, - ${shlibs:Depends}, ${misc:Depends} Recommends: ${R:Recommends} Suggests: ${R:Suggests} diff -Nru r-cran-tidyselect-1.1.2+dfsg/debian/tests/control r-cran-tidyselect-1.2.0+dfsg/debian/tests/control --- r-cran-tidyselect-1.1.2+dfsg/debian/tests/control 2022-02-21 17:57:16.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/debian/tests/control 2022-10-14 10:15:14.000000000 +0000 @@ -1,5 +1,13 @@ Tests: run-unit-test -Depends: @, r-cran-testthat, +Depends: @, + r-cran-covr, + r-cran-crayon, + r-cran-dplyr, + r-cran-knitr, + r-cran-magrittr, + r-cran-rmarkdown, + r-cran-stringr, + r-cran-testthat, + r-cran-tibble Restrictions: allow-stderr - diff -Nru r-cran-tidyselect-1.1.2+dfsg/DESCRIPTION r-cran-tidyselect-1.2.0+dfsg/DESCRIPTION --- r-cran-tidyselect-1.1.2+dfsg/DESCRIPTION 2022-02-21 16:00:02.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/DESCRIPTION 2022-10-10 19:00:02.000000000 +0000 @@ -1,33 +1,34 @@ Package: tidyselect Title: Select from a Set of Strings -Version: 1.1.2 +Version: 1.2.0 Authors@R: c( - person("Lionel", "Henry", ,"lionel@rstudio.com", c("aut", "cre")), - person("Hadley", "Wickham", ,"hadley@rstudio.com", "aut"), - person("RStudio", role = "cph") - ) -Description: A backend for the selecting functions of the 'tidyverse'. - It makes it easy to implement select-like functions in your own - packages in a way that is consistent with other 'tidyverse' - interfaces for selection. -Depends: R (>= 3.2) -Imports: ellipsis, glue (>= 1.3.0), purrr (>= 0.3.2), rlang (>= 1.0.1), - vctrs (>= 0.3.0) -Suggests: covr, crayon, dplyr, knitr, magrittr, rmarkdown, testthat (>= - 3.1.1), tibble (>= 2.1.3), withr + person("Lionel", "Henry", , "lionel@rstudio.com", role = c("aut", "cre")), + person("Hadley", "Wickham", , "hadley@rstudio.com", role = "aut"), + person("RStudio", role = c("cph", "fnd")) + ) +Description: A backend for the selecting functions of the 'tidyverse'. It + makes it easy to implement select-like functions in your own packages + in a way that is consistent with other 'tidyverse' interfaces for + selection. License: MIT + file LICENSE -Encoding: UTF-8 -ByteCompile: true -RoxygenNote: 7.1.2 URL: https://tidyselect.r-lib.org, https://github.com/r-lib/tidyselect BugReports: https://github.com/r-lib/tidyselect/issues +Depends: R (>= 3.4) +Imports: cli (>= 3.3.0), glue (>= 1.3.0), lifecycle (>= 1.0.3), rlang + (>= 1.0.4), vctrs (>= 0.4.1), withr +Suggests: covr, crayon, dplyr, knitr, magrittr, rmarkdown, stringr, + testthat (>= 3.1.1), tibble (>= 2.1.3) VignetteBuilder: knitr +ByteCompile: true Config/testthat/edition: 3 -NeedsCompilation: yes -Packaged: 2022-02-21 14:59:24 UTC; lionel +Config/Needs/website: tidyverse/tidytemplate +Encoding: UTF-8 +RoxygenNote: 7.2.1 +NeedsCompilation: no +Packaged: 2022-10-10 14:09:03 UTC; hadleywickham Author: Lionel Henry [aut, cre], Hadley Wickham [aut], - RStudio [cph] + RStudio [cph, fnd] Maintainer: Lionel Henry Repository: CRAN -Date/Publication: 2022-02-21 16:00:02 UTC +Date/Publication: 2022-10-10 19:00:02 UTC diff -Nru r-cran-tidyselect-1.1.2+dfsg/inst/doc/syntax.R r-cran-tidyselect-1.2.0+dfsg/inst/doc/syntax.R --- r-cran-tidyselect-1.1.2+dfsg/inst/doc/syntax.R 2022-02-21 14:59:22.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/inst/doc/syntax.R 2022-10-10 14:09:02.000000000 +0000 @@ -29,9 +29,9 @@ } ## ----------------------------------------------------------------------------- -mtcars %>% select_loc(mpg:hp, -cyl, vs) +mtcars %>% select_loc(mpg:hp, !cyl, vs) -mtcars %>% select_loc(1:4, -2, 8) +mtcars %>% select_loc(1:4, !2, 8) ## ----------------------------------------------------------------------------- mtcars %>% select_loc(2:4) @@ -61,35 +61,6 @@ iris %>% select_loc(starts_with("Sepal") | ends_with("Width") | Species) -iris %>% select_loc(union(union(starts_with("Sepal"), ends_with("Width")), 5L)) - -## ----------------------------------------------------------------------------- -iris %>% select_loc(starts_with("Sepal"), -ends_with("Width"), -Sepal.Length) - -iris %>% select_loc(setdiff(setdiff(starts_with("Sepal"), ends_with("Width")), 1L)) - -## ----------------------------------------------------------------------------- -iris %>% select_loc(-starts_with("Sepal")) - -iris %>% select_loc(everything(), -starts_with("Sepal")) - -iris %>% select_loc(setdiff(everything(), starts_with("Sepal"))) - -## ----------------------------------------------------------------------------- -iris %>% select_loc(-starts_with("Sepal")) - -iris %>% select_loc(!starts_with("Sepal")) - -## ----------------------------------------------------------------------------- -iris %>% select_loc(c(starts_with("Sepal"), -Sepal.Length)) - -iris %>% select_loc(c(starts_with("Sepal"), c(-Sepal.Length))) - -## ----------------------------------------------------------------------------- -iris %>% select_loc(starts_with("Sepal") & !Sepal.Length) - -iris %>% select_loc(starts_with("Sepal") | !Sepal.Length) - ## ----------------------------------------------------------------------------- mtcars %>% select_loc(foo = c(bar = mpg, baz = cyl)) diff -Nru r-cran-tidyselect-1.1.2+dfsg/inst/doc/syntax.Rmd r-cran-tidyselect-1.2.0+dfsg/inst/doc/syntax.Rmd --- r-cran-tidyselect-1.1.2+dfsg/inst/doc/syntax.Rmd 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/inst/doc/syntax.Rmd 2022-09-20 21:56:55.000000000 +0000 @@ -61,10 +61,13 @@ renaming a variable to multiple names (see section on Renaming variables). -The syntax of tidyselect is generally designed for set combination. -For instance, `c(foo(), bar())` represents the union of the variables -in `foo()` and those in `bar()`. - +Today, the syntax of tidyselect is generally designed around Boolean algebra, +i.e. we recommend writing `starts_with("a") & !ends_with("z")`. Earlier +versions of tidyselect had more of a flavour of set operations, so that +you'd write `starts_with("a") - ends_with("b")`. While the set operations are +still supported, and is how tidyselect represents variables internally, we no +longer recommend them because Boolean algebra is easy for people to +understand. ### Bare names @@ -73,12 +76,11 @@ expressions are equivalent: ```{r} -mtcars %>% select_loc(mpg:hp, -cyl, vs) +mtcars %>% select_loc(mpg:hp, !cyl, vs) -mtcars %>% select_loc(1:4, -2, 8) +mtcars %>% select_loc(1:4, !2, 8) ``` - ### The `:` operator `:` can be used to select consecutive variables between two locations. @@ -95,16 +97,8 @@ mtcars %>% select_loc(cyl:hp) ``` - ### Boolean operators -Boolean operators provide a more intuitive approach to set -combination. Though sets are internally represented with vectors of -locations, they could equally be represented with a full logical -vector of inclusion indicators (taking the `which()` of this vector -would then recover the locations). The boolean operators should be -considered in terms of the logical representation of sets. - The `|` operator takes the __union__ of two sets: ```{r} @@ -130,11 +124,10 @@ iris %>% select_loc(starts_with("Sepal") & !ends_with("Width")) ``` +### Dots and `c()` -### Dots, `c()`, and unary `-` - -tidyselect functions can take dots like `dplyr::select()`, or a named -argument like `tidyr::pivot_longer()`. In the latter case, the dots +tidyselect functions can take dots, like `dplyr::select()`, or a named +argument, like `tidyr::pivot_longer()`. In the latter case, the dots syntax is accessible via `c()`. In fact `...` syntax is implemented through `c(...)` and is thus completely equivalent. @@ -144,72 +137,14 @@ mtcars %>% select_loc(c(mpg, disp:hp)) ``` -Dots and `c()` are syntax for: - -* Set union or set difference -* Renaming variables - -Non-negative inputs are recursively joined with `union()`. The -precedence is left-associative, just like with boolean operators. -These expressions are all syntax for _set union_: +`c(x, y, z)` is a equivalent to `x | y | z`: ```{r} iris %>% select_loc(starts_with("Sepal"), ends_with("Width"), Species) iris %>% select_loc(starts_with("Sepal") | ends_with("Width") | Species) - -iris %>% select_loc(union(union(starts_with("Sepal"), ends_with("Width")), 5L)) -``` - -Unary `-` is normally syntax for _set difference_: - -```{r} -iris %>% select_loc(starts_with("Sepal"), -ends_with("Width"), -Sepal.Length) - -iris %>% select_loc(setdiff(setdiff(starts_with("Sepal"), ends_with("Width")), 1L)) -``` - -If the first `...` or `c()` input is negative, an implicit -`everything()` is appended. - -```{r} -iris %>% select_loc(-starts_with("Sepal")) - -iris %>% select_loc(everything(), -starts_with("Sepal")) - -iris %>% select_loc(setdiff(everything(), starts_with("Sepal"))) -``` - -In this case, unary `-` is syntax for _set complement_. Unary `-` and -`!` are equivalent: - -```{r} -iris %>% select_loc(-starts_with("Sepal")) - -iris %>% select_loc(!starts_with("Sepal")) -``` - -Each level of `c()` is independent. In particular, a nested `c()` -starting with `-` always stands for set complement: - -```{r} -iris %>% select_loc(c(starts_with("Sepal"), -Sepal.Length)) - -iris %>% select_loc(c(starts_with("Sepal"), c(-Sepal.Length))) ``` -In boolean terms, these expressions are equivalent to: - -```{r} -iris %>% select_loc(starts_with("Sepal") & !Sepal.Length) - -iris %>% select_loc(starts_with("Sepal") | !Sepal.Length) -``` - -In general, when unary `-` is used alone outside `...` or `c()`, it -stands for set complement. - - ### Renaming variables #### Name combination and propagation diff -Nru r-cran-tidyselect-1.1.2+dfsg/inst/doc/tidyselect.Rmd r-cran-tidyselect-1.2.0+dfsg/inst/doc/tidyselect.Rmd --- r-cran-tidyselect-1.1.2+dfsg/inst/doc/tidyselect.Rmd 2021-04-29 11:38:06.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/inst/doc/tidyselect.Rmd 2022-09-20 21:56:55.000000000 +0000 @@ -37,8 +37,7 @@ In this vignette, we describe how to include tidyselect in your own packages. If you just want to know how to use tidyselect syntax in -dplyr or tidyr, please read -instead. +dplyr or tidyr, please read `?language` instead. ## Before we start diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/all_of.Rd r-cran-tidyselect-1.2.0+dfsg/man/all_of.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/all_of.Rd 2022-02-21 13:57:15.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/all_of.Rd 2022-10-10 12:28:27.000000000 +0000 @@ -37,13 +37,17 @@ Selection helpers can be used in functions like \code{dplyr::select()} -or \code{tidyr::pivot_longer()}. Let's first attach the tidyverse:\if{html}{\out{
}}\preformatted{library(tidyverse) +or \code{tidyr::pivot_longer()}. Let's first attach the tidyverse: + +\if{html}{\out{
}}\preformatted{library(tidyverse) # For better printing iris <- as_tibble(iris) }\if{html}{\out{
}} -It is a common to have a names of variables in a vector.\if{html}{\out{
}}\preformatted{vars <- c("Sepal.Length", "Sepal.Width") +It is a common to have a names of variables in a vector. + +\if{html}{\out{
}}\preformatted{vars <- c("Sepal.Length", "Sepal.Width") iris[, vars] #> # A tibble: 150 x 2 @@ -56,7 +60,9 @@ #> # ... with 146 more rows }\if{html}{\out{
}} -To refer to these variables in selecting function, use \code{all_of()}:\if{html}{\out{
}}\preformatted{iris \%>\% select(all_of(vars)) +To refer to these variables in selecting function, use \code{all_of()}: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(all_of(vars)) #> # A tibble: 150 x 2 #> Sepal.Length Sepal.Width #> @@ -77,18 +83,26 @@ #> # ... with 296 more rows }\if{html}{\out{
}} -If any of the variable is missing from the data frame, that's an error:\if{html}{\out{
}}\preformatted{starwars \%>\% select(all_of(vars)) -}\if{html}{\out{
}}\preformatted{## Error: -## ! Can't subset columns that don't exist. -## x Columns `Sepal.Length` and `Sepal.Width` don't exist. -} +If any of the variable is missing from the data frame, that's an error: -Use \code{any_of()} to allow missing variables:\if{html}{\out{
}}\preformatted{starwars \%>\% select(any_of(vars)) +\if{html}{\out{
}}\preformatted{starwars \%>\% select(all_of(vars)) +#> Error: +#> ! Problem while evaluating `all_of(vars)`. +#> Caused by error in `all_of()`: +#> ! Can't subset elements that don't exist. +#> x Elements `Sepal.Length` and `Sepal.Width` don't exist. +}\if{html}{\out{
}} + +Use \code{any_of()} to allow missing variables: + +\if{html}{\out{
}}\preformatted{starwars \%>\% select(any_of(vars)) #> # A tibble: 87 x 0 }\if{html}{\out{
}} \code{any_of()} is especially useful to remove variables from a data -frame because calling it again does not cause an error:\if{html}{\out{
}}\preformatted{iris \%>\% select(-any_of(vars)) +frame because calling it again does not cause an error: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(-any_of(vars)) #> # A tibble: 150 x 3 #> Petal.Length Petal.Width Species #> diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/eval_relocate.Rd r-cran-tidyselect-1.2.0+dfsg/man/eval_relocate.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/eval_relocate.Rd 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/eval_relocate.Rd 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,120 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/eval-relocate.R +\name{eval_relocate} +\alias{eval_relocate} +\title{Evaluate an expression to relocate variables} +\usage{ +eval_relocate( + expr, + data, + ..., + before = NULL, + after = NULL, + strict = TRUE, + name_spec = NULL, + allow_rename = TRUE, + allow_empty = TRUE, + allow_predicates = TRUE, + before_arg = "before", + after_arg = "after", + env = caller_env(), + error_call = caller_env() +) +} +\arguments{ +\item{expr}{Defused R code describing a selection according to the +tidyselect syntax.} + +\item{data}{A named list, data frame, or atomic vector. +Technically, \code{data} can be any vector with \code{names()} and \code{"[["} +implementations.} + +\item{...}{These dots are for future extensions and must be empty.} + +\item{before, after}{Defused R code describing a selection according to the +tidyselect syntax. The selection represents the destination of the +selection provided through \code{expr}. Supplying neither of these will move the +selection to the left-hand side. Supplying both of these is an error.} + +\item{strict}{If \code{TRUE}, out-of-bounds errors are thrown if \code{expr} +attempts to select or rename a variable that doesn't exist. If +\code{FALSE}, failed selections or renamings are ignored.} + +\item{name_spec}{A name specification describing how to combine or +propagate names. This is used only in case nested \code{c()} +expressions like \code{c(foo = c(bar = starts_with("foo")))}. See the +\code{name_spec} argument of \code{\link[vctrs:vec_c]{vctrs::vec_c()}} for a description of +valid name specs.} + +\item{allow_rename}{If \code{TRUE} (the default), the renaming syntax +\code{c(foo = bar)} is allowed. If \code{FALSE}, it causes an error. This +is useful to implement purely selective behaviour.} + +\item{allow_empty}{If \code{TRUE} (the default), it is ok for \code{expr} to result +in an empty selection. If \code{FALSE}, will error if \code{expr} yields an empty +selection.} + +\item{allow_predicates}{If \code{TRUE} (the default), it is ok for \code{expr} to +use predicates (i.e. in \code{where()}). If \code{FALSE}, will error if \code{expr} uses a +predicate. Will automatically be set to \code{FALSE} if \code{data} does not +support predicates (as determined by \code{\link[=tidyselect_data_has_predicates]{tidyselect_data_has_predicates()}}).} + +\item{before_arg, after_arg}{Argument names for \code{before} and \code{after}. These +are used in error messages.} + +\item{env}{The environment in which to evaluate \code{expr}. Discarded +if \code{expr} is a \link[rlang:enquo]{quosure}.} + +\item{error_call}{The execution environment of a currently +running function, e.g. \code{caller_env()}. The function will be +mentioned in error messages as the source of the error. See the +\code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} +} +\value{ +A named vector of numeric locations with length equal to \code{length(data)}. +Each position in \code{data} will be represented exactly once. + +The names are normally the same as in the input data, except when the user +supplied named selections with \code{c()}. In the latter case, the names reflect +the new names chosen by the user. +} +\description{ +\code{eval_relocate()} is a variant of \code{\link[=eval_select]{eval_select()}} that moves a selection to +a new location. Either \code{before} or \code{after} can be provided to specify where +to move the selection to. This powers \code{dplyr::relocate()}. +} +\examples{ +library(rlang) + +# Interpret defused code as a request to relocate +x <- expr(c(mpg, disp)) +after <- expr(wt) +eval_relocate(x, mtcars, after = after) + +# Supplying neither `before` nor `after` will move the selection to the +# left-hand side +eval_relocate(x, mtcars) + +# Within a function, use `enquo()` to defuse a single argument. +# Note that `before` and `after` must also be defused with `enquo()`. +my_relocator <- function(x, expr, before = NULL, after = NULL) { + eval_relocate(enquo(expr), x, before = enquo(before), after = enquo(after)) +} + +my_relocator(mtcars, vs, before = hp) + +# Here is an example of using `eval_relocate()` to implement `relocate()`. +# Note that the dots are passed on as a defused call to `c(...)`. +relocate <- function(.x, ..., .before = NULL, .after = NULL) { + pos <- eval_relocate( + expr(c(...)), + .x, + before = enquo(.before), + after = enquo(.after) + ) + set_names(.x[pos], names(pos)) +} + +relocate(mtcars, vs, .before = hp) +relocate(mtcars, starts_with("d"), .after = last_col()) +} diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/eval_select.Rd r-cran-tidyselect-1.2.0+dfsg/man/eval_select.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/eval_select.Rd 2022-01-26 16:41:28.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/eval_select.Rd 2022-09-20 21:56:55.000000000 +0000 @@ -12,6 +12,7 @@ ..., strict = TRUE, name_spec = NULL, + allow_predicates = TRUE, error_call = caller_env() ) @@ -25,6 +26,8 @@ strict = TRUE, name_spec = NULL, allow_rename = TRUE, + allow_empty = TRUE, + allow_predicates = TRUE, error_call = caller_env() ) } @@ -51,6 +54,11 @@ \code{name_spec} argument of \code{\link[vctrs:vec_c]{vctrs::vec_c()}} for a description of valid name specs.} +\item{allow_predicates}{If \code{TRUE} (the default), it is ok for \code{expr} to +use predicates (i.e. in \code{where()}). If \code{FALSE}, will error if \code{expr} uses a +predicate. Will automatically be set to \code{FALSE} if \code{data} does not +support predicates (as determined by \code{\link[=tidyselect_data_has_predicates]{tidyselect_data_has_predicates()}}).} + \item{error_call}{The execution environment of a currently running function, e.g. \code{caller_env()}. The function will be mentioned in error messages as the source of the error. See the @@ -62,6 +70,10 @@ \item{allow_rename}{If \code{TRUE} (the default), the renaming syntax \code{c(foo = bar)} is allowed. If \code{FALSE}, it causes an error. This is useful to implement purely selective behaviour.} + +\item{allow_empty}{If \code{TRUE} (the default), it is ok for \code{expr} to result +in an empty selection. If \code{FALSE}, will error if \code{expr} yields an empty +selection.} } \value{ A named vector of numeric locations, one for each of the diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/everything.Rd r-cran-tidyselect-1.2.0+dfsg/man/everything.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/everything.Rd 2022-01-26 15:55:52.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/everything.Rd 2022-09-20 21:56:55.000000000 +0000 @@ -28,14 +28,18 @@ Selection helpers can be used in functions like \code{dplyr::select()} -or \code{tidyr::pivot_longer()}. Let's first attach the tidyverse:\if{html}{\out{
}}\preformatted{library(tidyverse) +or \code{tidyr::pivot_longer()}. Let's first attach the tidyverse: + +\if{html}{\out{
}}\preformatted{library(tidyverse) # For better printing iris <- as_tibble(iris) mtcars <- as_tibble(mtcars) }\if{html}{\out{
}} -Use \code{everything()} to select all variables:\if{html}{\out{
}}\preformatted{iris \%>\% select(everything()) +Use \code{everything()} to select all variables: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(everything()) #> # A tibble: 150 x 5 #> Sepal.Length Sepal.Width Petal.Length Petal.Width Species #> @@ -56,7 +60,9 @@ #> # ... with 348 more rows }\if{html}{\out{
}} -Use \code{last_col()} to select the last variable:\if{html}{\out{
}}\preformatted{iris \%>\% select(last_col()) +Use \code{last_col()} to select the last variable: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(last_col()) #> # A tibble: 150 x 1 #> Species #> @@ -78,7 +84,9 @@ }\if{html}{\out{
}} Supply an offset \code{n} to select a variable located \code{n} positions -from the end:\if{html}{\out{
}}\preformatted{mtcars \%>\% select(1:last_col(5)) +from the end: + +\if{html}{\out{
}}\preformatted{mtcars \%>\% select(1:last_col(5)) #> # A tibble: 32 x 6 #> mpg cyl disp hp drat wt #> diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/faq/selection-context.Rmd r-cran-tidyselect-1.2.0+dfsg/man/faq/selection-context.Rmd --- r-cran-tidyselect-1.1.2+dfsg/man/faq/selection-context.Rmd 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/faq/selection-context.Rmd 2022-09-20 21:56:55.000000000 +0000 @@ -3,12 +3,8 @@ ``` Functions like `starts_with()`, `contains()` or `matches()` are -__selection helpers__ that only work in a selection context. - -Examples of valid selection contexts are: - -- Inside `dplyr::select()`. -- The `cols` argument of `tidyr::pivot_longer()`. +__selection helpers__ that only work in a selection context, e.g. +`dplyr::select()` or the `cols` argument of `tidyr::pivot_longer()`. Using a selection helper anywhere else results in an error: @@ -20,6 +16,24 @@ subset(mtcars, select = matches("foo")) ``` -If you see this error, you've probably used a selection helper in the +If you see this error, you may have used a selection helper in the wrong place, possibly as the result of a typo (e.g. misplaced comma or -wrong argument name). +wrong argument name). Alternatively, you may be deliberately trying +to reduce duplication in your code by extracting out a selection into +a variable: + +```{r, error = TRUE} +my_vars <- c(name, species, ends_with("color")) +``` + +To make this work you'll need to do two things: + +* Wrap the whole thing in a function +* Use `any_of()` or `all_of()` instead of bare variable names + +```{r} +my_vars <- function() { + c(any_of(c("name", "species")), ends_with("color")) +} +dplyr::select(starwars, my_vars()) +``` diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/faq-external-vector.Rd r-cran-tidyselect-1.2.0+dfsg/man/faq-external-vector.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/faq-external-vector.Rd 2022-01-26 15:55:52.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/faq-external-vector.Rd 2022-10-10 14:07:38.000000000 +0000 @@ -7,7 +7,9 @@ \subsection{Ambiguity between columns and external variables}{ With selecting functions like \code{dplyr::select()} or -\code{tidyr::pivot_longer()}, you can refer to variables by name:\if{html}{\out{
}}\preformatted{mtcars \%>\% select(cyl, am, vs) +\code{tidyr::pivot_longer()}, you can refer to variables by name: + +\if{html}{\out{
}}\preformatted{mtcars \%>\% select(cyl, am, vs) #> # A tibble: 32 x 3 #> cyl am vs #> @@ -31,30 +33,45 @@ For historical reasons, it is also possible to refer an external vector of variable names. You get the correct result, but with a note informing you that selecting with an external variable is ambiguous because it is -not clear whether you want a data frame column or an external object.\if{html}{\out{
}}\preformatted{vars <- c("cyl", "am", "vs") +not clear whether you want a data frame column or an external object. + +\if{html}{\out{
}}\preformatted{vars <- c("cyl", "am", "vs") result <- mtcars \%>\% select(vars) -#> Note: Using an external vector in selections is ambiguous. -#> i Use `all_of(vars)` instead of `vars` to silence this message. -#> i See . -#> This message is displayed once per session. +#> Warning: Using an external vector in selections was deprecated in +#> tidyselect 1.1.0. +#> i Please use `all_of()` or `any_of()` instead. +#> # Was: +#> data \%>\% select(vars) +#> +#> # Now: +#> data \%>\% select(all_of(vars)) +#> +#> See +#> . }\if{html}{\out{
}} This note will become a warning in the future, and then an error. We have decided to deprecate this particular approach to using external vectors because they introduce ambiguity. Imagine that the data frame -contains a column with the same name as your external variable.\if{html}{\out{
}}\preformatted{some_df <- mtcars[1:4, ] +contains a column with the same name as your external variable. + +\if{html}{\out{
}}\preformatted{some_df <- mtcars[1:4, ] some_df$vars <- 1:nrow(some_df) }\if{html}{\out{
}} These are very different objects but it isn’t a problem if the context -forces you to be specific about where to find \code{vars}:\if{html}{\out{
}}\preformatted{vars +forces you to be specific about where to find \code{vars}: + +\if{html}{\out{
}}\preformatted{vars #> [1] "cyl" "am" "vs" some_df$vars #> [1] 1 2 3 4 }\if{html}{\out{
}} -In a selection context however, the column wins:\if{html}{\out{
}}\preformatted{some_df \%>\% select(vars) +In a selection context however, the column wins: + +\if{html}{\out{
}}\preformatted{some_df \%>\% select(vars) #> # A tibble: 4 x 1 #> vars #> @@ -68,7 +85,9 @@ \subsection{Fixing the ambiguity}{ To make your selection code more robust and silence the message, use -\code{all_of()} to force the external vector:\if{html}{\out{
}}\preformatted{some_df \%>\% select(all_of(vars)) +\code{all_of()} to force the external vector: + +\if{html}{\out{
}}\preformatted{some_df \%>\% select(all_of(vars)) #> # A tibble: 4 x 3 #> cyl am vs #> diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/faq-selection-context.Rd r-cran-tidyselect-1.2.0+dfsg/man/faq-selection-context.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/faq-selection-context.Rd 2022-01-26 16:41:28.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/faq-selection-context.Rd 2022-10-10 14:07:37.000000000 +0000 @@ -5,31 +5,56 @@ \title{FAQ - Error: Must be used within a \emph{selecting} function} \description{ Functions like \code{starts_with()}, \code{contains()} or \code{matches()} are -\strong{selection helpers} that only work in a selection context. +\strong{selection helpers} that only work in a selection context, e.g. +\code{dplyr::select()} or the \code{cols} argument of \code{tidyr::pivot_longer()}. -Examples of valid selection contexts are: -\itemize{ -\item Inside \code{dplyr::select()}. -\item The \code{cols} argument of \code{tidyr::pivot_longer()}. -} +Using a selection helper anywhere else results in an error: -Using a selection helper anywhere else results in an error:\if{html}{\out{
}}\preformatted{starts_with("foo") +\if{html}{\out{
}}\preformatted{starts_with("foo") #> Error: #> ! `starts_with()` must be used within a *selecting* function. -#> i See . +#> i See +#> for details. mtcars[contains("foo")] #> Error: #> ! `contains()` must be used within a *selecting* function. -#> i See . +#> i See +#> for details. subset(mtcars, select = matches("foo")) #> Error: #> ! `matches()` must be used within a *selecting* function. -#> i See . +#> i See +#> for details. +}\if{html}{\out{
}} + +If you see this error, you may have used a selection helper in the wrong +place, possibly as the result of a typo (e.g. misplaced comma or wrong +argument name). Alternatively, you may be deliberately trying to reduce +duplication in your code by extracting out a selection into a variable: + +\if{html}{\out{
}}\preformatted{my_vars <- c(name, species, ends_with("color")) +#> Error in eval(expr, envir, enclos): object 'name' not found }\if{html}{\out{
}} -If you see this error, you’ve probably used a selection helper in the -wrong place, possibly as the result of a typo (e.g. misplaced comma or -wrong argument name). +To make this work you’ll need to do two things: +\itemize{ +\item Wrap the whole thing in a function +\item Use \code{any_of()} or \code{all_of()} instead of bare variable names +} + +\if{html}{\out{
}}\preformatted{my_vars <- function() \{ + c(any_of(c("name", "species")), ends_with("color")) +\} +dplyr::select(starwars, my_vars()) +#> # A tibble: 87 x 5 +#> name species hair_color skin_color eye_color +#> +#> 1 Luke Skywalker Human blond fair blue +#> 2 C-3PO Droid gold yellow +#> 3 R2-D2 Droid white, blue red +#> 4 Darth Vader Human none white yellow +#> # ... with 83 more rows +}\if{html}{\out{
}} } diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/language.Rd r-cran-tidyselect-1.2.0+dfsg/man/language.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/language.Rd 2022-01-26 15:55:52.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/language.Rd 2022-09-20 21:56:55.000000000 +0000 @@ -7,46 +7,35 @@ \description{ \subsection{Overview of selection features:}{ -Tidyverse selections implement a dialect of R where operators make -it easy to select variables: +tidyselect implements a DSL for selecting variables. It provides helpers +for selecting variables: \itemize{ -\item \code{:} for selecting a range of consecutive variables. -\item \code{!} for taking the complement of a set of variables. -\item \code{&} and \code{|} for selecting the intersection or the union of two -sets of variables. -\item \code{c()} for combining selections. +\item \code{var1:var10}: variables lying between \code{var1} on the left and \code{var10} on the right. } - -In addition, you can use \strong{selection helpers}. Some helpers select specific -columns: \itemize{ -\item \code{\link[=everything]{everything()}}: Matches all variables. -\item \code{\link[=last_col]{last_col()}}: Select last variable, possibly with an offset. +\item \code{\link[=starts_with]{starts_with("a")}}: names that start with \code{"a"}. +\item \code{\link[=ends_with]{ends_with("z")}}: names that end with \code{"z"}. +\item \code{\link[=contains]{contains("b")}}: names that contain \code{"b"}. +\item \code{\link[=matches]{matches("x.y")}}: names that match regular expression \code{x.y}. +\item \code{\link[=num_range]{num_range(x, 1:4)}}: names following the pattern, \code{x1}, \code{x2}, ..., \code{x4}. +\item \code{\link[=all_of]{all_of(vars)}}/\code{\link[=any_of]{any_of(vars)}}: +matches names stored in the character vector \code{vars}. \code{all_of(vars)} will +error if the variables aren't present; \code{any_of(var)} will match just the +variables that exist. +\item \code{\link[=everything]{everything()}}: all variables. +\item \code{\link[=last_col]{last_col()}}: furthest column on the right. +\item \code{\link[=where]{where(is.numeric)}}: all variables where +\code{is.numeric()} returns \code{TRUE}. } -These helpers select variables by matching patterns in their names: +As well as operators for combining those selections: \itemize{ -\item \code{\link[=starts_with]{starts_with()}}: Starts with a prefix. -\item \code{\link[=ends_with]{ends_with()}}: Ends with a suffix. -\item \code{\link[=contains]{contains()}}: Contains a literal string. -\item \code{\link[=matches]{matches()}}: Matches a regular expression. -\item \code{\link[=num_range]{num_range()}}: Matches a numerical range like x01, x02, x03. +\item \code{!selection}: only variables that don't match \code{selection}. +\item \code{selection1 & selection2}: only variables included in both \code{selection1} and \code{selection2}. +\item \code{selection1 | selection2}: all variables that match either \code{selection1} or \code{selection2}. } -These helpers select variables from a character vector: -\itemize{ -\item \code{\link[=all_of]{all_of()}}: Matches variable names in a character vector. All -names must be present, otherwise an out-of-bounds error is -thrown. -\item \code{\link[=any_of]{any_of()}}: Same as \code{all_of()}, except that no error is thrown -for names that don't exist. -} - -This helper selects variables with a function: -\itemize{ -\item \code{\link[=where]{where()}}: Applies a function to all variables and selects those -for which the function returns \code{TRUE}. -} +When writing code inside packages you can substitute \code{"var"} for \code{var} to avoid \verb{R CMD check} notes. } } \section{Simple examples}{ @@ -57,13 +46,17 @@ The selection language can be used in functions like \code{dplyr::select()} or \code{tidyr::pivot_longer()}. Let's first attach -the tidyverse:\if{html}{\out{
}}\preformatted{library(tidyverse) +the tidyverse: + +\if{html}{\out{
}}\preformatted{library(tidyverse) # For better printing iris <- as_tibble(iris) }\if{html}{\out{
}} -Select variables by name:\if{html}{\out{
}}\preformatted{starwars \%>\% select(height) +Select variables by name: + +\if{html}{\out{
}}\preformatted{starwars \%>\% select(height) #> # A tibble: 87 x 1 #> height #> @@ -85,7 +78,9 @@ }\if{html}{\out{
}} Select multiple variables by separating them with commas. Note how -the order of columns is determined by the order of inputs:\if{html}{\out{
}}\preformatted{starwars \%>\% select(homeworld, height, mass) +the order of columns is determined by the order of inputs: + +\if{html}{\out{
}}\preformatted{starwars \%>\% select(homeworld, height, mass) #> # A tibble: 87 x 3 #> homeworld height mass #> @@ -97,7 +92,9 @@ }\if{html}{\out{
}} Functions like \code{tidyr::pivot_longer()} don't take variables with -dots. In this case use \code{c()} to select multiple variables:\if{html}{\out{
}}\preformatted{iris \%>\% pivot_longer(c(Sepal.Length, Petal.Length)) +dots. In this case use \code{c()} to select multiple variables: + +\if{html}{\out{
}}\preformatted{iris \%>\% pivot_longer(c(Sepal.Length, Petal.Length)) #> # A tibble: 300 x 5 #> Sepal.Width Petal.Width Species name value #> @@ -109,7 +106,9 @@ }\if{html}{\out{
}} \subsection{Operators:}{ -The \code{:} operator selects a range of consecutive variables:\if{html}{\out{
}}\preformatted{starwars \%>\% select(name:mass) +The \code{:} operator selects a range of consecutive variables: + +\if{html}{\out{
}}\preformatted{starwars \%>\% select(name:mass) #> # A tibble: 87 x 3 #> name height mass #> @@ -120,16 +119,19 @@ #> # ... with 83 more rows }\if{html}{\out{
}} -The \code{!} operator negates a selection:\if{html}{\out{
}}\preformatted{starwars \%>\% select(!(name:mass)) +The \code{!} operator negates a selection: + +\if{html}{\out{
}}\preformatted{starwars \%>\% select(!(name:mass)) #> # A tibble: 87 x 11 -#> hair_color skin_color eye_color birth_year sex gender homeworld species -#> -#> 1 blond fair blue 19 male masculine Tatooine Human -#> 2 gold yellow 112 none masculine Tatooine Droid -#> 3 white, blue red 33 none masculine Naboo Droid -#> 4 none white yellow 41.9 male masculine Tatooine Human -#> # ... with 83 more rows, and 3 more variables: films , vehicles , -#> # starships +#> hair_color skin_c~1 eye_c~2 birth~3 sex gender homew~4 species films vehic~5 +#> +#> 1 blond fair blue 19 male mascu~ Tatooi~ Human +#> 2 gold yellow 112 none mascu~ Tatooi~ Droid +#> 3 white, ~ red 33 none mascu~ Naboo Droid +#> 4 none white yellow 41.9 male mascu~ Tatooi~ Human +#> # ... with 83 more rows, 1 more variable: starships , and abbreviated +#> # variable names 1: skin_color, 2: eye_color, 3: birth_year, 4: homeworld, +#> # 5: vehicles iris \%>\% select(!c(Sepal.Length, Petal.Length)) #> # A tibble: 150 x 3 @@ -152,7 +154,9 @@ #> # ... with 146 more rows }\if{html}{\out{
}} -\code{&} and \code{|} take the intersection or the union of two selections:\if{html}{\out{
}}\preformatted{iris \%>\% select(starts_with("Petal") & ends_with("Width")) +\code{&} and \code{|} take the intersection or the union of two selections: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(starts_with("Petal") & ends_with("Width")) #> # A tibble: 150 x 1 #> Petal.Width #> @@ -174,7 +178,9 @@ }\if{html}{\out{
}} To take the difference between two selections, combine the \code{&} and -\code{!} operators:\if{html}{\out{
}}\preformatted{iris \%>\% select(starts_with("Petal") & !ends_with("Width")) +\code{!} operators: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(starts_with("Petal") & !ends_with("Width")) #> # A tibble: 150 x 1 #> Petal.Length #> diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/rmd/overview.Rmd r-cran-tidyselect-1.2.0+dfsg/man/rmd/overview.Rmd --- r-cran-tidyselect-1.1.2+dfsg/man/rmd/overview.Rmd 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/rmd/overview.Rmd 2022-09-20 21:56:55.000000000 +0000 @@ -1,32 +1,26 @@ -Tidyverse selections implement a dialect of R where operators make -it easy to select variables: +tidyselect implements a DSL for selecting variables. It provides helpers +for selecting variables: -- `:` for selecting a range of consecutive variables. -- `!` for taking the complement of a set of variables. -- `&` and `|` for selecting the intersection or the union of two - sets of variables. -- `c()` for combining selections. +- `var1:var10`: variables lying between `var1` on the left and `var10` on the right. +* [`starts_with("a")`][tidyselect::starts_with]: names that start with `"a"`. +* [`ends_with("z")`][tidyselect::ends_with]: names that end with `"z"`. +* [`contains("b")`][tidyselect::contains]: names that contain `"b"`. +* [`matches("x.y")`][tidyselect::matches]: names that match regular expression `x.y`. +* [`num_range(x, 1:4)`][tidyselect::num_range]: names following the pattern, `x1`, `x2`, ..., `x4`. +* [`all_of(vars)`][tidyselect::all_of]/[`any_of(vars)`][tidyselect::any_of()]: + matches names stored in the character vector `vars`. `all_of(vars)` will + error if the variables aren't present; `any_of(var)` will match just the + variables that exist. +* [`everything()`][tidyselect::everything]: all variables. +* [`last_col()`][tidyselect::last_col]: furthest column on the right. +* [`where(is.numeric)`][tidyselect::where]: all variables where + `is.numeric()` returns `TRUE`. + +As well as operators for combining those selections: + +- `!selection`: only variables that don't match `selection`. +- `selection1 & selection2`: only variables included in both `selection1` and `selection2`. +- `selection1 | selection2`: all variables that match either `selection1` or `selection2`. -In addition, you can use __selection helpers__. Some helpers select specific -columns: -* [`everything()`][tidyselect::everything]: Matches all variables. -* [`last_col()`][tidyselect::last_col]: Select last variable, possibly with an offset. - -These helpers select variables by matching patterns in their names: -* [`starts_with()`][tidyselect::starts_with]: Starts with a prefix. -* [`ends_with()`][tidyselect::ends_with()]: Ends with a suffix. -* [`contains()`][tidyselect::contains()]: Contains a literal string. -* [`matches()`][tidyselect::matches()]: Matches a regular expression. -* [`num_range()`][tidyselect::num_range()]: Matches a numerical range like x01, x02, x03. - -These helpers select variables from a character vector: -* [`all_of()`][tidyselect::all_of()]: Matches variable names in a character vector. All - names must be present, otherwise an out-of-bounds error is - thrown. -* [`any_of()`][tidyselect::any_of()]: Same as `all_of()`, except that no error is thrown - for names that don't exist. - -This helper selects variables with a function: -* [`where()`][tidyselect::where()]: Applies a function to all variables and selects those - for which the function returns `TRUE`. +When writing code inside packages you can substitute `"var"` for `var` to avoid `R CMD check` notes. diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/starts_with.Rd r-cran-tidyselect-1.2.0+dfsg/man/starts_with.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/starts_with.Rd 2022-01-26 15:55:52.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/starts_with.Rd 2022-09-20 21:56:55.000000000 +0000 @@ -16,11 +16,15 @@ matches(match, ignore.case = TRUE, perl = FALSE, vars = NULL) -num_range(prefix, range, width = NULL, vars = NULL) +num_range(prefix, range, suffix = "", width = NULL, vars = NULL) } \arguments{ \item{match}{A character vector. If length > 1, the union of the -matches is taken.} +matches is taken. + +For \code{starts_with()}, \code{ends_with()}, and \code{contains()} this is an exact +match. For \code{matches()} this is a regular expression, and can be a +stringr pattern.} \item{ignore.case}{If \code{TRUE}, the default, ignores case when matching names.} @@ -31,7 +35,7 @@ \item{perl}{Should Perl-compatible regexps be used?} -\item{prefix}{A prefix that starts the numeric range.} +\item{prefix, suffix}{A prefix/suffix added before/after the numeric range.} \item{range}{A sequence of integers, like \code{1:5}.} @@ -42,8 +46,8 @@ These \link[=language]{selection helpers} match variables according to a given pattern. \itemize{ -\item \code{\link[=starts_with]{starts_with()}}: Starts with a prefix. -\item \code{\link[=ends_with]{ends_with()}}: Ends with a suffix. +\item \code{\link[=starts_with]{starts_with()}}: Starts with an exact prefix. +\item \code{\link[=ends_with]{ends_with()}}: Ends with an exact suffix. \item \code{\link[=contains]{contains()}}: Contains a literal string. \item \code{\link[=matches]{matches()}}: Matches a regular expression. \item \code{\link[=num_range]{num_range()}}: Matches a numerical range like x01, x02, x03. @@ -53,14 +57,18 @@ Selection helpers can be used in functions like \code{dplyr::select()} -or \code{tidyr::pivot_longer()}. Let's first attach the tidyverse:\if{html}{\out{
}}\preformatted{library(tidyverse) +or \code{tidyr::pivot_longer()}. Let's first attach the tidyverse: + +\if{html}{\out{
}}\preformatted{library(tidyverse) # For better printing iris <- as_tibble(iris) }\if{html}{\out{
}} \code{starts_with()} selects all variables matching a prefix and -\code{ends_with()} matches a suffix:\if{html}{\out{
}}\preformatted{iris \%>\% select(starts_with("Sepal")) +\code{ends_with()} matches a suffix: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(starts_with("Sepal")) #> # A tibble: 150 x 2 #> Sepal.Length Sepal.Width #> @@ -82,7 +90,9 @@ }\if{html}{\out{
}} You can supply multiple prefixes or suffixes. Note how the order of -variables depends on the order of the suffixes and prefixes:\if{html}{\out{
}}\preformatted{iris \%>\% select(starts_with(c("Petal", "Sepal"))) +variables depends on the order of the suffixes and prefixes: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(starts_with(c("Petal", "Sepal"))) #> # A tibble: 150 x 4 #> Petal.Length Petal.Width Sepal.Length Sepal.Width #> @@ -103,7 +113,9 @@ #> # ... with 146 more rows }\if{html}{\out{
}} -\code{contains()} selects columns whose names contain a word:\if{html}{\out{
}}\preformatted{iris \%>\% select(contains("al")) +\code{contains()} selects columns whose names contain a word: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(contains("al")) #> # A tibble: 150 x 4 #> Sepal.Length Sepal.Width Petal.Length Petal.Width #> @@ -114,8 +126,10 @@ #> # ... with 146 more rows }\if{html}{\out{
}} -These helpers do not use regular expressions. To select with a -regexp use \code{matches()}\if{html}{\out{
}}\preformatted{# [pt] is matched literally: +\code{starts_with()}, \code{ends_with()}, and \code{contains()} do not use regular expressions. To select with a +regexp use \code{matches()}: + +\if{html}{\out{
}}\preformatted{# [pt] is matched literally: iris \%>\% select(contains("[pt]al")) #> # A tibble: 150 x 0 @@ -132,7 +146,9 @@ }\if{html}{\out{
}} \code{starts_with()} selects all variables starting with a prefix. To -select a range, use \code{num_range()}. Compare:\if{html}{\out{
}}\preformatted{billboard \%>\% select(starts_with("wk")) +select a range, use \code{num_range()}. Compare: + +\if{html}{\out{
}}\preformatted{billboard \%>\% select(starts_with("wk")) #> # A tibble: 317 x 76 #> wk1 wk2 wk3 wk4 wk5 wk6 wk7 wk8 wk9 wk10 wk11 wk12 wk13 #> diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/tidyselect_data_proxy.Rd r-cran-tidyselect-1.2.0+dfsg/man/tidyselect_data_proxy.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/tidyselect_data_proxy.Rd 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/tidyselect_data_proxy.Rd 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/proxy.R +\name{tidyselect_data_proxy} +\alias{tidyselect_data_proxy} +\alias{tidyselect_data_has_predicates} +\title{tidyselect methods for custom types} +\usage{ +tidyselect_data_proxy(x) + +tidyselect_data_has_predicates(x) +} +\arguments{ +\item{x}{A data-frame like object passed to \code{\link[=eval_select]{eval_select()}}, +\code{\link[=eval_rename]{eval_rename()}}, and friends.} +} +\description{ +\itemize{ +\item \code{tidyselect_data_proxy()} returns a data frame. +\item \code{tidyselect_data_has_predicates()} returns \code{TRUE} or \code{FALSE} +} + +If your doesn't support predicate functions, return a 0-row data frame +from \code{tidyselect_data_proxy()} and \code{FALSE} from +\code{tidyselect_data_has_predicates()}. +} diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/tidyselect-package.Rd r-cran-tidyselect-1.2.0+dfsg/man/tidyselect-package.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/tidyselect-package.Rd 2022-01-26 15:55:52.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/tidyselect-package.Rd 2022-09-20 21:56:55.000000000 +0000 @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/tidyselect.R +% Please edit documentation in R/tidyselect-package.R \docType{package} \name{tidyselect-package} \alias{tidyselect} @@ -27,7 +27,7 @@ Other contributors: \itemize{ - \item RStudio [copyright holder] + \item RStudio [copyright holder, funder] } } diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/vars_pull.Rd r-cran-tidyselect-1.2.0+dfsg/man/vars_pull.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/vars_pull.Rd 2022-01-26 15:55:52.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/vars_pull.Rd 2022-09-20 21:56:55.000000000 +0000 @@ -4,7 +4,12 @@ \alias{vars_pull} \title{Select variable} \usage{ -vars_pull(vars, var = -1) +vars_pull( + vars, + var = -1, + error_call = caller_env(), + error_arg = caller_arg(var) +) } \arguments{ \item{vars}{A character vector of existing column names.} @@ -22,6 +27,15 @@ This argument is taken by expression and supports \link[rlang:topic-inject]{quasiquotation} (you can unquote column names and column locations).} + +\item{error_call}{The execution environment of a currently +running function, e.g. \code{caller_env()}. The function will be +mentioned in error messages as the source of the error. See the +\code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} + +\item{error_arg}{An argument name as a string. This argument +will be mentioned in error messages as the input that is at the +origin of a problem.} } \value{ The selected column name as an unnamed string. @@ -41,7 +55,7 @@ # You can unquote variables: var <- 10 -vars_pull(letters, !! var) +vars_pull(letters, !!var) } \seealso{ \code{\link[dplyr:pull]{dplyr::pull()}}, \code{\link[=vars_select]{vars_select()}} diff -Nru r-cran-tidyselect-1.1.2+dfsg/man/where.Rd r-cran-tidyselect-1.2.0+dfsg/man/where.Rd --- r-cran-tidyselect-1.1.2+dfsg/man/where.Rd 2022-01-26 15:55:52.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/man/where.Rd 2022-09-20 21:56:55.000000000 +0000 @@ -18,14 +18,18 @@ Selection helpers can be used in functions like \code{dplyr::select()} -or \code{tidyr::pivot_longer()}. Let's first attach the tidyverse:\if{html}{\out{
}}\preformatted{library(tidyverse) +or \code{tidyr::pivot_longer()}. Let's first attach the tidyverse: + +\if{html}{\out{
}}\preformatted{library(tidyverse) # For better printing iris <- as_tibble(iris) }\if{html}{\out{
}} \code{where()} takes a function and returns all variables for which the -function returns \code{TRUE}:\if{html}{\out{
}}\preformatted{is.factor(iris[[4]]) +function returns \code{TRUE}: + +\if{html}{\out{
}}\preformatted{is.factor(iris[[4]]) #> [1] FALSE is.factor(iris[[5]]) @@ -60,7 +64,9 @@ \subsection{The formula shorthand}{ You can use purrr-like formulas as a shortcut for creating a -function on the spot. These expressions are equivalent:\if{html}{\out{
}}\preformatted{iris \%>\% select(where(is.numeric)) +function on the spot. These expressions are equivalent: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(where(is.numeric)) #> # A tibble: 150 x 4 #> Sepal.Length Sepal.Width Petal.Length Petal.Width #> @@ -92,7 +98,9 @@ }\if{html}{\out{
}} The shorthand is useful for adding logic inline. Here we select all -numeric variables whose mean is greater than 3.5:\if{html}{\out{
}}\preformatted{iris \%>\% select(where(~ is.numeric(.x) && mean(.x) > 3.5)) +numeric variables whose mean is greater than 3.5: + +\if{html}{\out{
}}\preformatted{iris \%>\% select(where(~ is.numeric(.x) && mean(.x) > 3.5)) #> # A tibble: 150 x 2 #> Sepal.Length Petal.Length #> diff -Nru r-cran-tidyselect-1.1.2+dfsg/MD5 r-cran-tidyselect-1.2.0+dfsg/MD5 --- r-cran-tidyselect-1.1.2+dfsg/MD5 2022-02-21 16:00:02.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/MD5 2022-10-10 19:00:02.000000000 +0000 @@ -1,77 +1,94 @@ -62e83bf3a8cb26465685b3f2a6638826 *DESCRIPTION +900f633eab3d84af22ec8ce3413758bf *DESCRIPTION 2d19204519c1403aa1c4d36dcbbd5a51 *LICENSE -8e4b0518c69b56386e6886790b67d25d *NAMESPACE -50e4ed3855ac5873fe71046caeceeeba *NEWS.md -e5a9676fa2b27c9a20ed34b04731c271 *R/compat-friendly-type.R -25d1539defae5dcd5a5f5f88d556472d *R/conditions.R -1207c4ee9e09905d6997d5cc13c9ed1b *R/eval-bool.R -ba3d9df43443dd76c2bd5337689ea09f *R/eval-c.R -70a89e7f6794651812b3a47726f07a38 *R/eval-rename.R -4225cbdec8b9688c8475a5ba520c0604 *R/eval-select.R -8662486c75ed1a878c2521d9d3a76eee *R/eval-walk.R +bb0487b56562a51a1ed2b1d6c6f6616f *NAMESPACE +d9b30d72c6d8c02a7121335bc3bae773 *NEWS.md +0fa60b49bc17479ffacbdf7e1d738a31 *R/compat-purrr.R +3274a05a6f761f203ef960e42538fa67 *R/compat-type.R +e088583b2a60dbac50626165c333037c *R/conditions.R +679d601ac9a422497c6f3333f836aef4 *R/eval-bool.R +c8b3ffddec9b71d310de11142a3e4bec *R/eval-c.R +6ffec84f6b26d6a153f0b1d13920b4ee *R/eval-relocate.R +4b028731c50ee52567604b40d8b27a97 *R/eval-rename.R +e45d168327ed5edade1bcbbdb0ddef1a *R/eval-select.R +e83cdc29e2d4922092c3253edda61fa3 *R/eval-walk.R 56d8980e059b13528656ad9576bdb55b *R/faq.R -b0cc984d4fbeef5dfb9452ac86635519 *R/helpers-misc.R -1cc7a8ef7b726966ad7e0ddb3b2460eb *R/helpers-pattern.R -efa9bd184aa2a6b0b42a0f20b4d93db3 *R/helpers-vector.R -049b3120fcf3cd579cc144f0e28b803b *R/helpers-where.R -e80b79b2d030ec0d9a534f89ef2e3894 *R/helpers.R +a0daf9936531949194312ad45b7a3752 *R/helpers-misc.R +60bdfdc40f33fe5562ae5a5eb6b3cb5a *R/helpers-pattern.R +fc4755eef45b07bf583c36f470a790b0 *R/helpers-vector.R +4555203c2d31f329dbd4793febcdbf95 *R/helpers-where.R +011f477a9de6e8417c8575f01a9215cd *R/helpers.R 8064f7c74ed2876d56b52e0aa1614f46 *R/lifecycle-deprecated.R +49092f6ca267e44f692b0ae6c8560f07 *R/proxy.R 69a92531f4b91811f4ae95266ed9694a *R/reexport-rlang.R 2c731e20f44f1665d9866e7d194fa4b6 *R/sets.R -91177a969c83d8c40291c8822b1bc9a8 *R/tidyselect.R -70e60bff576f1a2c615c5abb6804e27d *R/utils-errors.R -5bff0537a4479b448e3b96e4c22a5b25 *R/utils.R -a0a236be111d224b0176130e72df1892 *R/vars-pull.R -276e26455a5a2561a72e4d4b4052e4af *R/vars.R +2c9b982b979018363cc9dbbe282cfc6e *R/tidyselect-package.R +6a45a17536943debfc7036c8ebd8f55f *R/utils.R +90609c621f7082ed87d998f7b7745118 *R/vars-pull.R +264c4f7496c29e60a5dec2bcf1a0e277 *R/vars.R 7e4525c7c18f6837c0e5f49d7968270d *R/zzz.R -29ca0551c72fdff4f578798dac3b5177 *README.md -a380b55104f9e943b4b31b7f0426af73 *build/vignette.rds -a00b9e409f775f1cda187ad190335afc *inst/doc/syntax.R -fdd36e96fd85909f9802ec3c5e471c77 *inst/doc/syntax.Rmd -465b36679dd427a48a84f0de2981c3dc *inst/doc/syntax.html +09f1c50f284302818e9d61a4ba8291f6 *README.md +d8b55803002ee512050bf195f217c198 *build/vignette.rds +da58b3ee012ebb31d2a89290ddfb0822 *inst/doc/syntax.R +7cf98e5a8509189bbbbaddd52107fef8 *inst/doc/syntax.Rmd +f28f3b2f37d0f342316c82f3dd86fa7e *inst/doc/syntax.html cceffb1cc58a31bef9aa9e00fc3b626b *inst/doc/tidyselect.R -8421d652bf80c5130d25bb9ecfc796ca *inst/doc/tidyselect.Rmd -6cba0be8a314c24a7498b9c34a12ef6b *inst/doc/tidyselect.html -d1f538f60001d44111d66cf24be981d4 *man/all_of.Rd -de5075db542773aadebc87e5fc5b13ad *man/eval_select.Rd -920e8ffdb61dcd824064f451c1009eaf *man/everything.Rd -05144264a8eaacece0c97f4fe1cd6b0d *man/faq-external-vector.Rd -223cacd592eac9db07b8a7c6db2ad9b6 *man/faq-selection-context.Rd +5ae925284f8746747be64518c509bf94 *inst/doc/tidyselect.Rmd +833d9cdf8a01e9d06d9601f7aaa87d39 *inst/doc/tidyselect.html +a562cd2638a37156540d87c7fb29442d *man/all_of.Rd +7252dfcd4e57ea98303946382f5140e8 *man/eval_relocate.Rd +7febcfe2312d2157f97a05f7f7eaeab9 *man/eval_select.Rd +bfda8dd481b40aa794cfd96b60e1d768 *man/everything.Rd +ace77b02e9f1cc64b4c7671049178f36 *man/faq-external-vector.Rd +c32efea62b1713911d8ce0ae961e34fb *man/faq-selection-context.Rd 57a8436dfcfa3137060fadb8d78ec9d3 *man/faq/external-vector.Rmd -afffd087b592aadd71d2eaed0e1ba810 *man/faq/selection-context.Rmd +dae2e2be8ce1403df3676432d19d14e4 *man/faq/selection-context.Rmd 101fc3cea514d508ce26ee793c1920ec *man/faq/setup.Rmd -8ab1396052d7eedf8e791c7851993797 *man/language.Rd +1d8efaf1f2fdf234002cf2e4f2455357 *man/language.Rd 7f139d934c3830e475ce7d7769832c7c *man/one_of.Rd 5f1cdc2af056fbf926b28cfc22deafdc *man/peek_vars.Rd 1e980934b49b8e19599cd90b6c911050 *man/poke_vars.Rd cf7cdc5c491a22bd880397f89e6c1b14 *man/reexports.Rd -aeda6121b91c598bc0f15410bf9f894c *man/rmd/overview.Rmd +38f89602a38bead06497b0d536c93e9e *man/rmd/overview.Rmd 4fa370dea568ce4c9aff95b54e6f8122 *man/rmd/setup.Rmd -a96d3408160af0e03407960d904ab4ec *man/starts_with.Rd -2478069961df758946de630289193583 *man/tidyselect-package.Rd -0f0d6998d1cf33d681ba04c3c19ffdb5 *man/vars_pull.Rd +7353eeb66e5f14ca6765edf9937e8aec *man/starts_with.Rd +14cc33716a4fe52fd75ba46eb23aa6f8 *man/tidyselect-package.Rd +a41807bfb4718109156f16f490a648f9 *man/tidyselect_data_proxy.Rd +f07e813547734ba589488359f25241a9 *man/vars_pull.Rd 7b43b4051ead15c2f60ac0ebdf6e4d7e *man/vars_select.Rd 6bfcf3e4feabaf9c59fc77c89ad81bc5 *man/vars_select_helpers.Rd -a450cbf245dcc8b9032a660fb2a193d2 *man/where.Rd -2dfb04adf6a141cf668b2ac7db3ba2f9 *tests/testthat.R -69722d5c0ef993795cd42351562be7f2 *tests/testthat/_snaps/eval-bool.md +4c40ad65ca3d4564c2c276be900b0797 *man/where.Rd +8dff2a7d6831786a0527c7d97067c23a *tests/testthat.R +6948a53b8032bae9c7f5c402f9c67476 *tests/testthat/_snaps/eval-bool.md 3dc17964fa29904d9b2d0b6c71206a6b *tests/testthat/_snaps/eval-c.md -f62dc6653838328b4073675955531e5a *tests/testthat/_snaps/eval-walk.md -170e690820d38ca72e720ff76ff3a2bd *tests/testthat/_snaps/lifecycle-deprecated.md -8b1f97fcbfd8ad07443287fbfbb30d9e *tests/testthat/_snaps/rename.md -4ea1cdc478249e70069450ee12775cb0 *tests/testthat/_snaps/select.md -48d54d8419ab521e9289828262ae967c *tests/testthat/_snaps/vars-pull.md +f3a5e7f6e169f97f158a2344ab3ef835 *tests/testthat/_snaps/eval-relocate.md +da0fc47723b0787b006de27dba160a0f *tests/testthat/_snaps/eval-rename.md +22edc713c10e26d2d86f936deecaa760 *tests/testthat/_snaps/eval-select.md +5ce47bcf312be6ea78e30d42d13046f7 *tests/testthat/_snaps/eval-walk.md +e75c989d6486f9eba23d4ee32f2ab8e9 *tests/testthat/_snaps/helpers-misc.md +f829a822c4b1761cb1a8f5817a71a28f *tests/testthat/_snaps/helpers-pattern.md +5ca5ec9bccc44aafe78bf18d7d310f4e *tests/testthat/_snaps/helpers-vector.md +a5c7d874e1b12986d2b36bcba5e7a689 *tests/testthat/_snaps/helpers-where.md +72f41c84f80f76c45fc36529b1496e49 *tests/testthat/_snaps/helpers.md +b385a26380ea6c4452cb2f5f68a6334f *tests/testthat/_snaps/lifecycle-deprecated.md +219142e38de32c93616c9ed768d1bf1b *tests/testthat/_snaps/proxy.md +7991c19c01ee01ac593ed6a0b5031468 *tests/testthat/_snaps/vars-pull.md +6199366bec15cf172986e0c2e7bfc0d2 *tests/testthat/_snaps/vars.md cd8573470d846ff8bea57c5c0cef8a4b *tests/testthat/helper-tidyselect.R -900b6513f58cbe44124275fe29476379 *tests/testthat/test-eval-bool.R +22e010cae556bef3cb0392c54807f1ee *tests/testthat/test-eval-bool.R 345ff6cec03dc699343b992b52edb7d8 *tests/testthat/test-eval-c.R -3378d893c8ba9605a74430dda7d9395c *tests/testthat/test-eval-walk.R -e5d52ce41e89a0943b9e29c743642848 *tests/testthat/test-helpers-where.R -96ff020ef76c3ca71db68fa22f5a753f *tests/testthat/test-lifecycle-deprecated.R -c848db69358eb33dc7d34839764d06c5 *tests/testthat/test-rename.R -d63923060c384b8c76d2f1eeb9787655 *tests/testthat/test-select-helpers.R -c2827bf7b6d6fc1739d0b6b9498212e6 *tests/testthat/test-select.R -d90d024db363b81676f0f5cef9d48105 *tests/testthat/test-sets.R -284e3cbbfb7a73a973b84ee206a1afba *tests/testthat/test-vars-pull.R -807cee60dd9f22eb9a748bf9dadd0d2e *tests/testthat/test-vars.R -fdd36e96fd85909f9802ec3c5e471c77 *vignettes/syntax.Rmd -8421d652bf80c5130d25bb9ecfc796ca *vignettes/tidyselect.Rmd +6db899df58a77c9eb87b3c6386f685df *tests/testthat/test-eval-relocate.R +e3eeca5146d234a9b2f3897cbf19b9da *tests/testthat/test-eval-rename.R +991c90c867801c2e660306b7f0e38691 *tests/testthat/test-eval-select.R +b79916f017a7436441d93066b6896107 *tests/testthat/test-eval-walk.R +57888f50d48452d6e0a2ab3f4521c300 *tests/testthat/test-helpers-misc.R +d90fc8a1a8936b991760f1634b33fc47 *tests/testthat/test-helpers-pattern.R +1dae0a27fda19fb8ab37b0c941dd15a2 *tests/testthat/test-helpers-vector.R +7ef24ab8dc33c26b2f469339e8c3c7ab *tests/testthat/test-helpers-where.R +e2773ae57c92bcba45f198fa7a73fa89 *tests/testthat/test-helpers.R +0ee166bd0f0b725105f05b6176fb9478 *tests/testthat/test-lifecycle-deprecated.R +e8c17a82b47541805188112ae7a42bf4 *tests/testthat/test-proxy.R +a88f0fd6c7f1013b8d25c0ce7f8ede76 *tests/testthat/test-sets.R +a331f0828432e672c591ec1058fbf9f9 *tests/testthat/test-vars-pull.R +f355cec3c687f8dd790db151db415f66 *tests/testthat/test-vars.R +7cf98e5a8509189bbbbaddd52107fef8 *vignettes/syntax.Rmd +5ae925284f8746747be64518c509bf94 *vignettes/tidyselect.Rmd diff -Nru r-cran-tidyselect-1.1.2+dfsg/NAMESPACE r-cran-tidyselect-1.2.0+dfsg/NAMESPACE --- r-cran-tidyselect-1.1.2+dfsg/NAMESPACE 2022-02-21 07:41:29.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/NAMESPACE 2022-09-20 21:56:55.000000000 +0000 @@ -1,10 +1,13 @@ # Generated by roxygen2: do not edit by hand +S3method(tidyselect_data_has_predicates,default) +S3method(tidyselect_data_proxy,default) export(all_of) export(any_of) export(contains) export(ends_with) export(enquo) +export(eval_relocate) export(eval_rename) export(eval_select) export(everything) @@ -20,22 +23,13 @@ export(quos) export(scoped_vars) export(starts_with) +export(tidyselect_data_has_predicates) +export(tidyselect_data_proxy) export(vars_pull) export(vars_rename) export(vars_select) export(vars_select_helpers) +export(where) export(with_vars) import(rlang) importFrom(glue,glue) -importFrom(purrr,compact) -importFrom(purrr,detect_index) -importFrom(purrr,discard) -importFrom(purrr,every) -importFrom(purrr,map) -importFrom(purrr,map2) -importFrom(purrr,map2_chr) -importFrom(purrr,map_chr) -importFrom(purrr,map_if) -importFrom(purrr,map_lgl) -importFrom(purrr,negate) -importFrom(purrr,walk) diff -Nru r-cran-tidyselect-1.1.2+dfsg/NEWS.md r-cran-tidyselect-1.2.0+dfsg/NEWS.md --- r-cran-tidyselect-1.1.2+dfsg/NEWS.md 2022-02-21 14:57:40.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/NEWS.md 2022-10-10 14:08:43.000000000 +0000 @@ -1,10 +1,78 @@ +# tidyselect 1.2.0 + +## New features + +* New `tidyselect_data_proxy()` and `tidyselect_data_has_predicates()` + allows tidyselect to work with custom input types (#242). + +* New `eval_relocate()` for moving a selection. This powers `dplyr::relocate()` + (#232). + +## Lifecycle changes + +* Using `all_of()` outside of a tidyselect context is now deprecated (#269). + In the future it will error to be consistent with `any_of()`. + +* Use of `.data` in tidyselect expressions is now deprecated to more cleanly + separate tidy-select from data-masking. Replace `.data$x` with `"x"` and + `.data[[var]]` with `any_of(var)` or `all_of(var)` (#169). + +* Use of bare predicates (not wrapped in `where()`) and indirection (without + using `all_of()`) have been formally deprecated (#317). + +## Minor improvements and bug fixes + +* Selection language: + + * `any_of()` generates a more informative error if you supply too many + arguments (#241). + + * `all_of()` (like `any_of()`) returns an integer vector to make it easier + to combine in functions (#270, #294). It also fails when it can't find + variables even when `strict = FALSE`. + + * `matches()` recognises and correctly uses stringr pattern objects + (`stringr::regex()`, `stringr::fixed()`, etc) (#238). It also now + works with named vectors (#250). + + * `num_range()` gains a `suffix` argument (#229). + + * `where()` is now exported, like all other select helpers (#201), + and gives more informative errors (#236). + +* `eval_select()` with `include` now preserves the order of the variables + if they're present in the selection (#224). + +* `eval_select()` always returns a named vector, even when renaming is not + permitted (#220). + +* `eval_select()` and `eval_relocate()` gain new `allow_empty` argument which + makes it possible to forbid empty selections with `allow_empty = FALSE` (#252). + +* `eval_select(allow_rename = FALSE)` no longer fails with empty + selections (#221, @eutwt) or with predicate functions (#225). It now properly + fails with partial renaming (#305). + +* `peek_var()` error now generates hyperlink to docs with recent RStudio (#289). + +* `vars_pull()` generates more informative error messages (#234, #258, #318) + and gains `error_call` and `error_arg` arguments. + +* Errors produced by tidyselect should now be more informative. Evaluation + errors are now chained, with the child error call is set to the `error_call` + argument of `eval_select()` and `eval_rename()`. We've also improved + backtraces of base errors, and done better at propagating the root + `error_call` to vctrs input checkers. + +* `tidyselect_verbosity` is no longer used; deprecation messaging is now + controlled by `lifecycle_verbosity` like all other packages (#317). + # tidyselect 1.1.2 * Fix for CRAN checks. * Better compatibility with rlang 1.0.0 errors. More to come soon. - # tidyselect 1.1.1 * Fix for CRAN checks. diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/compat-friendly-type.R r-cran-tidyselect-1.2.0+dfsg/R/compat-friendly-type.R --- r-cran-tidyselect-1.1.2+dfsg/R/compat-friendly-type.R 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/compat-friendly-type.R 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -# nocov start --- r-lib/rlang compat-friendly-type --- 2019-09-09 Mon 11:50 - -friendly_type_of <- function(x, length = FALSE) { - if (is.object(x)) { - return(sprintf("a `%s` object", paste(class(x), collapse = "/"))) - } - - friendly <- as_friendly_type(typeof(x)) - - if (length && rlang::is_vector(x)) { - friendly <- paste0(friendly, sprintf(" of length %s", length(x))) - } - - friendly -} - -as_friendly_type <- function(type) { - switch(type, - logical = "a logical vector", - integer = "an integer vector", - numeric = , - double = "a double vector", - complex = "a complex vector", - character = "a character vector", - raw = "a raw vector", - string = "a string", - list = "a list", - - NULL = "NULL", - environment = "an environment", - externalptr = "a pointer", - weakref = "a weak reference", - S4 = "an S4 object", - - name = , - symbol = "a symbol", - language = "a call", - pairlist = "a pairlist node", - expression = "an expression vector", - quosure = "a quosure", - formula = "a formula", - - char = "an internal string", - promise = "an internal promise", - ... = "an internal dots object", - any = "an internal `any` object", - bytecode = "an internal bytecode object", - - primitive = , - builtin = , - special = "a primitive function", - closure = "a function", - - type - ) -} - -# nocov end diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/compat-purrr.R r-cran-tidyselect-1.2.0+dfsg/R/compat-purrr.R --- r-cran-tidyselect-1.1.2+dfsg/R/compat-purrr.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/compat-purrr.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,204 @@ +# nocov start - compat-purrr.R +# Latest version: https://github.com/r-lib/rlang/blob/master/R/compat-purrr.R + +# This file provides a minimal shim to provide a purrr-like API on top of +# base R functions. They are not drop-in replacements but allow a similar style +# of programming. +# +# Changelog: +# 2020-04-14: +# * Removed `pluck*()` functions +# * Removed `*_cpl()` functions +# * Used `as_function()` to allow use of `~` +# * Used `.` prefix for helpers +# +# 2021-05-21: +# * Fixed "object `x` not found" error in `imap()` (@mgirlich) +# +# 2021-12-15: +# * `transpose()` now supports empty lists. + +map <- function(.x, .f, ...) { + .f <- as_function(.f, env = global_env()) + lapply(.x, .f, ...) +} +walk <- function(.x, .f, ...) { + map(.x, .f, ...) + invisible(.x) +} + +map_lgl <- function(.x, .f, ...) { + .rlang_purrr_map_mold(.x, .f, logical(1), ...) +} +map_int <- function(.x, .f, ...) { + .rlang_purrr_map_mold(.x, .f, integer(1), ...) +} +map_dbl <- function(.x, .f, ...) { + .rlang_purrr_map_mold(.x, .f, double(1), ...) +} +map_chr <- function(.x, .f, ...) { + .rlang_purrr_map_mold(.x, .f, character(1), ...) +} +.rlang_purrr_map_mold <- function(.x, .f, .mold, ...) { + .f <- as_function(.f, env = global_env()) + out <- vapply(.x, .f, .mold, ..., USE.NAMES = FALSE) + names(out) <- names(.x) + out +} + +map2 <- function(.x, .y, .f, ...) { + .f <- as_function(.f, env = global_env()) + out <- mapply(.f, .x, .y, MoreArgs = list(...), SIMPLIFY = FALSE) + if (length(out) == length(.x)) { + set_names(out, names(.x)) + } else { + set_names(out, NULL) + } +} +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") +} +imap <- function(.x, .f, ...) { + map2(.x, names(.x) %||% seq_along(.x), .f, ...) +} + +pmap <- function(.l, .f, ...) { + .f <- as.function(.f) + args <- .rlang_purrr_args_recycle(.l) + do.call("mapply", c( + FUN = list(quote(.f)), + args, MoreArgs = quote(list(...)), + SIMPLIFY = FALSE, USE.NAMES = FALSE + )) +} +.rlang_purrr_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 +} + +keep <- function(.x, .f, ...) { + .x[.rlang_purrr_probe(.x, .f, ...)] +} +discard <- function(.x, .p, ...) { + sel <- .rlang_purrr_probe(.x, .p, ...) + .x[is.na(sel) | !sel] +} +map_if <- function(.x, .p, .f, ...) { + matches <- .rlang_purrr_probe(.x, .p) + .x[matches] <- map(.x[matches], .f, ...) + .x +} +.rlang_purrr_probe <- function(.x, .p, ...) { + if (is_logical(.p)) { + stopifnot(length(.p) == length(.x)) + .p + } else { + .p <- as_function(.p, env = global_env()) + map_lgl(.x, .p, ...) + } +} + +compact <- function(.x) { + Filter(length, .x) +} + +transpose <- function(.l) { + if (!length(.l)) { + return(.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, ...) { + .p <- as_function(.p, env = global_env()) + + for (i in seq_along(.x)) { + if (!rlang::is_true(.p(.x[[i]], ...))) return(FALSE) + } + TRUE +} +some <- function(.x, .p, ...) { + .p <- as_function(.p, env = global_env()) + + for (i in seq_along(.x)) { + if (rlang::is_true(.p(.x[[i]], ...))) return(TRUE) + } + FALSE +} +negate <- function(.p) { + .p <- as_function(.p, env = global_env()) + 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) +} + +detect <- function(.x, .f, ..., .right = FALSE, .p = is_true) { + .p <- as_function(.p, env = global_env()) + .f <- as_function(.f, env = global_env()) + + for (i in .rlang_purrr_index(.x, .right)) { + if (.p(.f(.x[[i]], ...))) { + return(.x[[i]]) + } + } + NULL +} +detect_index <- function(.x, .f, ..., .right = FALSE, .p = is_true) { + .p <- as_function(.p, env = global_env()) + .f <- as_function(.f, env = global_env()) + + for (i in .rlang_purrr_index(.x, .right)) { + if (.p(.f(.x[[i]], ...))) { + return(i) + } + } + 0L +} +.rlang_purrr_index <- function(x, right = FALSE) { + idx <- seq_along(x) + if (right) { + idx <- rev(idx) + } + idx +} + +# nocov end diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/compat-type.R r-cran-tidyselect-1.2.0+dfsg/R/compat-type.R --- r-cran-tidyselect-1.1.2+dfsg/R/compat-type.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/compat-type.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,226 @@ +# nocov start --- r-lib/rlang compat-type +# +# Changelog +# ========= +# +# 2022-06-22: +# - `friendly_type_of()` is now `obj_type_friendly()`. +# - Added `obj_type_oo()`. +# +# 2021-12-20: +# - Added support for scalar values and empty vectors. +# - Added `stop_input_type()` +# +# 2021-06-30: +# - Added support for missing arguments. +# +# 2021-04-19: +# - Added support for matrices and arrays (#141). +# - Added documentation. +# - Added changelog. + + +#' Return English-friendly type +#' @param x Any R object. +#' @param value Whether to describe the value of `x`. +#' @param length Whether to mention the length of vectors and lists. +#' @return A string describing the type. Starts with an indefinite +#' article, e.g. "an integer vector". +#' @noRd +obj_type_friendly <- function(x, value = TRUE, length = FALSE) { + if (is_missing(x)) { + return("absent") + } + + if (is.object(x)) { + if (inherits(x, "quosure")) { + type <- "quosure" + } else { + type <- paste(class(x), collapse = "/") + } + return(sprintf("a <%s> object", type)) + } + + if (!rlang::is_vector(x)) { + return(.rlang_as_friendly_type(typeof(x))) + } + + n_dim <- length(dim(x)) + + if (value && !n_dim) { + if (is_na(x)) { + return(switch( + typeof(x), + logical = "`NA`", + integer = "an integer `NA`", + double = "a numeric `NA`", + complex = "a complex `NA`", + character = "a character `NA`", + .rlang_stop_unexpected_typeof(x) + )) + } + if (length(x) == 1 && !is_list(x)) { + return(switch( + typeof(x), + logical = if (x) "`TRUE`" else "`FALSE`", + integer = "an integer", + double = "a number", + complex = "a complex number", + character = if (nzchar(x)) "a string" else "`\"\"`", + raw = "a raw value", + .rlang_stop_unexpected_typeof(x) + )) + } + if (length(x) == 0) { + return(switch( + typeof(x), + logical = "an empty logical vector", + integer = "an empty integer vector", + double = "an empty numeric vector", + complex = "an empty complex vector", + character = "an empty character vector", + raw = "an empty raw vector", + list = "an empty list", + .rlang_stop_unexpected_typeof(x) + )) + } + } + + type <- .rlang_as_friendly_vector_type(typeof(x), n_dim) + + if (length && !n_dim) { + type <- paste0(type, sprintf(" of length %s", length(x))) + } + + type +} + +.rlang_as_friendly_vector_type <- function(type, n_dim) { + if (type == "list") { + if (n_dim < 2) { + return("a list") + } else if (n_dim == 2) { + return("a list matrix") + } else { + return("a list array") + } + } + + type <- switch( + type, + logical = "a logical %s", + integer = "an integer %s", + numeric = , + double = "a double %s", + complex = "a complex %s", + character = "a character %s", + raw = "a raw %s", + type = paste0("a ", type, " %s") + ) + + if (n_dim < 2) { + kind <- "vector" + } else if (n_dim == 2) { + kind <- "matrix" + } else { + kind <- "array" + } + sprintf(type, kind) +} + +.rlang_as_friendly_type <- function(type) { + switch( + type, + + list = "a list", + + NULL = "NULL", + environment = "an environment", + externalptr = "a pointer", + weakref = "a weak reference", + S4 = "an S4 object", + + name = , + symbol = "a symbol", + language = "a call", + pairlist = "a pairlist node", + expression = "an expression vector", + + char = "an internal string", + promise = "an internal promise", + ... = "an internal dots object", + any = "an internal `any` object", + bytecode = "an internal bytecode object", + + primitive = , + builtin = , + special = "a primitive function", + closure = "a function", + + type + ) +} + +.rlang_stop_unexpected_typeof <- function(x, call = rlang::caller_env()) { + rlang::abort( + sprintf("Unexpected type <%s>.", typeof(x)), + call = call + ) +} + +#' Return OO type +#' @param x Any R object. +#' @return One of `"bare"` (for non-OO objects), `"S3"`, `"S4"`, +#' `"R6"`, or `"R7"`. +#' @noRd +obj_type_oo <- function(x) { + if (!is.object(x)) { + return("bare") + } + + class <- inherits(x, c("R6", "R7_object"), which = TRUE) + + if (class[[1]]) { + "R6" + } else if (class[[2]]) { + "R7" + } else if (isS4(x)) { + "S4" + } else { + "S3" + } +} + +#' @param x The object type which does not conform to `what`. Its +#' `obj_type_friendly()` is taken and mentioned in the error message. +#' @param what The friendly expected type. +#' @param ... Arguments passed to [abort()]. +#' @inheritParams args_error_context +#' @noRd +stop_input_type <- function(x, + what, + ..., + arg = rlang::caller_arg(x), + call = rlang::caller_env()) { + # From compat-cli.R + format_arg <- rlang::env_get( + nm = "format_arg", + last = topenv(), + default = NULL, + inherit = TRUE + ) + if (!is.function(format_arg)) { + format_arg <- function(x) sprintf("`%s`", x) + } + + message <- sprintf( + "%s must be %s, not %s.", + format_arg(arg), + what, + obj_type_friendly(x) + ) + + rlang::abort(message, ..., call = call, arg = arg) +} + +# nocov end diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/conditions.R r-cran-tidyselect-1.2.0+dfsg/R/conditions.R --- r-cran-tidyselect-1.1.2+dfsg/R/conditions.R 2022-01-24 13:13:39.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/conditions.R 2022-09-20 21:56:55.000000000 +0000 @@ -1,7 +1,6 @@ with_subscript_errors <- function(expr, type = "select") { - tryCatch( - with_entraced_errors(expr), - + try_fetch( + expr, vctrs_error_subscript = function(cnd) { cnd$subscript_action <- subscript_action(type) cnd$subscript_elt <- "column" @@ -10,15 +9,19 @@ ) } -with_entraced_errors <- function(expr) { +with_chained_errors <- function(expr, action, call, eval_expr = NULL) { try_fetch( expr, - simpleError = function(cnd) { - # TODO! `parent = NA` - abort( - conditionMessage(cnd), - call = conditionCall(cnd) - ) + error = function(cnd) { + eval_expr <- quo_squash(eval_expr) + # Only display a message if there's useful context to add + if (!is_call(eval_expr) || identical(cnd[["call"]], call2(eval_expr[[1]])) ) { + msg <- "" + } else { + code <- as_label(eval_expr) + msg <- cli::format_inline("Problem while evaluating {.code {code}}.") + } + abort(msg, call = call, parent = cnd) } ) } @@ -33,7 +36,7 @@ validate_type <- function(type) { # We might add `recode` in the future if (!is_string(type, c("select", "rename", "pull"))) { - abort("Internal error: unexpected value for `tidyselect_type`") + cli::cli_abort("Unexpected value for {.arg tidyselect_type}.", .internal = TRUE) } type } diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/eval-bool.R r-cran-tidyselect-1.2.0+dfsg/R/eval-bool.R --- r-cran-tidyselect-1.1.2+dfsg/R/eval-bool.R 2022-01-26 16:41:28.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/eval-bool.R 2022-09-20 21:56:55.000000000 +0000 @@ -26,11 +26,14 @@ y <- eval_sym(y, data_mask, context_mask, strict = TRUE) if (!is_function(x) && !is_function(y)) { - msg <- glue_c( - "Can't take the intersection of two columns.", - i = "`{x_name} & {y_name}` is always an empty selection." + cli::cli_abort( + c( + "Can't take the intersection of two columns.", + # can't use {.code}: https://github.com/r-lib/cli/issues/422 + i = "`{x_name} & {y_name}` is always an empty selection." + ), + call = mask_error_call(data_mask) ) - abort(msg, call = mask_error_call(data_mask)) } } @@ -48,31 +51,34 @@ } stop_bad_bool_op <- function(bad, ok, call) { - msg <- glue_c( - "Can't use scalar `{bad}` in selections.", - i = "Do you need `{ok}` instead?" + cli::cli_abort( + c( + "Can't use scalar {.code {bad}} in selections.", + i = "Do you need {.arg {ok}} instead?" + ), + call = call ) - abort(msg, call = call) } stop_bad_arith_op <- function(op, call) { - msg <- glue_c( - "Can't use arithmetic operator `{op}` in selection context." + cli::cli_abort( + "Can't use arithmetic operator `{op}` in selection context.", + call = call ) - abort(msg, call = call) } stop_formula <- function(expr, call) { f <- as_label(expr) - msg <- glue_line(c( - "Formula shorthand must be wrapped in `where()`.", - "", - " # Bad", - " data %>% select({f})", - "", - " # Good", - " data %>% select(where({f}))" - )) - - abort(msg, call = call) + cli::cli_abort( + c( + "Formula shorthand must be wrapped in `where()`.", + "", + " " = " # Bad", + " " = " data %>% select({f})", + "", + " " = " # Good", + " " = " data %>% select(where({f}))" + ), + call = call + ) } diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/eval-c.R r-cran-tidyselect-1.2.0+dfsg/R/eval-c.R --- r-cran-tidyselect-1.1.2+dfsg/R/eval-c.R 2022-01-26 16:41:28.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/eval-c.R 2022-09-20 21:56:55.000000000 +0000 @@ -105,8 +105,7 @@ error_call) { if (uniquely_named && is_data_dups(x)) { name <- as_string(tag) - msg <- glue("Can't rename duplicate variables to `{name}`.") - abort(msg, call = error_call) + cli::cli_abort("Can't rename duplicate variables to `{name}`.", call = error_call) } vctrs::vec_c(!!tag := x, .name_spec = name_spec) diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/eval-relocate.R r-cran-tidyselect-1.2.0+dfsg/R/eval-relocate.R --- r-cran-tidyselect-1.1.2+dfsg/R/eval-relocate.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/eval-relocate.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,192 @@ +#' Evaluate an expression to relocate variables +#' +#' @description +#' `eval_relocate()` is a variant of [eval_select()] that moves a selection to +#' a new location. Either `before` or `after` can be provided to specify where +#' to move the selection to. This powers `dplyr::relocate()`. +#' +#' @inheritParams eval_select +#' +#' @param before,after Defused R code describing a selection according to the +#' tidyselect syntax. The selection represents the destination of the +#' selection provided through `expr`. Supplying neither of these will move the +#' selection to the left-hand side. Supplying both of these is an error. +#' +#' @param before_arg,after_arg Argument names for `before` and `after`. These +#' are used in error messages. +#' +#' @return +#' A named vector of numeric locations with length equal to `length(data)`. +#' Each position in `data` will be represented exactly once. +#' +#' The names are normally the same as in the input data, except when the user +#' supplied named selections with `c()`. In the latter case, the names reflect +#' the new names chosen by the user. +#' +#' @export +#' @examples +#' library(rlang) +#' +#' # Interpret defused code as a request to relocate +#' x <- expr(c(mpg, disp)) +#' after <- expr(wt) +#' eval_relocate(x, mtcars, after = after) +#' +#' # Supplying neither `before` nor `after` will move the selection to the +#' # left-hand side +#' eval_relocate(x, mtcars) +#' +#' # Within a function, use `enquo()` to defuse a single argument. +#' # Note that `before` and `after` must also be defused with `enquo()`. +#' my_relocator <- function(x, expr, before = NULL, after = NULL) { +#' eval_relocate(enquo(expr), x, before = enquo(before), after = enquo(after)) +#' } +#' +#' my_relocator(mtcars, vs, before = hp) +#' +#' # Here is an example of using `eval_relocate()` to implement `relocate()`. +#' # Note that the dots are passed on as a defused call to `c(...)`. +#' relocate <- function(.x, ..., .before = NULL, .after = NULL) { +#' pos <- eval_relocate( +#' expr(c(...)), +#' .x, +#' before = enquo(.before), +#' after = enquo(.after) +#' ) +#' set_names(.x[pos], names(pos)) +#' } +#' +#' relocate(mtcars, vs, .before = hp) +#' relocate(mtcars, starts_with("d"), .after = last_col()) +eval_relocate <- function(expr, + data, + ..., + before = NULL, + after = NULL, + strict = TRUE, + name_spec = NULL, + allow_rename = TRUE, + allow_empty = TRUE, + allow_predicates = TRUE, + before_arg = "before", + after_arg = "after", + env = caller_env(), + error_call = caller_env()) { + check_dots_empty() + + allow_predicates <- allow_predicates && tidyselect_data_has_predicates(data) + data <- tidyselect_data_proxy(data) + + expr <- as_quosure(expr, env = env) + + sel <- eval_select_impl( + x = data, + names = names(data), + expr = expr, + strict = strict, + name_spec = name_spec, + allow_rename = allow_rename, + allow_empty = allow_empty, + allow_predicates = allow_predicates, + error_call = error_call + ) + + # Enforce the invariant that relocating can't change the number of columns by + # retaining only the last instance of a column that is renamed multiple times + # TODO: https://github.com/r-lib/vctrs/issues/1442 + # `sel <- vctrs::vec_unique(sel, which = "last")` + loc_last <- which(!duplicated(sel, fromLast = TRUE)) + sel <- vctrs::vec_slice(sel, loc_last) + + n <- length(data) + + before <- as_quosure(before, env = env) + after <- as_quosure(after, env = env) + + has_before <- !quo_is_null(before) + has_after <- !quo_is_null(after) + + if (has_before && has_after) { + cli::cli_abort( + "Can't supply both {.arg {before_arg}} and {.arg {after_arg}}.", + call = error_call + ) + } + + if (has_before) { + where <- with_rename_errors( + eval_select( + expr = before, + data = data, + env = env, + error_call = error_call, + allow_predicates = allow_predicates, + allow_rename = FALSE + ), + arg = before_arg, + error_call = error_call + ) + where <- unname(where) + + if (length(where) == 0L) { + # Empty `before` selection pushes `sel` to the front + where <- 1L + } else { + where <- min(where) + } + } else if (has_after) { + where <- with_rename_errors( + eval_select( + expr = after, + data = data, + env = env, + error_call = error_call, + allow_predicates = allow_predicates, + allow_rename = FALSE + ), + arg = after_arg, + error_call = error_call + ) + where <- unname(where) + + if (length(where) == 0L) { + # Empty `after` selection pushes `sel` to the back + where <- n + } else { + where <- max(where) + } + + where <- where + 1L + } else { + # Defaults to `before = everything()` if neither + # `before` nor `after` are supplied + where <- 1L + } + + lhs <- seq2(1L, where - 1L) + rhs <- seq2(where, n) + + lhs <- setdiff(lhs, sel) + rhs <- setdiff(rhs, sel) + + names <- names(data) + + names(lhs) <- names[lhs] + names(rhs) <- names[rhs] + + sel <- vctrs::vec_c(lhs, sel, rhs) + + sel +} + +with_rename_errors <- function(expr, arg, error_call) { + try_fetch( + expr, + `tidyselect:::error_disallowed_rename` = function(cnd) { + cli::cli_abort( + "Can't rename variables when {.arg {arg}} is supplied.", + call = error_call + ) + } + ) +} diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/eval-rename.R r-cran-tidyselect-1.2.0+dfsg/R/eval-rename.R --- r-cran-tidyselect-1.1.2+dfsg/R/eval-rename.R 2022-02-21 07:41:19.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/eval-rename.R 2022-09-20 21:56:55.000000000 +0000 @@ -6,14 +6,20 @@ ..., strict = TRUE, name_spec = NULL, + allow_predicates = TRUE, error_call = caller_env()) { - ellipsis::check_dots_empty() + check_dots_empty() + + allow_predicates <- allow_predicates && tidyselect_data_has_predicates(data) + data <- tidyselect_data_proxy(data) + rename_impl( data, names(data), as_quosure(expr, env), strict = strict, name_spec = name_spec, + allow_predicates = allow_predicates, error_call = error_call ) } @@ -24,9 +30,10 @@ sel, strict = TRUE, name_spec = NULL, + allow_predicates = TRUE, error_call) { if (is_null(names)) { - abort("Can't rename an unnamed vector.", call = error_call) + cli::cli_abort("Can't rename an unnamed vector.", call = error_call) } pos <- eval_select_impl( @@ -36,6 +43,7 @@ strict = strict, name_spec = name_spec, type = "rename", + allow_predicates = allow_predicates, error_call = error_call ) @@ -45,7 +53,8 @@ with_subscript_errors( vctrs::vec_as_names( names, - repair = "check_unique" + repair = "check_unique", + call = error_call ) ) } diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/eval-select.R r-cran-tidyselect-1.2.0+dfsg/R/eval-select.R --- r-cran-tidyselect-1.1.2+dfsg/R/eval-select.R 2022-01-26 16:41:28.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/eval-select.R 2022-09-20 21:56:55.000000000 +0000 @@ -36,7 +36,14 @@ #' @param allow_rename If `TRUE` (the default), the renaming syntax #' `c(foo = bar)` is allowed. If `FALSE`, it causes an error. This #' is useful to implement purely selective behaviour. -#' @inheritParams ellipsis::dots_empty +#' @param allow_empty If `TRUE` (the default), it is ok for `expr` to result +#' in an empty selection. If `FALSE`, will error if `expr` yields an empty +#' selection. +#' @param allow_predicates If `TRUE` (the default), it is ok for `expr` to +#' use predicates (i.e. in `where()`). If `FALSE`, will error if `expr` uses a +#' predicate. Will automatically be set to `FALSE` if `data` does not +#' support predicates (as determined by [tidyselect_data_has_predicates()]). +#' @inheritParams rlang::args_dots_empty #' #' @return A named vector of numeric locations, one for each of the #' selected elements. @@ -122,8 +129,14 @@ strict = TRUE, name_spec = NULL, allow_rename = TRUE, + allow_empty = TRUE, + allow_predicates = TRUE, error_call = caller_env()) { - ellipsis::check_dots_empty() + check_dots_empty() + + allow_predicates <- allow_predicates && tidyselect_data_has_predicates(data) + data <- tidyselect_data_proxy(data) + eval_select_impl( data, names(data), @@ -133,6 +146,8 @@ strict = strict, name_spec = name_spec, allow_rename = allow_rename, + allow_empty = allow_empty, + allow_predicates = allow_predicates, error_call = error_call, ) } @@ -146,13 +161,15 @@ name_spec = NULL, uniquely_named = NULL, allow_rename = TRUE, + allow_empty = TRUE, + allow_predicates = TRUE, type = "select", error_call = caller_env()) { if (!is_null(x)) { vctrs::vec_assert(x) } if (is_null(names)) { - abort("Can't select within an unnamed vector.", call = error_call) + cli::cli_abort("Can't select within an unnamed vector.", call = error_call) } # Put vars in scope and peek validated vars @@ -161,15 +178,8 @@ local_data(x) - if (length(include)) { - expr <- quo(all_of(include) | !!expr) - } - if (length(exclude)) { - expr <- quo(!!expr & !any_of(exclude)) - } - with_subscript_errors( - vars_select_eval( + out <- vars_select_eval( vars, expr, strict = strict, @@ -177,11 +187,43 @@ name_spec = name_spec, uniquely_named = uniquely_named, allow_rename = allow_rename, + allow_empty = allow_empty, + allow_predicates = allow_predicates, type = type, error_call = error_call ), type = type ) + + if (length(include) > 0) { + if (!is.character(include)) { + cli::cli_abort("{.arg include} must be a character vector.", call = error_call) + } + + missing <- setdiff(include, names) + if (length(missing) > 0) { + cli::cli_abort(c( + "{.arg include} must only include variables found in {.arg data}.", + i = "Unknown variables: {.and {missing}}" + ), call = error_call) + } + + to_include <- vctrs::vec_match(include, names) + names(to_include) <- names[to_include] + + out <- c(to_include[!to_include %in% out], out) + } + + if (length(exclude) > 0) { + if (!is.character(exclude)) { + cli::cli_abort("{.arg include} must be a character vector.", call = error_call) + } + + to_exclude <- vctrs::vec_match(intersect(exclude, names), names) + out <- out[!out %in% to_exclude] + } + + out } # Example implementation mainly used for unit tests diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/eval-walk.R r-cran-tidyselect-1.2.0+dfsg/R/eval-walk.R --- r-cran-tidyselect-1.1.2+dfsg/R/eval-walk.R 2022-02-21 07:41:19.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/eval-walk.R 2022-10-10 14:07:38.000000000 +0000 @@ -5,12 +5,16 @@ name_spec = NULL, uniquely_named = NULL, allow_rename = TRUE, + allow_empty = TRUE, + allow_predicates = TRUE, type = "select", error_call) { wrapped <- quo_get_expr2(expr, expr) if (is_missing(wrapped)) { - return(named(int())) + pos <- named(int()) + check_empty(pos, allow_empty, call = error_call) + return(pos) } uniquely_named <- uniquely_named %||% is.data.frame(data) @@ -21,14 +25,16 @@ vars = vars, strict = strict, data = data, + allow_predicates = allow_predicates, call = error_call ) pos <- loc_validate(pos, vars) pos <- ensure_named( pos, vars, - uniquely_named, - allow_rename, + uniquely_named = uniquely_named, + allow_rename = allow_rename, + allow_empty = allow_empty, call = error_call ) return(pos) @@ -69,36 +75,42 @@ strict = strict, name_spec = name_spec, uniquely_named = uniquely_named, + allow_predicates = allow_predicates, error_call = error_call ) data_mask$.__tidyselect__.$internal <- internal - pos <- walk_data_tree(expr, data_mask, context_mask, error_call) + pos <- walk_data_tree(expr, data_mask, context_mask) pos <- loc_validate(pos, vars, call = error_call) if (type == "rename" && !is_named(pos)) { - abort("All renaming inputs must be named.", call = error_call) + cli::cli_abort("All renaming inputs must be named.", call = error_call) } ensure_named( pos, vars, - uniquely_named, - allow_rename, + uniquely_named = uniquely_named, + allow_rename = allow_rename, + allow_empty = allow_empty, call = error_call ) } ensure_named <- function(pos, vars, - uniquely_named, - allow_rename, - call) { - if (!allow_rename) { - if (is_named(pos)) { - abort("Can't rename variables in this context.", call = call) - } - return(set_names(pos, NULL)) + uniquely_named = FALSE, + allow_rename = TRUE, + allow_empty = TRUE, + call = caller_env()) { + check_empty(pos, allow_empty, call = call) + + if (!allow_rename && any(names2(pos) != "")) { + cli::cli_abort( + "Can't rename variables in this context.", + class = "tidyselect:::error_disallowed_rename", + call = call + ) } nms <- names(pos) <- names2(pos) @@ -107,12 +119,18 @@ # Duplicates are not allowed for data frames if (uniquely_named) { - vctrs::vec_as_names(names(pos), repair = "check_unique") + vctrs::vec_as_names(names(pos), repair = "check_unique", call = call) } pos } +check_empty <- function(x, allow_empty = TRUE, call = caller_env()) { + if (!allow_empty && length(x) == 0) { + cli::cli_abort("Must select at least one item.", call = call) + } +} + # `walk_data_tree()` is a recursive interpreter that implements a # clear separation between data expressions (calls to `-`, `:`, `c`, # and `(`) and context expressions (selection helpers and any other @@ -134,12 +152,12 @@ error_call <- data_mask$.__tidyselect__.$internal$error_call out <- switch( - expr_kind(expr, error_call), + expr_kind(expr, context_mask, error_call), literal = expr, symbol = eval_sym(expr, data_mask, context_mask), `(` = walk_data_tree(expr[[2]], data_mask, context_mask, colon = colon), `!` = eval_bang(expr, data_mask, context_mask), - `-` = eval_minus(expr, data_mask, context_mask), + `-` = eval_minus(expr, data_mask, context_mask, error_call), `:` = eval_colon(expr, data_mask, context_mask), `|` = eval_or(expr, data_mask, context_mask), `&` = eval_and(expr, data_mask, context_mask), @@ -151,44 +169,82 @@ `^` = stop_bad_arith_op("^", call = error_call), `~` = stop_formula(expr, call = error_call), .data = eval(expr, data_mask), - eval_context(expr, context_mask) + eval_context(expr, context_mask, call = error_call) ) vars <- data_mask$.__tidyselect__.$internal$vars strict <- data_mask$.__tidyselect__.$internal$strict data <- data_mask$.__tidyselect__.$internal$data + allow_predicates <- data_mask$.__tidyselect__.$internal$allow_predicates as_indices_sel_impl( out, vars = vars, strict = strict, data = data, - call = error_call + allow_predicates = allow_predicates, + call = error_call, + arg = as_label(expr) ) } -as_indices_sel_impl <- function(x, vars, strict, data = NULL, call) { +as_indices_sel_impl <- function(x, + vars, + strict, + data = NULL, + allow_predicates = TRUE, + call, + arg = NULL) { if (is.function(x)) { + if (!allow_predicates) { + cli::cli_abort( + "This tidyselect interface doesn't support predicates.", + call = call, + class = "tidyselect_error_predicates_unsupported" + ) + } if (is_null(data)) { - msg <- c( - "This tidyselect interface doesn't support predicates yet.", - i = "Contact the package author and suggest using `eval_select()`." + cli::cli_abort( + c( + "This tidyselect interface doesn't support predicates yet.", + i = "Contact the package author and suggest using {.code eval_select()}." + ), + call = call ) - abort(msg, call = call) } predicate <- x - x <- which(map_lgl(data, predicate)) + + xs <- map(data, predicate) + for (i in seq_along(xs)) { + check_predicate_output(xs[[i]], call = call) + } + + x <- which(as.logical(xs)) } - as_indices_impl(x, vars, call = call, strict = strict) + as_indices_impl(x, vars, call = call, arg = arg, strict = strict) +} + +check_predicate_output <- function(x, call) { + if (!is_bool(x)) { + cli::cli_abort( + "Predicate must return `TRUE` or `FALSE`, not {obj_type_friendly(x)}.", + call = call + ) + } } -as_indices_impl <- function(x, vars, strict, call = caller_env()) { +as_indices_impl <- function(x, vars, strict, call = caller_env(), arg = NULL) { if (is_null(x)) { return(int()) } - x <- vctrs::vec_as_subscript(x, logical = "error") + x <- vctrs::vec_as_subscript( + x, + logical = "error", + call = call, + arg = arg + ) if (!strict) { # Remove out-of-bounds elements if non-strict. We do this eagerly @@ -203,18 +259,20 @@ switch( typeof(x), - character = chr_as_locations(x, vars, call = call), + character = chr_as_locations(x, vars, call = call, arg = arg), double = , integer = x, - abort("Unexpected type.", .internal = TRUE) + cli::cli_abort("Unexpected type.", .internal = TRUE) ) } -chr_as_locations <- function(x, vars, call = caller_env()) { +chr_as_locations <- function(x, vars, call = caller_env(), arg = NULL) { out <- vctrs::vec_as_location( x, n = length(vars), - names = vars + names = vars, + call = call, + arg = arg ) set_names(out, names(x)) } @@ -224,24 +282,44 @@ vctrs::vec_as_location(inds, length(vars), vars, convert_values = NULL) } -expr_kind <- function(expr, error_call) { +expr_kind <- function(expr, context_mask, error_call) { switch( typeof(expr), symbol = "symbol", - language = call_kind(expr, error_call), + language = call_kind(expr, context_mask, error_call), "literal" ) } -call_kind <- function(expr, error_call) { +call_kind <- function(expr, context_mask, error_call) { head <- node_car(expr) if (!is_symbol(head)) { return("call") } + env <- context_mask$.__current__. + fn <- as_string(head) - if (fn %in% c("$", "[[") && identical(node_cadr(expr), quote(.data))) { + if (fn %in% c("$", "[[") && identical(expr[[2]], quote(.data))) { validate_dot_data(expr, error_call) + + what <- I("Use of .data in tidyselect expressions") + if (fn == "$") { + var <- as_string(expr[[3]]) + str <- encodeString(var, quote = '"') + + lifecycle::deprecate_soft("1.2.0", what, + details = cli::format_inline("Please use {.code {str}} instead of `.data${var}`"), + user_env = env + ) + } else if (fn == "[[") { + # .data[[ is an injection operator so can't give specific advice + lifecycle::deprecate_soft("1.2.0", what, + details = cli::format_inline("Please use {.code all_of(var)} (or {.code any_of(var)}) instead of {.code .data[[var]]}"), + user_env = env + ) + } + return(".data") } @@ -278,11 +356,11 @@ } } -eval_minus <- function(expr, data_mask, context_mask) { +eval_minus <- function(expr, data_mask, context_mask, call = call) { if (length(expr) == 2) { eval_bang(expr, data_mask, context_mask) } else { - eval_context(expr, context_mask) + eval_context(expr, context_mask, call = call) } } @@ -296,10 +374,13 @@ sel_diff(lhs, rhs, vars, error_call = error_call) } -eval_context <- function(expr, context_mask) { +eval_context <- function(expr, context_mask, call) { env <- context_mask$.__current__. %||% base_env() - expr <- as_quosure(expr, env) - eval_tidy(expr, context_mask) + with_chained_errors( + eval_tidy(as_quosure(expr, env), context_mask), + call = call, + eval_expr = expr + ) } eval_sym <- function(expr, data_mask, context_mask, strict = FALSE) { @@ -336,21 +417,19 @@ return(name) } - if (!is_string(verbosity(), "quiet")) { - msg <- paste_line(c( - "Predicate functions must be wrapped in `where()`.", - "", - " # Bad", - glue::glue(" data %>% select({name})"), + # Formally deprecated in 1.2.0 + lifecycle::deprecate_soft("1.1.0", + what = I("Use of bare predicate functions"), + with = I("wrap predicates in `where()`"), + details = c( + " " = "# Was:", + " " = glue("data %>% select({name})"), "", - " # Good", - glue::glue(" data %>% select(where({name}))"), - "" - )) - bullet <- format_error_bullets(c(i = "Please update your code.")) - - warn_once(paste_line(msg, bullet)) - } + " " = "# Now:", + " " = glue("data %>% select(where({name}))") + ), + user_env = env + ) return(value) } @@ -360,33 +439,37 @@ return(name) } - verbosity <- verbosity() - - if (!is_string(verbosity, "quiet") && env_needs_advice(env)) { - # Please keep in sync with faq.R. - msg <- glue_c( - "Note: Using an external vector in selections is ambiguous.", - i = "Use `all_of({name})` instead of `{name}` to silence this message.", - i = "See ." - ) - id <- paste0("strict_lookup_", name) - - if (is_string(verbosity, "verbose")) { - inform(msg) - } else { - inform_once(msg, id) - } - } + # Formally deprecated in 1.2.0 + lifecycle::deprecate_soft("1.1.0", + I("Using an external vector in selections"), + I("`all_of()` or `any_of()`"), + details = c( + " " = "# Was:", + " " = glue("data %>% select({name})"), + "", + " " = "# Now:", + " " = glue("data %>% select(all_of({name}))"), + "", + "See ." + ), + user_env = env + ) value } validate_dot_data <- function(expr, call) { if (is_call(expr, "$") && !is_symbol(expr[[3]])) { - abort("The RHS of `.data$rhs` must be a symbol.", call = call) + cli::cli_abort( + "The RHS of {.code .data$rhs} must be a symbol.", + call = call + ) } if (is_call(expr, "[[") && is_symbolic(expr[[3]])) { - abort("The subscript of `.data[[subscript]]` must be a constant.", call = call) + cli::cli_abort( + "The subscript of {.code .data[[subscript]]} must be a constant.", + call = call + ) } } diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/helpers-misc.R r-cran-tidyselect-1.2.0+dfsg/R/helpers-misc.R --- r-cran-tidyselect-1.1.2+dfsg/R/helpers-misc.R 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/helpers-misc.R 2022-09-20 21:56:55.000000000 +0000 @@ -61,15 +61,18 @@ #' @export #' @param offset Set it to `n` to select the nth var from the end. last_col <- function(offset = 0L, vars = NULL) { - stopifnot(is_integerish(offset)) + if (!is_integerish(offset, n = 1)) { + not <- obj_type_friendly(offset) + cli::cli_abort("{.arg offset} must be a single integer, not {not}.") + } vars <- vars %||% peek_vars(fn = "last_col") n <- length(vars) if (offset && n <= offset) { - abort(glue("`offset` must be smaller than the number of { plural(vars) }")) + cli::cli_abort("{.arg offset} ({offset}) must be smaller than the number of columns ({n}).") } else if (n == 0) { - abort(glue("Can't select last { singular(vars) } when input is empty")) + cli::cli_abort("Can't select last column when input is empty.") } else { n - as.integer(offset) } diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/helpers-pattern.R r-cran-tidyselect-1.2.0+dfsg/R/helpers-pattern.R --- r-cran-tidyselect-1.1.2+dfsg/R/helpers-pattern.R 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/helpers-pattern.R 2022-09-20 21:56:55.000000000 +0000 @@ -5,14 +5,18 @@ #' These [selection helpers][language] match variables according #' to a given pattern. #' -#' * [starts_with()]: Starts with a prefix. -#' * [ends_with()]: Ends with a suffix. +#' * [starts_with()]: Starts with an exact prefix. +#' * [ends_with()]: Ends with an exact suffix. #' * [contains()]: Contains a literal string. #' * [matches()]: Matches a regular expression. #' * [num_range()]: Matches a numerical range like x01, x02, x03. #' #' @param match A character vector. If length > 1, the union of the #' matches is taken. +#' +#' For `starts_with()`, `ends_with()`, and `contains()` this is an exact +#' match. For `matches()` this is a regular expression, and can be a +#' stringr pattern. #' @param ignore.case If `TRUE`, the default, ignores case when matching #' names. #' @param vars A character vector of variable names. If not supplied, @@ -58,8 +62,8 @@ #' iris %>% select(contains("al")) #' ``` #' -#' These helpers do not use regular expressions. To select with a -#' regexp use `matches()` +#' `starts_with()`, `ends_with()`, and `contains()` do not use regular expressions. To select with a +#' regexp use `matches()`: #' #' ```{r, comment = "#>", collapse = TRUE} #' # [pt] is matched literally: @@ -87,8 +91,8 @@ vars <- vars %||% peek_vars(fn = "starts_with") if (ignore.case) { - vars <- tolower(vars) - match <- tolower(match) + vars <- tolower(vars) + match <- tolower(match) } flat_map_int(match, starts_with_impl, vars) @@ -144,17 +148,36 @@ vars = NULL) { check_match(match) vars <- vars %||% peek_vars(fn = "matches") - flat_map_int(match, grep_vars, vars, ignore.case = ignore.case, perl = perl) + + if (inherits(match, "pattern") || inherits(match, "stringr_pattern")) { + check_installed("stringr") + if (!missing(ignore.case)) { + cli::cli_abort("{.arg ignore.case} not supported when {.arg match} is a {.pkg stringr} pattern.") + } + if (!missing(perl)) { + cli::cli_abort("{.arg perl} not supported when {.arg match} is a {.pkg stringr} pattern.") + } + + # no [ or [[ methods for pattern objects + if (length(match) > 1) { + cli::cli_abort("{.pkg stringr} patterns must be length 1.") + } + + stringr::str_which(vars, match) + } else { + flat_map_int(match, grep_vars, vars, ignore.case = ignore.case, perl = perl) + } } #' @rdname starts_with -#' @param prefix A prefix that starts the numeric range. +#' @param prefix,suffix A prefix/suffix added before/after the numeric range. #' @param range A sequence of integers, like `1:5`. #' @param width Optionally, the "width" of the numeric range. For example, #' a range of 2 gives "01", a range of three "001", etc. #' @export num_range <- function(prefix, range, + suffix = "", width = NULL, vars = NULL) { vars <- vars %||% peek_vars(fn = "num_range") @@ -163,12 +186,12 @@ range <- sprintf(paste0("%0", width, "d"), range) } - match_vars(paste0(prefix, range), vars) + match_vars(paste0(prefix, range, suffix), vars) } check_match <- function(match) { if (!is_character(match) || !all(nzchar(match))) { - abort("`match` must be a character vector of non empty strings.") + cli::cli_abort("{.arg match} must be a character vector of non empty strings.") } } diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/helpers.R r-cran-tidyselect-1.2.0+dfsg/R/helpers.R --- r-cran-tidyselect-1.1.2+dfsg/R/helpers.R 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/helpers.R 2022-09-20 21:56:55.000000000 +0000 @@ -112,16 +112,18 @@ bad_input <- detect_index(keep, ~ !vec_is_coercible(., chr())) if (bad_input) { - type <- friendly_type_of(keep[[bad_input]]) - msg <- glue::glue("Input { bad_input } must be a vector of column names, not {type}.") - abort(msg, "vctrs_error_incompatible_index_type") + type <- obj_type_friendly(keep[[bad_input]]) + cli::cli_abort( + "Input {bad_input} must be a vector of column names, not {type}.", + class = "vctrs_error_incompatible_index_type" + ) } keep <- vctrs::vec_c(!!!keep, .ptype = character()) if (!all(keep %in% .vars)) { bad <- setdiff(keep, .vars) - warn(glue("Unknown { plural(.vars) }: ", paste0("`", bad, "`", collapse = ", "))) + warn(glue("Unknown columns: ", paste0("`", bad, "`", collapse = ", "))) } match_vars(keep, .vars) diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/helpers-vector.R r-cran-tidyselect-1.2.0+dfsg/R/helpers-vector.R --- r-cran-tidyselect-1.1.2+dfsg/R/helpers-vector.R 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/helpers-vector.R 2022-10-10 12:09:06.000000000 +0000 @@ -74,20 +74,30 @@ #' @seealso `r rd_helpers_seealso()` #' @export all_of <- function(x) { - if (is.function(x)) { - # Trigger bad type error - vctrs::vec_as_location(x, 0L) - abort("Internal error: `all_of()` should have failed sooner") + if (!has_vars()) { + lifecycle::deprecate_soft( + "1.2.0", + I("Using `all_of()` outside of a selecting function"), + details = paste("See details at", peek_vars_link()) + ) + return(x) } - x + vars <- peek_vars(fn = "all_of") + as_indices_impl(x, vars = vars, strict = TRUE) } #' @rdname all_of -#' @inheritParams ellipsis::dots_empty +#' @inheritParams rlang::args_dots_empty #' @export any_of <- function(x, ..., vars = NULL) { vars <- vars %||% peek_vars(fn = "any_of") - ellipsis::check_dots_empty() + if (!missing(...)) { + cli::cli_abort(c( + "{.arg ...} must be empty.", + i = "Did you forget {.code c()}?", + i = 'The expected syntax is {.code any_of(c("a", "b"))}, not {.code any_of("a", "b")}' + )) + } as_indices_impl(x, vars = vars, strict = FALSE) } diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/helpers-where.R r-cran-tidyselect-1.2.0+dfsg/R/helpers-where.R --- r-cran-tidyselect-1.1.2+dfsg/R/helpers-where.R 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/helpers-where.R 2022-09-20 21:56:55.000000000 +0000 @@ -59,16 +59,14 @@ #' iris %>% select(where(~ is.numeric(.x) && mean(.x) > 3.5)) #' ``` #' -#' @name where +#' @export where <- function(fn) { predicate <- as_function(fn) + call <- current_call() function(x, ...) { out <- predicate(x, ...) - - if (!is_bool(out)) { - abort("`where()` must be used with functions that return `TRUE` or `FALSE`.") - } + check_predicate_output(out, call = call) out } diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/proxy.R r-cran-tidyselect-1.2.0+dfsg/R/proxy.R --- r-cran-tidyselect-1.1.2+dfsg/R/proxy.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/proxy.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,31 @@ +#' tidyselect methods for custom types +#' +#' @description +#' * `tidyselect_data_proxy()` returns a data frame. +#' * `tidyselect_data_has_predicates()` returns `TRUE` or `FALSE` +#' +#' If your doesn't support predicate functions, return a 0-row data frame +#' from `tidyselect_data_proxy()` and `FALSE` from +#' `tidyselect_data_has_predicates()`. +#' +#' @param x A data-frame like object passed to [eval_select()], +#' [eval_rename()], and friends. +#' @export +tidyselect_data_proxy <- function(x) { + UseMethod("tidyselect_data_proxy") +} +#' @export +tidyselect_data_proxy.default <- function(x) { + x +} + + +#' @rdname tidyselect_data_proxy +#' @export +tidyselect_data_has_predicates <- function(x) { + UseMethod("tidyselect_data_has_predicates") +} +#' @export +tidyselect_data_has_predicates.default <- function(x) { + TRUE +} diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/tidyselect-package.R r-cran-tidyselect-1.2.0+dfsg/R/tidyselect-package.R --- r-cran-tidyselect-1.1.2+dfsg/R/tidyselect-package.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/tidyselect-package.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,8 @@ +#' @keywords internal +#' @import rlang +#' @importFrom glue glue +"_PACKAGE" + +## usethis namespace: start +## usethis namespace: end +NULL diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/tidyselect.R r-cran-tidyselect-1.2.0+dfsg/R/tidyselect.R --- r-cran-tidyselect-1.1.2+dfsg/R/tidyselect.R 2022-01-21 13:58:58.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/tidyselect.R 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -#' @import rlang -#' @importFrom glue glue -#' @importFrom purrr discard map map_chr map_if map_lgl map2 map2_chr -#' detect_index negate walk every compact -#' @keywords internal -"_PACKAGE" diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/utils-errors.R r-cran-tidyselect-1.2.0+dfsg/R/utils-errors.R --- r-cran-tidyselect-1.1.2+dfsg/R/utils-errors.R 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/utils-errors.R 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ - -# ngettext() does extra work, this function is a simpler version -pluralise <- function(n, singular, plural) { - if (n == 1) { - singular - } else { - plural - } -} -pluralise_len <- function(x, singular, plural) { - pluralise(length(x), singular, plural) -} - -bad <- function(..., .envir = parent.frame()) { - glubort(NULL, ..., .envir = parent.frame()) -} - -bad_args <- function(args, ..., .envir = parent.frame()) { - glubort(fmt_args(args), ..., .envir = .envir) -} - -bad_pos_args <- function(pos_args, ..., .envir = parent.frame()) { - glubort(fmt_pos_args(pos_args), ..., .envir = .envir) -} - -bad_calls <- function(calls, ..., .envir = parent.frame()) { - glubort(fmt_calls(calls), ..., .envir = .envir) -} - -bad_named_calls <- function(named_calls, ..., .envir = parent.frame()) { - glubort(fmt_named_calls(named_calls), ..., .envir = .envir) -} - -bad_eq_ops <- function(named_calls, ..., .envir = parent.frame()) { - glubort(fmt_wrong_eq_ops(named_calls), ..., .envir = .envir) -} - -bad_cols <- function(cols, ..., .envir = parent.frame()) { - glubort(fmt_cols(cols), ..., .envir = .envir) -} - -bad_measures <- function(measures, ..., .envir = parent.frame()) { - glubort(fmt_measures(measures), ..., .envir = .envir) -} - -glubort <- function(header, ..., .envir = parent.frame(), .abort = abort) { - text <- glue(..., .envir = .envir) - if (!is_null(header)) text <- paste0(header, " ", text) - .abort(text) -} - -fmt_args <- function(x) { - x <- parse_args(x) - fmt_obj(x) -} - -fmt_pos_args <- function(x) { - args <- pluralise_len(x, "Argument", "Arguments") - glue("{args} {fmt_comma(x)}") -} - -fmt_calls <- function(...) { - x <- parse_named_call(...) - fmt_obj(x) -} - -fmt_named_calls <- function(...) { - x <- parse_named_call(...) - fmt_named(x) -} - -fmt_wrong_eq_ops <- function(...) { - x <- parse_named_call(...) - fmt_comma( - paste0(fmt_obj1(names2(x)), " (", fmt_obj1(paste0(names2(x), " = ", x)), ")") - ) -} - -fmt_cols <- function(x) { - cols <- pluralise_len(x, "Column", "Columns") - glue("{cols} {fmt_obj(x)}") -} - -fmt_measures <- function(x) { - measures <- pluralise_len(x, "Measure", "Measures") - glue("{measures} {fmt_obj(x)}") -} - -fmt_named <- function(x) { - fmt_comma(paste0(fmt_obj1(names2(x)), " = ", x)) -} - -fmt_obj <- function(x) { - fmt_comma(fmt_obj1(x)) -} - -fmt_obj1 <- function(x) { - paste0("`", x, "`") -} - -fmt_classes <- function(x) { - paste(class(x), collapse = "/") -} - -fmt_dims <- function(x) { - paste0("[", paste0(x, collapse = " x "), "]") -} - -fmt_comma <- function(...) { - MAX_ITEMS <- 6L - - x <- paste0(...) - if (length(x) > MAX_ITEMS) { - length(x) <- MAX_ITEMS - x[[MAX_ITEMS]] <- "..." - } - - glue::glue_collapse(x, sep = ", ", last = " and ") -} - -parse_args <- function(x) { - # convert single formula to list of length 1 - x <- unlist(list(x), recursive = FALSE) - is_fml <- map_lgl(x, is_formula) - x[is_fml] <- map_chr(map(x[is_fml], "[[", 2), as_string) - unlist(x) -} - -parse_named_call <- function(x) { - map_chr(x, quo_text) -} - -bad_unknown_vars <- function(vars, unknown) { - thing <- vars_pluralise_len(vars, unknown) - abort(glue("Unknown { thing } { fmt_args(unknown) } ")) -} diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/utils.R r-cran-tidyselect-1.2.0+dfsg/R/utils.R --- r-cran-tidyselect-1.1.2+dfsg/R/utils.R 2022-02-21 07:41:19.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/utils.R 2022-09-20 21:56:55.000000000 +0000 @@ -6,8 +6,10 @@ strict = TRUE, name_spec = NULL, allow_rename = TRUE, + allow_empty = TRUE, + allow_predicates = TRUE, error_call = current_env()) { - ellipsis::check_dots_empty() + check_dots_empty() eval_select( enquo(sel), @@ -17,6 +19,8 @@ strict = strict, name_spec = name_spec, allow_rename = allow_rename, + allow_empty = allow_empty, + allow_predicates = allow_predicates, error_call = error_call ) } @@ -27,7 +31,7 @@ strict = TRUE, name_spec = NULL, error_call = current_env()) { - ellipsis::check_dots_empty() + check_dots_empty() rename_impl( x, names(x), @@ -38,63 +42,33 @@ ) } -sym_dollar <- quote(`$`) -sym_brackets2 <- quote(`[[`) -is_data_pronoun <- function(expr) { - is_call(expr, list(sym_dollar, sym_brackets2)) && - identical(node_cadr(expr), quote(.data)) -} - -singular <- function(vars) { - nm <- attr(vars, "type") %||% c("column", "columns") - if (!is_character(nm, 2)) { - abort("The `type` attribute must be a character vector of length 2") - } - nm[[1]] -} -plural <- function(vars) { - nm <- attr(vars, "type") %||% c("column", "columns") - if (!is_character(nm, 2)) { - abort("The `type` attribute must be a character vector of length 2") - } - nm[[2]] -} -Singular <- function(vars) { - capitalise_first(singular(vars)) -} -Plural <- function(vars) { - capitalise_first(plural(vars)) -} - -vars_pluralise <- function(vars) { - pluralise(vars, singular(vars), plural(vars)) -} -vars_pluralise_len <- function(vars, x) { - pluralise_len(x, singular(vars), plural(vars)) -} - -capitalise_first <- function(chr) { - gsub("(^[[:alpha:]])", "\\U\\1", chr, perl = TRUE) -} - -paren_sym <- quote(`(`) -minus_sym <- quote(`-`) -colon_sym <- quote(`:`) -c_sym <- quote(`c`) - -quo_as_list <- function(quo) { - as.list(quo_get_expr(quo)) -} - -is_character <- function(x, n = NULL) { - if (typeof(x) != "character") return(FALSE) - - if (!is_null(n)) { - if (is_scalar_integerish(n) && length(x) != n) return(FALSE) - else if (is_function(n) && !n(length(x))) return(FALSE) - } - - TRUE +relocate_loc <- function(x, + sel, + ..., + before = NULL, + after = NULL, + strict = TRUE, + name_spec = NULL, + allow_rename = TRUE, + allow_empty = TRUE, + before_arg = "before", + after_arg = "after", + error_call = current_env()) { + check_dots_empty() + + eval_relocate( + expr = enquo(sel), + data = x, + before = enquo(before), + after = enquo(after), + strict = strict, + name_spec = name_spec, + allow_rename = allow_rename, + allow_empty = allow_empty, + before_arg = before_arg, + after_arg = after_arg, + error_call = error_call + ) } are_empty_name <- function(nms) { @@ -105,30 +79,9 @@ nms == "" | is.na(nms) } -# Compatibility with R < 3.2 -isNamespaceLoaded <- function(name) { - name %in% loadedNamespaces() -} - -collapse_labels <- function(x) { - bullets <- map_chr(x, ~ paste0("* ", as_label(.))) - paste_line(!!!bullets) -} -paste_line <- function (...) { - paste(chr(...), collapse = "\n") -} - -maybe_unwrap_quosure <- function(x) { - if (is_quosure(x)) { - quo_get_expr(x) - } else { - x - } -} - # https://github.com/r-lib/vctrs/issues/571 vec_is_coercible <- function(x, to, ..., x_arg = "x", to_arg = "to") { - tryCatch( + try_fetch( vctrs_error_incompatible_type = function(...) FALSE, { vctrs::vec_ptype2(x, to, ..., x_arg = x_arg, y_arg = to_arg) @@ -137,47 +90,8 @@ ) } -last <- function(x) { - x[[length(x)]] -} - -str_compact <- function(x) { - x[x != ""] -} - -vec_index_invert <- function(x) { - if (vec_index_is_empty(x)) { - TRUE - } else { - -x - } -} -vec_index_is_empty <- function(x) { - !length(x) || all(x == 0L) -} - -vec_is_subtype <- function(x, super, ..., x_arg = "x", super_arg = "super") { - tryCatch( - vctrs_error_incompatible_type = function(...) FALSE, - { - common <- vctrs::vec_ptype2(x, super, ..., x_arg = x_arg, y_arg = super_arg) - vctrs::vec_is(common, super) - } - ) -} - -glue_c <- function(..., env = caller_env()) { - map_chr(chr(...), glue::glue, .envir = env) -} -glue_line <- function(..., env = caller_env()) { - paste(glue_c(..., env = env), collapse = "\n") -} -glue_bullet <- function(..., .env = caller_env()) { - format_error_bullets(glue_c(..., env = .env)) -} - flat_map_int <- function(.x, .fn, ...) { - out <- map(.x, .fn, ...) + out <- map(unname(.x), .fn, ...) vctrs::vec_c(!!!out, .ptype = int()) } @@ -188,11 +102,13 @@ pos <- vctrs::vec_as_subscript( pos, logical = "error", - character = "error" + character = "error", + call = call ) pos <- vctrs::vec_as_location( pos, - n = length(vars) + n = length(vars), + call = call ) named(sel_unique(pos)) @@ -292,109 +208,12 @@ node_poke_cdr(node_tail(node), new) } -node_reverse <- function(node) { - if (is_null(node)) { - return(NULL) - } - - prev <- NULL - rest <- NULL - tail <- node - - while (!is_null(tail)) { - rest <- node_cdr(tail) - - if (is_reference(rest, node)) { - abort("Can't reverse cyclic pairlist.") - } - - node_poke_cdr(tail, prev) - prev <- tail - tail <- rest - } - - prev -} - named <- function(x) { set_names(x, names2(x)) } -signal_env <- env() - -signal_once <- function(signal, msg, id) { - stopifnot(is_string(id)) - - if (env_has(signal_env, id)) { - return(invisible(NULL)) - } - signal_env[[id]] <- TRUE - - issue <- msg[[1]] - bullets <- msg[-1] - - msg <- issue - if (length(bullets)) { - bullets <- format_error_bullets(bullets) - msg <- paste_line(msg, bullets) - } - - signal(paste_line( - msg, silver("This message is displayed once per session.") - )) -} -inform_once <- function(msg, id = msg) { - signal_once(inform, msg, id) -} -warn_once <- function(msg, id = msg) { - signal_once(warn, msg, id) -} - -verbosity <- function(default = "default") { - opt <- peek_option("tidyselect_verbosity") %||% default - - if (!is_string(opt, c("default", "quiet", "verbose"))) { - options(tidyselect_verbosity = NULL) - warn(c( - "`tidyselect_verbosity` must be `\"quiet\"` or `\"verbose\"`.", - i = "Resetting to NULL." - )) - - opt <- default - } - - opt -} - -env_needs_advice <- function(env) { - if (is_reference(topenv(env), global_env())) { - return(TRUE) - } - - if (from_tests(env)) { - return(TRUE) - } - - FALSE -} -from_tests <- function(env) { - testthat_pkg <- Sys.getenv("TESTTHAT_PKG") - - nzchar(testthat_pkg) && - identical(Sys.getenv("NOT_CRAN"), "true") && - env_name(topenv(env)) == env_name(ns_env(testthat_pkg)) -} - -has_crayon <- function() { - is_installed("crayon") && crayon::has_color() -} -silver <- function(x) if (has_crayon()) crayon::silver(x) else x - -glue_line <- function(..., env = parent.frame()) { - out <- map_chr(chr(...), glue::glue, .envir = env) - paste(out, collapse = "\n") -} - mask_error_call <- function(data_mask) { data_mask$.__tidyselect__.$internal$error_call } + +paste_lines <- function(...) paste(c(...), collapse = "\n") diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/vars-pull.R r-cran-tidyselect-1.2.0+dfsg/R/vars-pull.R --- r-cran-tidyselect-1.1.2+dfsg/R/vars-pull.R 2022-01-24 13:13:39.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/vars-pull.R 2022-09-20 21:56:55.000000000 +0000 @@ -6,6 +6,7 @@ #' negative numbers to select columns from the end. #' #' @inheritParams vars_select +#' @inheritParams rlang::args_error_context #' @param var A variable specified as: #' * a literal variable name #' * a positive integer, giving the position counting from the left @@ -30,39 +31,65 @@ #' #' # You can unquote variables: #' var <- 10 -#' vars_pull(letters, !! var) -vars_pull <- function(vars, var = -1) { +#' vars_pull(letters, !!var) +vars_pull <- function(vars, var = -1, error_call = caller_env(), error_arg = caller_arg(var)) { + expr <- enquo(var) + if (quo_is_missing(expr)) { + # No easy way to determine what var is in parent because it's likely + # to be embraced; so don't try and use error_arg here + cli::cli_abort( + "{.arg var} is absent but must be supplied.", + call = error_call + ) + } + + local_vars(vars) n <- length(vars) - with_entraced_errors( - loc <- eval_tidy(enquo(var), set_names(seq_along(vars), vars)) + with_chained_errors( + loc <- eval_tidy(expr, set_names(seq_along(vars), vars)), + call = error_call, + eval_expr = expr ) - loc <- pull_as_location2(loc, n, vars) + + loc <- pull_as_location2(loc, n, vars, error_arg = error_arg, error_call = error_call) if (loc < 0L) { loc <- n + 1L + loc } - vars[[loc]] } -pull_as_location2 <- function(i, n, names) { +pull_as_location2 <- function(i, n, names, error_call = caller_env(), error_arg = "var") { with_subscript_errors(type = "pull", { - i <- vctrs::vec_as_subscript2(i, arg = "var", logical = "error") + i <- vctrs::vec_as_subscript2(i, + logical = "error", + arg = error_arg, + call = error_call + ) + + if (length(i) != 1) { + cli::cli_abort( + "{.arg {error_arg}} must select exactly one column.", + call = error_call + ) + } if (is.numeric(i)) { vctrs::num_as_location2( i, n = n, negative = "ignore", - arg = "var" + arg = error_arg, + call = error_call ) } else { vctrs::vec_as_location2( i, n = n, names = names, - arg = "var" + arg = error_arg, + call = error_call, ) } }) diff -Nru r-cran-tidyselect-1.1.2+dfsg/R/vars.R r-cran-tidyselect-1.2.0+dfsg/R/vars.R --- r-cran-tidyselect-1.1.2+dfsg/R/vars.R 2022-01-26 16:41:28.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/R/vars.R 2022-09-20 21:56:55.000000000 +0000 @@ -2,7 +2,7 @@ peeker <- function(what) { function(..., fn = NULL) { if (!missing(...)) { - ellipsis::check_dots_empty() + check_dots_empty() } x <- vars_env[[what]] @@ -15,17 +15,28 @@ } # Please keep in sync with faq.R. - msg <- glue_c( - "{fn} must be used within a *selecting* function.", - i = "See ." + cli::cli_abort( + c( + "{fn} must be used within a *selecting* function.", + i = "See {peek_vars_link()} for details." + ), + call = NULL ) - abort(msg, call = NULL) } x } } +peek_vars_link <- function() { + if (is_interactive() && cli::ansi_has_hyperlink_support()) { + topic <- "tidyselect::faq-selection-context" + cli::style_hyperlink(paste0("?", topic), "ide:help", params = c(package = "tidyselect", topic = "faq-selection-context")) + } else { + "" + } +} + #' Peek at variables in the selection context #' #' @description @@ -46,7 +57,7 @@ #' [selection helpers][language] to the current selection #' context. #' -#' @inheritParams ellipsis::dots_empty +#' @inheritParams rlang::args_dots_empty #' @param fn The name of the function to use in error messages when #' the helper is used in the wrong context. If not supplied, a #' generic error message is used instead. @@ -153,22 +164,14 @@ #' @export scoped_vars <- function(vars, frame = caller_env()) { old <- poke_vars(vars) - - # Inline everything so the call will succeed in any environment - expr <- call2(on.exit, call2(poke_vars, old), add = TRUE) - eval_bare(expr, frame) - + withr::defer(poke_vars(old), envir = frame) invisible(old) } local_vars <- scoped_vars local_data <- function(data, frame = caller_env()) { old <- poke_data(data) - - # Inline everything so the call will succeed in any environment - expr <- call2(on.exit, call2(poke_data, old), add = TRUE) - eval_bare(expr, frame) - + withr::defer(poke_data(old), envir = frame) invisible(old) } diff -Nru r-cran-tidyselect-1.1.2+dfsg/README.md r-cran-tidyselect-1.2.0+dfsg/README.md --- r-cran-tidyselect-1.1.2+dfsg/README.md 2022-02-21 14:56:39.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/README.md 2022-09-20 21:56:55.000000000 +0000 @@ -3,10 +3,9 @@ [![Codecov test coverage](https://codecov.io/gh/r-lib/tidyselect/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/tidyselect?branch=main) [![CRAN status](https://www.r-pkg.org/badges/version/tidyselect)](https://cran.r-project.org/package=tidyselect) -[![R-CMD-check](https://github.com/r-lib/tidyselect/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/tidyselect/actions) +[![R-CMD-check](https://github.com/r-lib/tidyselect/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/tidyselect/actions/workflows/R-CMD-check.yaml) - ## Overview The tidyselect package is the backend of functions like `dplyr::select()` @@ -14,23 +13,22 @@ create selecting verbs that are consistent with other tidyverse packages. * To learn about the selection syntax as a user of dplyr or tidyr, read - the user-friendly [Selection language](https://tidyselect.r-lib.org/reference/language.html) reference. + the user-friendly `?language` reference. -* To learn how to implement tidyselect in your own functions, read the - [Get started](https://tidyselect.r-lib.org/articles/tidyselect.html) - vignette. +* To learn how to implement tidyselect in your own functions, read + `vignette("tidyselect")`. * To learn exactly how the tidyselect syntax is interpreted, read the - [Technical descrition](https://tidyselect.r-lib.org/articles/syntax.html) - vignette. - + technical description in `vignette("syntax")`. ## Installation -tidyselect is on CRAN. You can also install the development version -from github with: +Generally, tidyselect will be installed automatically by the packages that need it. If you need to install it manually for some reason, you can get it with: ```r -# install.packages("remotes") -remotes::install_github("r-lib/tidyselect") +install.packages("tidyselect") ``` + +## Code of Conduct + +Please note that the tidyselect project is released with a [Contributor Code of Conduct](https://github.com/r-lib/tidyselect/blob/main/.github/CODE_OF_CONDUCT.md). By contributing to this project, you agree to abide by its terms. diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-bool.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-bool.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-bool.md 2022-02-21 07:41:19.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-bool.md 2022-10-10 12:35:27.000000000 +0000 @@ -4,13 +4,13 @@ # Unknown names select_loc(mtcars, foobar & contains("am")) Condition - Error in `stop_subscript()`: + Error in `select_loc()`: ! Can't subset columns that don't exist. x Column `foobar` doesn't exist. Code select_loc(mtcars, contains("am") | foobar) Condition - Error in `stop_subscript()`: + Error in `select_loc()`: ! Can't subset columns that don't exist. x Column `foobar` doesn't exist. Code @@ -25,7 +25,7 @@ foo <- 1:2 select_loc(iris, Species | foo) Condition - Error in `stop_subscript()`: + Error in `select_loc()`: ! Can't subset columns that don't exist. x Column `foo` doesn't exist. diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-relocate.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-relocate.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-relocate.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-relocate.md 2022-10-10 12:35:28.000000000 +0000 @@ -0,0 +1,129 @@ +# can't supply both `before` and `after` + + Code + relocate_loc(c(x = 1), before = 1, after = 1) + Condition + Error in `relocate_loc()`: + ! Can't supply both `before` and `after`. + +--- + + Code + relocate_loc(c(x = 1), before = 1, after = 1, before_arg = ".before", + after_arg = ".after") + Condition + Error in `relocate_loc()`: + ! Can't supply both `.before` and `.after`. + +# can't relocate with out-of-bounds variables by default + + Code + (expect_error(relocate_loc(x, c))) + Output + + Error in `relocate_loc()`: + ! Can't subset columns that don't exist. + x Column `c` doesn't exist. + Code + (expect_error(relocate_loc(x, c(1, 3)))) + Output + + Error in `relocate_loc()`: + ! Can't subset columns past the end. + i Location 3 doesn't exist. + i There are only 2 columns. + Code + (expect_error(relocate_loc(x, a, before = c))) + Output + + Error in `relocate_loc()`: + ! Can't subset columns that don't exist. + x Column `c` doesn't exist. + Code + (expect_error(relocate_loc(x, a, after = c))) + Output + + Error in `relocate_loc()`: + ! Can't subset columns that don't exist. + x Column `c` doesn't exist. + +# can relocate with out-of-bounds variables in `expr` if `strict = FALSE` + + Code + (expect_error(relocate_loc(x, a, before = c, strict = FALSE))) + Output + + Error in `relocate_loc()`: + ! Can't subset columns that don't exist. + x Column `c` doesn't exist. + Code + (expect_error(relocate_loc(x, a, after = c, strict = FALSE))) + Output + + Error in `relocate_loc()`: + ! Can't subset columns that don't exist. + x Column `c` doesn't exist. + +# can forbid rename syntax + + Code + (expect_error(relocate_loc(x, c(foo = b), allow_rename = FALSE))) + Output + + Error in `relocate_loc()`: + ! Can't rename variables in this context. + Code + (expect_error(relocate_loc(x, c(b, foo = b), allow_rename = FALSE))) + Output + + Error in `relocate_loc()`: + ! Can't rename variables in this context. + +# can forbid empty selections + + Code + (expect_error(relocate_loc(x, allow_empty = FALSE))) + Output + + Error in `relocate_loc()`: + ! Must select at least one item. + Code + (expect_error(relocate_loc(mtcars, integer(), allow_empty = FALSE))) + Output + + Error in `relocate_loc()`: + ! Must select at least one item. + Code + (expect_error(relocate_loc(mtcars, starts_with("z"), allow_empty = FALSE))) + Output + + Error in `relocate_loc()`: + ! Must select at least one item. + +# `before` and `after` forbid renaming + + Code + (expect_error(relocate_loc(x, b, before = c(new = c)))) + Output + + Error in `relocate_loc()`: + ! Can't rename variables when `before` is supplied. + Code + (expect_error(relocate_loc(x, b, before = c(new = c), before_arg = ".before"))) + Output + + Error in `relocate_loc()`: + ! Can't rename variables when `.before` is supplied. + Code + (expect_error(relocate_loc(x, b, after = c(new = c)))) + Output + + Error in `relocate_loc()`: + ! Can't rename variables when `after` is supplied. + Code + (expect_error(relocate_loc(x, b, after = c(new = c), after_arg = ".after"))) + Output + + Error in `relocate_loc()`: + ! Can't rename variables when `.after` is supplied. + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-rename.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-rename.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-rename.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-rename.md 2022-10-10 12:35:28.000000000 +0000 @@ -0,0 +1,31 @@ +# rename_loc() works with predicate functions + + Code + rename_loc(x, where(is.numeric)) + Condition + Error in `rename_loc()`: + ! All renaming inputs must be named. + +# rename_loc() throws helpful errors + + Code + # Unnamed vector + rename_loc(letters, c(foo = a)) + Condition + Error in `rename_loc()`: + ! Can't rename an unnamed vector. + Code + # Duplicate names (FIXME) + rename_loc(mtcars, c(foo = cyl, foo = disp)) + Condition + Error in `rename_loc()`: + ! Names must be unique. + x These names are duplicated: + * "foo" at locations 1 and 2. + Code + # Unnamed inputs + rename_loc(iris, Species) + Condition + Error in `rename_loc()`: + ! All renaming inputs must be named. + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-select.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-select.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-select.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-select.md 2022-10-10 12:35:28.000000000 +0000 @@ -0,0 +1,139 @@ +# include and exclude validate their inputs + + Code + x <- list(a = 1, b = 2, c = 3) + (expect_error(select_loc(x, "a", include = 1))) + Output + + Error in `select_loc()`: + ! `include` must be a character vector. + Code + (expect_error(select_loc(x, "a", include = "d"))) + Output + + Error in `select_loc()`: + ! `include` must only include variables found in `data`. + i Unknown variables: d + Code + (expect_error(select_loc(x, "a", exclude = 1))) + Output + + Error in `select_loc()`: + ! `include` must be a character vector. + +# can forbid rename syntax (#178) + + Code + (expect_error(select_loc(mtcars, c(foo = cyl), allow_rename = FALSE))) + Output + + Error in `select_loc()`: + ! Can't rename variables in this context. + Code + (expect_error(select_loc(mtcars, c(cyl, foo = cyl), allow_rename = FALSE))) + Output + + Error in `select_loc()`: + ! Can't rename variables in this context. + Code + (expect_error(select_loc(mtcars, c(cyl, foo = mpg), allow_rename = FALSE))) + Output + + Error in `select_loc()`: + ! Can't rename variables in this context. + Code + (expect_error(select_loc(mtcars, c(foo = mpg, cyl), allow_rename = FALSE))) + Output + + Error in `select_loc()`: + ! Can't rename variables in this context. + +# can forbid empty selections + + Code + select_loc(mtcars, allow_empty = FALSE) + Condition + Error in `select_loc()`: + ! Must select at least one item. + Code + select_loc(mtcars, integer(), allow_empty = FALSE) + Condition + Error in `select_loc()`: + ! Must select at least one item. + Code + select_loc(mtcars, starts_with("z"), allow_empty = FALSE) + Condition + Error in `select_loc()`: + ! Must select at least one item. + +# eval_select() errors mention correct calls + + Code + (expect_error(select_loc(mtcars, f()))) + Output + + Error in `select_loc()`: + Caused by error in `f()`: + ! foo + +# predicate outputs are type-checked + + Code + (expect_error(select_loc(mtcars, function(x) ""))) + Output + + Error in `select_loc()`: + ! Predicate must return `TRUE` or `FALSE`, not `""`. + +# eval_select() produces correct backtraces + + Code + print(expect_error(select_loc(mtcars, f(base = TRUE)))) + Output + + Error in `select_loc()`: + ! Problem while evaluating `f(base = TRUE)`. + Caused by error in `h()`: + ! foo + --- + Backtrace: + 1. base::print(expect_error(select_loc(mtcars, f(base = TRUE)))) + 25. tidyselect (local) f(base = TRUE) + 26. tidyselect (local) g(base) + 27. tidyselect (local) h(base) + 28. base::stop("foo") + Code + print(expect_error(select_loc(mtcars, f(base = FALSE)))) + Output + + Error in `select_loc()`: + ! Problem while evaluating `f(base = FALSE)`. + Caused by error in `h()`: + ! foo + --- + Backtrace: + 1. base::print(expect_error(select_loc(mtcars, f(base = FALSE)))) + 25. tidyselect (local) f(base = FALSE) + 26. tidyselect (local) g(base) + 27. tidyselect (local) h(base) + +# eval_select() produces correct chained errors + + Code + (expect_error(select_loc(mtcars, 1 + ""))) + Output + + Error in `select_loc()`: + ! Problem while evaluating `1 + ""`. + Caused by error in `1 + ""`: + ! non-numeric argument to binary operator + Code + f <- (function() 1 + "") + (expect_error(select_loc(mtcars, f()))) + Output + + Error in `select_loc()`: + ! Problem while evaluating `f()`. + Caused by error in `1 + ""`: + ! non-numeric argument to binary operator + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-walk.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-walk.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/eval-walk.md 2022-02-21 07:32:49.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/eval-walk.md 2022-10-10 12:35:29.000000000 +0000 @@ -26,44 +26,33 @@ Error in `select_loc()`: ! Can't use arithmetic operator `^` in selection context. -# symbol evaluation only informs once (#184) +# symbol lookup outside data informs caller about better practice Code - # Default - with_options(tidyselect_verbosity = NULL, { - `_vars_default` <- "cyl" - select_loc(mtcars, `_vars_default`) - select_loc(mtcars, `_vars_default`) - invisible(NULL) - }) - Message - Note: Using an external vector in selections is ambiguous. - i Use `all_of(_vars_default)` instead of `_vars_default` to silence this message. - i See . - This message is displayed once per session. - Code - # Verbose - with_options(tidyselect_verbosity = "verbose", { - `_vars_verbose` <- "cyl" - select_loc(mtcars, `_vars_verbose`) - select_loc(mtcars, `_vars_verbose`) - invisible(NULL) - }) - Message - Note: Using an external vector in selections is ambiguous. - i Use `all_of(_vars_verbose)` instead of `_vars_verbose` to silence this message. - i See . - Note: Using an external vector in selections is ambiguous. - i Use `all_of(_vars_verbose)` instead of `_vars_verbose` to silence this message. - i See . - Code - # Quiet - with_options(tidyselect_verbosity = "quiet", { - `_vars_quiet` <- "cyl" - select_loc(mtcars, `_vars_quiet`) - select_loc(mtcars, `_vars_quiet`) - invisible(NULL) - }) + vars <- c("a", "b") + select_loc(letters2, vars) + Condition + Warning: + Using an external vector in selections was deprecated in tidyselect 1.1.0. + i Please use `all_of()` or `any_of()` instead. + # Was: + data %>% select(vars) + + # Now: + data %>% select(all_of(vars)) + + See . + Output + a b + 1 2 + +# can forbid use of predicates + + Code + select_loc(iris, where(is.factor), allow_predicates = FALSE) + Condition + Error in `select_loc()`: + ! This tidyselect interface doesn't support predicates. # selections provide informative errors @@ -71,57 +60,78 @@ # Foreign errors during evaluation select_loc(iris, eval_tidy(foobar)) Condition - Error: + Error in `select_loc()`: + ! Problem while evaluating `eval_tidy(foobar)`. + Caused by error: ! object 'foobar' not found +# use of .data is deprecated + + Code + x <- select_loc(x, .data$a) + Condition + Warning: + Use of .data in tidyselect expressions was deprecated in tidyselect 1.2.0. + i Please use `"a"` instead of `.data$a` + +--- + + Code + x <- select_loc(x, .data[[var]]) + Condition + Warning: + Use of .data in tidyselect expressions was deprecated in tidyselect 1.2.0. + i Please use `all_of(var)` (or `any_of(var)`) instead of `.data[[var]]` + # eval_walk() has informative messages Code - # # Using a predicate without where() warns + # Using a predicate without where() warns invisible(select_loc(iris, is_integer)) Condition Warning: - Predicate functions must be wrapped in `where()`. - - # Bad + Use of bare predicate functions was deprecated in tidyselect 1.1.0. + i Please use wrap predicates in `where()` instead. + # Was: data %>% select(is_integer) - # Good + # Now: data %>% select(where(is_integer)) - - i Please update your code. - This message is displayed once per session. Code invisible(select_loc(iris, is.numeric)) Condition Warning: - Predicate functions must be wrapped in `where()`. - - # Bad + Use of bare predicate functions was deprecated in tidyselect 1.1.0. + i Please use wrap predicates in `where()` instead. + # Was: data %>% select(is.numeric) - # Good + # Now: data %>% select(where(is.numeric)) - - i Please update your code. - This message is displayed once per session. Code invisible(select_loc(iris, isTRUE)) Condition Warning: - Predicate functions must be wrapped in `where()`. - - # Bad + Use of bare predicate functions was deprecated in tidyselect 1.1.0. + i Please use wrap predicates in `where()` instead. + # Was: data %>% select(isTRUE) - # Good + # Now: data %>% select(where(isTRUE)) - - i Please update your code. - This message is displayed once per session. Code # Warning is not repeated invisible(select_loc(iris, is_integer)) + Condition + Warning: + Use of bare predicate functions was deprecated in tidyselect 1.1.0. + i Please use wrap predicates in `where()` instead. + # Was: + data %>% select(is_integer) + + # Now: + data %>% select(where(is_integer)) + Code # formula shorthand must be wrapped (expect_error(select_loc(mtcars, ~ is.numeric(.x)))) Output @@ -167,3 +177,16 @@ Error in `select_loc()`: ! The RHS of `.data$rhs` must be a symbol. +# can forbid empty selection + + Code + ensure_named(integer(), allow_empty = FALSE) + Condition + Error: + ! Must select at least one item. + Code + ensure_named(integer(), allow_empty = FALSE, allow_rename = FALSE) + Condition + Error: + ! Must select at least one item. + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers.md 2022-10-10 12:35:30.000000000 +0000 @@ -0,0 +1,10 @@ +# one_of gives useful errors + + Code + (expect_error(one_of(1L, .vars = c("x", "y")), class = "vctrs_error_incompatible_index_type") + ) + Output + + Error in `one_of()`: + ! Input 1 must be a vector of column names, not an integer. + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers-misc.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers-misc.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers-misc.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers-misc.md 2022-10-10 12:35:29.000000000 +0000 @@ -0,0 +1,23 @@ +# last_col() checks its inputs + + Code + last_col(Inf, letters[1:3]) + Condition + Error in `last_col()`: + ! `offset` (Inf) must be smaller than the number of columns (3). + Code + last_col(3, letters[1:3]) + Condition + Error in `last_col()`: + ! `offset` (3) must be smaller than the number of columns (3). + Code + last_col(0, character()) + Condition + Error in `last_col()`: + ! Can't select last column when input is empty. + Code + last_col(1:2, letters[1:3]) + Condition + Error in `last_col()`: + ! `offset` must be a single integer, not an integer vector. + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers-pattern.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers-pattern.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers-pattern.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers-pattern.md 2022-10-10 12:35:29.000000000 +0000 @@ -0,0 +1,18 @@ +# matches() complains about bad stringr pattern usage + + Code + matches(stringr::fixed("a"), perl = TRUE) + Condition + Error in `matches()`: + ! `perl` not supported when `match` is a stringr pattern. + Code + matches(stringr::fixed("a"), ignore.case = TRUE) + Condition + Error in `matches()`: + ! `ignore.case` not supported when `match` is a stringr pattern. + Code + matches(stringr::fixed(c("a", "b"))) + Condition + Error in `matches()`: + ! stringr patterns must be length 1. + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers-vector.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers-vector.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers-vector.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers-vector.md 2022-10-10 12:35:30.000000000 +0000 @@ -0,0 +1,95 @@ +# `all_of()` fails even if `.strict` is FALSE + + Code + select_loc(letters2, all_of(c("a", "bar", "c")), strict = FALSE) + Condition + Error in `select_loc()`: + ! Problem while evaluating `all_of(c("a", "bar", "c"))`. + Caused by error in `all_of()`: + ! Can't subset elements that don't exist. + x Element `bar` doesn't exist. + +# all_of() and any_of() check their inputs + + Code + (expect_error(select_loc(letters2, all_of(NA)))) + Output + + Error in `select_loc()`: + ! Selections can't have missing values. + Code + (expect_error(select_loc(letters2, any_of(NA)))) + Output + + Error in `select_loc()`: + ! Selections can't have missing values. + Code + (expect_error(select_loc(letters2, all_of(TRUE)))) + Output + + Error in `select_loc()`: + ! Problem while evaluating `all_of(TRUE)`. + Caused by error in `all_of()`: + ! Must subset elements with a valid subscript vector. + x Subscript has the wrong type `logical`. + i It must be numeric or character. + Code + (expect_error(select_loc(letters2, any_of(TRUE)))) + Output + + Error in `select_loc()`: + ! Problem while evaluating `any_of(TRUE)`. + Caused by error in `any_of()`: + ! Must subset elements with a valid subscript vector. + x Subscript has the wrong type `logical`. + i It must be numeric or character. + Code + (expect_error(select_loc(letters2, any_of(is.factor)))) + Output + + Error in `select_loc()`: + ! Problem while evaluating `any_of(is.factor)`. + Caused by error in `any_of()`: + ! Must subset elements with a valid subscript vector. + x Subscript has the wrong type `function`. + i It must be numeric or character. + Code + (expect_error(select_loc(letters2, all_of(is.factor)))) + Output + + Error in `select_loc()`: + ! Problem while evaluating `all_of(is.factor)`. + Caused by error in `all_of()`: + ! Must subset elements with a valid subscript vector. + x Subscript has the wrong type `function`. + i It must be numeric or character. + +# any_of() errors out of context + + Code + (expect_error(any_of())) + Output + + Error: + ! `any_of()` must be used within a *selecting* function. + i See for details. + +# all_of() is deprecated out of context (#269) + + Code + out <- all_of("x") + Condition + Warning: + Using `all_of()` outside of a selecting function was deprecated in tidyselect 1.2.0. + i See details at + +# any_of generates informative error if ... not empty + + Code + any_of("b", "c", "d") + Condition + Error in `any_of()`: + ! `...` must be empty. + i Did you forget `c()`? + i The expected syntax is `any_of(c("a", "b"))`, not `any_of("a", "b")` + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers-where.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers-where.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/helpers-where.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/helpers-where.md 2022-10-10 12:35:30.000000000 +0000 @@ -0,0 +1,26 @@ +# where() checks return values + + Code + where(NA) + Condition + Error in `where()`: + ! Can't convert `fn`, `NA`, to a function. + +--- + + Code + select_loc(iris, where(~NA)) + Condition + Error in `where()`: + ! Predicate must return `TRUE` or `FALSE`, not `NA`. + Code + select_loc(iris, where(~1)) + Condition + Error in `where()`: + ! Predicate must return `TRUE` or `FALSE`, not a number. + Code + select_loc(iris, where(mean)) + Condition + Error in `where()`: + ! Predicate must return `TRUE` or `FALSE`, not a number. + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/lifecycle-deprecated.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/lifecycle-deprecated.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/lifecycle-deprecated.md 2022-02-21 07:41:19.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/lifecycle-deprecated.md 2022-10-10 12:35:31.000000000 +0000 @@ -5,23 +5,20 @@ Condition Error: ! Must subset columns with a valid subscript vector. - x Subscript has the wrong type `logical`. + x Subscript `TRUE` has the wrong type `logical`. i It must be numeric or character. Code vars_select(letters, 2.5) Condition Error: ! Must subset columns with a valid subscript vector. - x Can't convert from to due to loss of precision. - Caused by error in `stop_vctrs()`: - ! Can't convert from to due to loss of precision. - * Locations: 1 + x Can't convert from `2.5` to due to loss of precision. Code vars_select(letters, structure(1:3, class = "tidysel_foobar")) Condition Error: ! Must subset columns with a valid subscript vector. - x Subscript has the wrong type `tidysel_foobar`. + x Subscript `structure(1:3, class = "tidysel_foobar")` has the wrong type `tidysel_foobar`. i It must be numeric or character. # vars_select() has consistent location errors @@ -30,49 +27,49 @@ # Bare names vars_select(letters, foo) Condition - Error in `stop_subscript()`: + Error: ! Can't subset columns that don't exist. x Column `foo` doesn't exist. Code vars_select(letters, -foo) Condition - Error in `stop_subscript()`: + Error: ! Can't subset columns that don't exist. x Column `foo` doesn't exist. Code # Names vars_select(letters, "foo") Condition - Error in `stop_subscript()`: + Error: ! Can't subset columns that don't exist. x Column `foo` doesn't exist. Code vars_select(letters, a:"foo") Condition - Error in `stop_subscript()`: + Error: ! Can't subset columns that don't exist. x Column `foo` doesn't exist. Code # Locations vars_select(letters, 30, 50, 100) Condition - Error in `stop_subscript()`: - ! Can't subset columns that don't exist. - x Locations 30, 50, and 100 don't exist. + Error: + ! Can't subset columns past the end. + i Locations 30, 50, and 100 don't exist. i There are only 26 columns. Code vars_select(letters, -100) Condition - Error in `stop_subscript()`: - ! Can't subset columns that don't exist. - x Location 100 doesn't exist. + Error: + ! Can't subset columns past the end. + i Location 100 doesn't exist. i There are only 26 columns. Code vars_select(letters, !100) Condition - Error in `stop_subscript()`: - ! Can't subset columns that don't exist. - x Location 100 doesn't exist. + Error: + ! Can't subset columns past the end. + i Location 100 doesn't exist. i There are only 26 columns. # when .strict = FALSE, vars_rename always succeeds @@ -80,19 +77,19 @@ Code vars_rename(c("a", "b"), d = e, .strict = TRUE) Condition - Error in `stop_subscript()`: + Error: ! Can't rename columns that don't exist. x Column `e` doesn't exist. Code vars_rename(c("a", "b"), d = e, f = g, .strict = TRUE) Condition - Error in `stop_subscript()`: + Error: ! Can't rename columns that don't exist. x Column `e` doesn't exist. Code vars_rename(c("a", "b"), d = "e", f = "g", .strict = TRUE) Condition - Error in `stop_subscript()`: + Error: ! Can't rename columns that don't exist. x Column `e` doesn't exist. @@ -102,7 +99,7 @@ # New column vars_rename(c("a", "b", "c"), foo = a, foo = b) Condition - Error in `stop_vctrs()`: + Error: ! Names must be unique. x These names are duplicated: * "foo" at locations 1 and 2. @@ -110,7 +107,7 @@ # Existing column vars_rename(c("a", "b", "c"), c = a, c = b) Condition - Error in `stop_vctrs()`: + Error: ! Names must be unique. x These names are duplicated: * "c" at locations 1, 2, and 3. @@ -121,7 +118,7 @@ # One column vars_rename(c("a", "b", "c"), b = a) Condition - Error in `stop_vctrs()`: + Error: ! Names must be unique. x These names are duplicated: * "b" at locations 1 and 2. @@ -129,7 +126,7 @@ # Multiple columns vars_rename(c("a", "b", "c", "d"), c = a, d = b) Condition - Error in `stop_vctrs()`: + Error: ! Names must be unique. x These names are duplicated: * "c" at locations 1 and 3. @@ -138,7 +135,7 @@ # Overlapping rename with one duplicate column vars_rename(c("a", "b", "c"), b = a, c = b) Condition - Error in `stop_vctrs()`: + Error: ! Names must be unique. x These names are duplicated: * "c" at locations 2 and 3. @@ -150,22 +147,19 @@ Condition Error: ! Must rename columns with a valid subscript vector. - x Subscript has the wrong type `logical`. + x Subscript `TRUE` has the wrong type `logical`. i It must be numeric or character. Code vars_rename(letters, A = 1.5) Condition Error: ! Must rename columns with a valid subscript vector. - x Can't convert from to due to loss of precision. - Caused by error in `stop_vctrs()`: - ! Can't convert from to due to loss of precision. - * Locations: 1 + x Can't convert from `1.5` to due to loss of precision. Code vars_rename(letters, A = list()) Condition Error: ! Must rename columns with a valid subscript vector. - x Subscript has the wrong type `list`. + x Subscript `list()` has the wrong type `list`. i It must be numeric or character. diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/proxy.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/proxy.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/proxy.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/proxy.md 2022-10-10 12:35:31.000000000 +0000 @@ -0,0 +1,28 @@ +# eval_*() respects proxy settings + + Code + eval_select(quote(where(is.numeric)), foo) + Condition + Error: + ! This tidyselect interface doesn't support predicates. + Code + eval_rename(quote(c(x = where(is.numeric))), foo) + Condition + Error: + ! This tidyselect interface doesn't support predicates. + Code + eval_relocate(quote(where(is.numeric)), foo) + Condition + Error: + ! This tidyselect interface doesn't support predicates. + Code + eval_relocate(quote(x), before = quote(where(is.numeric)), foo) + Condition + Error: + ! This tidyselect interface doesn't support predicates. + Code + eval_relocate(quote(x), after = quote(where(is.numeric)), foo) + Condition + Error: + ! This tidyselect interface doesn't support predicates. + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/rename.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/rename.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/rename.md 2022-02-21 07:41:19.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/rename.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -# rename_loc() throws helpful errors - - Code - # Unnamed vector - rename_loc(letters, c(foo = a)) - Condition - Error in `rename_loc()`: - ! Can't rename an unnamed vector. - Code - # Duplicate names (FIXME) - rename_loc(mtcars, c(foo = cyl, foo = disp)) - Condition - Error in `stop_vctrs()`: - ! Names must be unique. - x These names are duplicated: - * "foo" at locations 1 and 2. - Code - # Unnamed inputs - rename_loc(iris, Species) - Condition - Error in `rename_loc()`: - ! All renaming inputs must be named. - diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/select.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/select.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/select.md 2022-02-21 07:41:19.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/select.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -# eval_select() errors mention correct calls - - Code - (expect_error(select_loc(mtcars, f()))) - Output - - Error in `f()`: - ! foo - -# eval_select() produces correct backtraces - - Code - print(expect_error(select_loc(mtcars, f(base = TRUE)))) - Output - - Error in `h()`: - ! foo - Backtrace: - 1. base::print(expect_error(select_loc(mtcars, f(base = TRUE)))) - 27. base::.handleSimpleError(``, "foo", base::quote(h(base))) - 28. rlang h(simpleError(msg, call)) - 29. handlers[[1L]](cnd) - Code - print(expect_error(select_loc(mtcars, f(base = FALSE)))) - Output - - Error in `h()`: - ! foo - Backtrace: - 1. base::print(expect_error(select_loc(mtcars, f(base = FALSE)))) - 23. tidyselect f(base = FALSE) - 24. tidyselect g(base) - 25. tidyselect h(base) - diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/vars.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/vars.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/vars.md 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/vars.md 2022-10-10 12:35:32.000000000 +0000 @@ -0,0 +1,18 @@ +# generic error message is thrown if `fn` is not supplied + + Code + peek_vars() + Condition + Error: + ! Selection helpers must be used within a *selecting* function. + i See for details. + +--- + + Code + peek_vars() + Condition + Error: + ! Selection helpers must be used within a *selecting* function. + i See ]8;package = tidyselect:topic = faq-selection-context;ide:help?tidyselect::faq-selection-context]8;; for details. + diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/vars-pull.md r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/vars-pull.md --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/_snaps/vars-pull.md 2022-02-21 07:41:19.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/_snaps/vars-pull.md 2022-10-10 12:35:32.000000000 +0000 @@ -1,11 +1,20 @@ # errors for bad inputs Code - vars_pull(letters, letters) + vars_pull(letters, character()) Condition Error: - ! Must extract column with a single valid subscript. - x Subscript `var` has size 26 but must be size 1. + ! `character()` must select exactly one column. + Code + vars_pull(letters, c("a", "b")) + Condition + Error: + ! `c("a", "b")` must select exactly one column. + Code + vars_pull(letters, !!c("a", "b")) + Condition + Error: + ! `!!c("a", "b")` must select exactly one column. Code vars_pull(letters, aa) Condition @@ -16,61 +25,61 @@ Condition Error: ! Must extract column with a single valid subscript. - x Subscript `var` has value 0 but must be a positive location. + x Subscript `0` has value 0 but must be a positive location. Code vars_pull(letters, 100) Condition - Error in `stop_subscript()`: - ! Can't extract columns that don't exist. - x Location 100 doesn't exist. + Error in `vec_as_location2_result()`: + ! Can't extract columns past the end. + i Location 100 doesn't exist. i There are only 26 columns. Code vars_pull(letters, -100) Condition - Error in `stop_subscript()`: - ! Can't extract columns that don't exist. - x Location 100 doesn't exist. + Error in `vec_as_location2_result()`: + ! Can't extract columns past the end. + i Location 100 doesn't exist. i There are only 26 columns. Code vars_pull(letters, -Inf) Condition Error: ! Must extract column with a single valid subscript. - x Can't convert from `var` to due to loss of precision. - Caused by error in `stop_vctrs()`: - ! Can't convert from `var` to due to loss of precision. - * Locations: 1 + x Subscript `-Inf` has the wrong type `double`. + i It must be numeric or character. Code vars_pull(letters, TRUE) Condition Error: ! Must extract column with a single valid subscript. - x Subscript `var` has the wrong type `logical`. + x Subscript `TRUE` has the wrong type `logical`. i It must be numeric or character. Code vars_pull(letters, NA) Condition Error: ! Must extract column with a single valid subscript. - x Subscript `var` can't be `NA`. + x Subscript `NA` can't be `NA`. Code vars_pull(letters, na_int) Condition Error: ! Must extract column with a single valid subscript. - x Subscript `var` can't be `NA`. + x Subscript `na_int` can't be `NA`. Code vars_pull(letters, "foo") Condition - Error in `stop_subscript()`: + Error in `vec_as_location2_result()`: ! Can't extract columns that don't exist. x Column `foo` doesn't exist. + +# gives informative error if quosure is missing + Code - vars_pull(letters, !!c("a", "b")) + f() Condition - Error: - ! Must extract column with a single valid subscript. - x Subscript `var` has size 2 but must be size 1. + Error in `f()`: + ! `var` is absent but must be supplied. # vars_pull() has informative errors @@ -97,22 +106,29 @@ print(expect_error(vars_pull(letters, f(base = TRUE)))) Output - Error in `h()`: + Error: + ! Problem while evaluating `f(base = TRUE)`. + Caused by error in `h()`: ! foo + --- Backtrace: 1. base::print(expect_error(vars_pull(letters, f(base = TRUE)))) - 17. base::.handleSimpleError(``, "foo", base::quote(h(base))) - 18. rlang h(simpleError(msg, call)) - 19. handlers[[1L]](cnd) + 17. tidyselect (local) f(base = TRUE) + 18. tidyselect (local) g(base) + 19. tidyselect (local) h(base) + 20. base::stop("foo") Code print(expect_error(vars_pull(letters, f(base = FALSE)))) Output - Error in `h()`: + Error: + ! Problem while evaluating `f(base = FALSE)`. + Caused by error in `h()`: ! foo + --- Backtrace: 1. base::print(expect_error(vars_pull(letters, f(base = FALSE)))) - 13. tidyselect f(base = FALSE) - 14. tidyselect g(base) - 15. tidyselect h(base) + 17. tidyselect (local) f(base = FALSE) + 18. tidyselect (local) g(base) + 19. tidyselect (local) h(base) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-bool.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-bool.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-bool.R 2021-11-15 08:54:52.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-bool.R 2022-09-20 21:56:55.000000000 +0000 @@ -8,10 +8,10 @@ }) test_that("can use named inputs in & operands", { - x <- list(a = 1L, b = 2L) - expect_identical(select_loc(x, a & c(foo = a)), c(foo = 1L)) - expect_identical(select_loc(x, c(foo = a) & a), c(foo = 1L)) - expect_identical(select_loc(x, c(foo = a) & c(bar = a)), named(int())) + x <- list(a = 1L, b = 2L) + expect_identical(select_loc(x, a & c(foo = a)), c(foo = 1L)) + expect_identical(select_loc(x, c(foo = a) & a), c(foo = 1L)) + expect_identical(select_loc(x, c(foo = a) & c(bar = a)), named(int())) }) test_that("symbol operands are evaluated in strict mode", { diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-relocate.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-relocate.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-relocate.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-relocate.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,196 @@ +test_that("`before` and `after` relocates the selection", { + x <- list(x = 1, a = "a", y = 2, b = "a") + + expect_identical( + relocate_loc(x, x, after = y), + c(a = 2L, y = 3L, x = 1L, b = 4L) + ) + expect_identical( + relocate_loc(x, y, before = x), + c(y = 3L, x = 1L, a = 2L, b = 4L) + ) + expect_identical( + relocate_loc(x, where(is.character), before = x), + c(a = 2L, b = 4L, x = 1L, y = 3L) + ) +}) + +test_that("works with `before` and `after` `everything()`", { + x <- c(w = 1, x = 2, y = 3, z = 4) + + expect_identical( + relocate_loc(x, c(y, z), before = everything()), + c(y = 3L, z = 4L, w = 1L, x = 2L) + ) + expect_identical( + relocate_loc(x, c(y, z), after = everything()), + c(w = 1L, x = 2L, y = 3L, z = 4L) + ) +}) + +test_that("moves columns to the front when neither `before` nor `after` are specified", { + x <- c(x = 1, y = 2, z = 3) + + expect_identical( + relocate_loc(x, c(z, y)), + c(z = 3L, y = 2L, x = 1L) + ) +}) + +test_that("empty `before` selection moves columns to front", { + x <- c(x = 1, y = 2, z = 3) + + expect_identical( + relocate_loc(x, y, before = where(is.character)), + c(y = 2L, x = 1L, z = 3L) + ) +}) + +test_that("empty `after` selection moves columns to end", { + x <- c(x = 1, y = 2, z = 3) + + expect_identical( + relocate_loc(x, y, after = where(is.character)), + c(x = 1L, z = 3L, y = 2L) + ) +}) + +test_that("minimum of the `before` selection is used", { + x <- c(a = 1, b = 1, c = 1, d = 1, e = 1) + expect_named(relocate_loc(x, e, before = c(b, d)), c("a", "e", "b", "c", "d")) +}) + +test_that("maximum of the `after` selection is used", { + x <- c(a = 1, b = 1, c = 1, d = 1, e = 1) + expect_named(relocate_loc(x, b, after = c(a, c, e)), c("a", "c", "d", "e", "b")) +}) + +test_that("works with zero column data frames (tidyverse/dplyr#6167)", { + expect_identical(relocate_loc(data.frame(), any_of("b")), named(int())) + expect_identical(relocate_loc(data.frame(), any_of("b"), before = where(is.character)), named(int())) + expect_identical(relocate_loc(data.frame(), any_of("b"), after = where(is.character)), named(int())) +}) + +test_that("retains the last duplicate when renaming while moving (tidyverse/dplyr#6209)", { + # To enforce the invariant that relocating can't change the number of columns + x <- c(x = 1) + expect_identical( + relocate_loc(x, c(a = x, b = x)), + c(b = 1L) + ) + + x <- c(x = 1, y = 2) + expect_identical( + relocate_loc(x, c(a = x, b = y, c = x)), + c(b = 2L, c = 1L) + ) +}) + +test_that("respects order specified by `...` (tidyverse/dplyr#5328)", { + x <- c(a = 1, x = 1, b = 1, z = 1, y = 1) + + expect_named( + relocate_loc(x, c(x, y, z), before = x), + c("a", "x", "y", "z", "b") + ) + expect_named( + relocate_loc(x, c(x, y, z), after = last_col()), + c("a", "b", "x", "y", "z") + ) + expect_named( + relocate_loc(x, c(x, a, z)), + c("x", "a", "z", "b", "y") + ) +}) + +test_that("allows for renaming (tidyverse/dplyr#5569)", { + x <- c(a = 1, b = 1, c = 1) + + expect_named( + relocate_loc(x, c(new = b)), + c("new", "a", "c") + ) + expect_named( + relocate_loc(x, c(new = b), after = c), + c("a", "c", "new") + ) +}) + +test_that("can't supply both `before` and `after`", { + expect_snapshot(error = TRUE, { + relocate_loc(c(x = 1), before = 1, after = 1) + }) + expect_snapshot(error = TRUE, { + relocate_loc(c(x = 1), before = 1, after = 1, before_arg = ".before", after_arg = ".after") + }) +}) + +test_that("can't relocate with out-of-bounds variables by default", { + x <- c(a = 1, b = 2) + + expect_snapshot({ + (expect_error(relocate_loc(x, c))) + (expect_error(relocate_loc(x, c(1, 3)))) + (expect_error(relocate_loc(x, a, before = c))) + (expect_error(relocate_loc(x, a, after = c))) + }) +}) + +test_that("can relocate with out-of-bounds variables in `expr` if `strict = FALSE`", { + x <- c(a = 1, b = 2) + + expect_identical(relocate_loc(x, c, strict = FALSE), c(a = 1L, b = 2L)) + expect_identical(relocate_loc(x, c(d = b, e = c), strict = FALSE), c(d = 2L, a = 1L)) + + # But still not with OOB variables in `before` or `after` + expect_snapshot({ + (expect_error(relocate_loc(x, a, before = c, strict = FALSE))) + (expect_error(relocate_loc(x, a, after = c, strict = FALSE))) + }) +}) + +test_that("accepts name spec", { + x <- c(a = 1, b = 2, c = 3) + + expect_identical( + relocate_loc(x, c(foo = c(c, a)), name_spec = "{outer}_{inner}"), + c(foo_1 = 3L, foo_2 = 1L, b = 2L) + ) + expect_identical( + relocate_loc(x, c(foo = c(bar = c, baz = a)), name_spec = "{outer}_{inner}"), + c(foo_bar = 3L, foo_baz = 1L, b = 2L) + ) +}) + +test_that("can forbid rename syntax", { + x <- c(a = 1, b = 2, c = 3) + + expect_snapshot({ + (expect_error(relocate_loc(x, c(foo = b), allow_rename = FALSE))) + (expect_error(relocate_loc(x, c(b, foo = b), allow_rename = FALSE))) + }) + + expect_named(relocate_loc(x, c(c, b), allow_rename = FALSE), c("c", "b", "a")) +}) + +test_that("can forbid empty selections", { + x <- c(a = 1, b = 2, c = 3) + + expect_snapshot({ + (expect_error(relocate_loc(x, allow_empty = FALSE))) + (expect_error(relocate_loc(mtcars, integer(), allow_empty = FALSE))) + (expect_error(relocate_loc(mtcars, starts_with("z"), allow_empty = FALSE))) + }) +}) + +test_that("`before` and `after` forbid renaming", { + x <- c(a = 1, b = 2, c = 3) + + expect_snapshot({ + (expect_error(relocate_loc(x, b, before = c(new = c)))) + (expect_error(relocate_loc(x, b, before = c(new = c), before_arg = ".before"))) + + (expect_error(relocate_loc(x, b, after = c(new = c)))) + (expect_error(relocate_loc(x, b, after = c(new = c), after_arg = ".after"))) + }) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-rename.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-rename.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-rename.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-rename.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,99 @@ +test_that("rename_loc() requires named vectors", { + expect_error( + rename_loc(letters, c(foo = a)), + "unnamed vector" + ) +}) + +test_that("rename_loc() partially renames", { + expect_identical( + rename_loc(mtcars, c(foo = cyl, bar = disp)), + int(foo = 2, bar = 3) + ) +}) + +test_that("rename_loc() allows renaming to self", { + expect_identical( + rename_loc(mtcars, c(mpg = mpg, cyl = cyl)), + int(mpg = 1, cyl = 2) + ) +}) + +test_that("rename() always preserves order", { + expect_identical( + rename(mtcars, c(disp = disp, cyl = cyl, mpg = mpg)), + mtcars + ) +}) + +test_that("rename_loc() partially renames", { + expect_identical( + rename_loc(mtcars, c(foo = cyl, bar = disp)), + int(foo = 2, bar = 3) + ) +}) + +test_that("rename_loc() requires unique names", { + expect_error( + rename_loc(mtcars, c(foo = cyl, foo = disp)), + class = "vctrs_error_names_must_be_unique" + ) + expect_error( + rename_loc(mtcars, c(cyl = mpg, foo = disp)), + class = "vctrs_error_names_must_be_unique" + ) +}) + +test_that("rename_loc() disambiguates if necessary", { + expect_identical( + rename_loc(mtcars, c(foo = starts_with("d"))), + int(foo1 = 3, foo2 = 5) + ) + expect_identical( + rename_loc(unclass(mtcars), c(foo = starts_with("d"))), + int(foo = 3, foo = 5) + ) +}) + +test_that("rename_loc() allows renaming to existing variable that is also renamed", { + expect_identical( + rename_loc(mtcars, c(cyl = mpg, foo = cyl)), + int(cyl = 1, foo = 2) + ) +}) + +test_that("rename_loc() allows fixing duplicates by locations", { + dups <- vctrs::new_data_frame(list(x = 1, x = 2)) + expect_identical( + rename_loc(dups, c(foo = 2L)), + int(foo = 2) + ) +}) + +test_that("rename_loc() works with predicate functions", { + x <- data.frame(a = 1, b = 2, c = "x", stringsAsFactors = FALSE) + expect_equal(rename_loc(x, c(var = where(is.numeric))), c(var1 = 1, var2 = 2)) + expect_snapshot(rename_loc(x, where(is.numeric)), error = TRUE) +}) + +test_that("rename_loc() requires named inputs", { + expect_error(rename_loc(iris, Species), "named") + expect_error(rename_loc(iris, c(contains("Width"))), "named") +}) + +test_that("rename_loc() uses names inside c()", { + expect_identical(rename_loc(iris, c(foo = Species)), c(foo = 5L)) +}) + +test_that("rename_loc() throws helpful errors", { + expect_snapshot(error = TRUE, { + "Unnamed vector" + rename_loc(letters, c(foo = a)) + + "Duplicate names (FIXME)" + rename_loc(mtcars, c(foo = cyl, foo = disp)) + + "Unnamed inputs" + rename_loc(iris, Species) + }) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-select.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-select.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-select.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-select.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,193 @@ +test_that("select() is generic", { + expect_identical( + select(set_names(letters), b:c), + c(b = "b", c = "c") + ) + expect_identical( + select(as.list(set_names(letters)), b:c), + list(b = "b", c = "c") + ) +}) + +test_that("select() supports existing duplicates", { + x <- list(a = 1, b = 2, a = 3) + expect_identical(select(x, A = a), list(A = 1, A = 3)) +}) + +test_that("absent `sel` leads to empty selection", { + expect_identical(select_loc(mtcars), named(int())) + expect_identical(select_loc(data.frame()), named(int())) +}) + +test_that("zero-length vector `sel` leads to empty selection (#214)", { + expect_identical(select_loc(mtcars, character()), named(int())) + expect_identical(select_loc(data.frame(), character()), named(int())) +}) + +test_that("can specify inclusion and exclusion", { + x <- list(a = 1, b = 2, c = 3) + expect_identical(select_loc(x, int(), include = "b"), c(b = 2L)) + expect_identical(select_loc(x, -int(), exclude = c("a", "c")), c(b = 2L)) + + # Can exclude variables that don't exist + expect_identical(select_loc(x, 2, exclude = "d"), c(b = 2L)) +}) + +test_that("included variables added to front", { + x <- list(a = 1, b = 2, c = 3) + expect_named(select_loc(x, "a", include = "b"), c("b", "a")) + expect_named(select_loc(x, "c", include = "b"), c("b", "c")) + + # but only if not already present + expect_named(select_loc(x, c("a", "b"), include = "b"), c("a", "b")) + expect_named(select_loc(x, c("b", "a"), include = "b"), c("b", "a")) + + state <- 0L + fn <- fn <- function() { + state <<- state + 1L + "b" + } + + select_loc(x, c("a", fn()), include = "b") + expect_equal(state, 1) +}) + +test_that("include and exclude validate their inputs", { + expect_snapshot({ + x <- list(a = 1, b = 2, c = 3) + (expect_error(select_loc(x, "a", include = 1))) + (expect_error(select_loc(x, "a", include = "d"))) + (expect_error(select_loc(x, "a", exclude = 1))) + }) +}) + +test_that("variables are excluded with non-strict `any_of()`", { + expect_identical( + select_loc(iris, 1:3, exclude = "foo"), + select_loc(iris, 1:3) + ) +}) + +test_that("select_loc() checks inputs", { + expect_error(select_loc(function() NULL), class = "vctrs_error_scalar_type") +}) + +test_that("select_loc() accepts name spec", { + expect_identical( + select_loc(mtcars, c(foo = c(mpg, cyl)), name_spec = "{outer}_{inner}"), + c(foo_1 = 1L, foo_2 = 2L) + ) +}) + +test_that("result is named even with constant inputs (#173)", { + expect_identical( + eval_select("Sepal.Width", iris), + c(Sepal.Width = 2L) + ) +}) + +test_that("can forbid rename syntax (#178)", { + expect_snapshot({ + (expect_error(select_loc(mtcars, c(foo = cyl), allow_rename = FALSE))) + (expect_error(select_loc(mtcars, c(cyl, foo = cyl), allow_rename = FALSE))) + (expect_error(select_loc(mtcars, c(cyl, foo = mpg), allow_rename = FALSE))) + (expect_error(select_loc(mtcars, c(foo = mpg, cyl), allow_rename = FALSE))) + }) + + expect_named(select_loc(mtcars, starts_with("c") | all_of("am"), allow_rename = FALSE), c("cyl", "carb", "am")) +}) + +test_that("can forbid empty selections", { + expect_snapshot(error = TRUE, { + select_loc(mtcars, allow_empty = FALSE) + select_loc(mtcars, integer(), allow_empty = FALSE) + select_loc(mtcars, starts_with("z"), allow_empty = FALSE) + }) +}) + +test_that("eval_select() errors mention correct calls", { + f <- function() stop("foo") + expect_snapshot((expect_error(select_loc(mtcars, f())))) +}) + +test_that("predicate outputs are type-checked", { + expect_snapshot({ + (expect_error(select_loc(mtcars, function(x) ""))) + }) +}) + +test_that("eval_select() produces correct backtraces", { + f <- function(base) g(base) + g <- function(base) h(base) + h <- function(base) if (base) stop("foo") else abort("foo") + + local_options( + rlang_trace_trop_env = current_env(), + rlang_trace_format_srcrefs = FALSE + ) + + expect_snapshot({ + print(expect_error(select_loc(mtcars, f(base = TRUE)))) + print(expect_error(select_loc(mtcars, f(base = FALSE)))) + }) +}) + +test_that("eval_select() produces correct chained errors", { + expect_snapshot({ + (expect_error(select_loc(mtcars, 1 + ""))) + + f <- function() 1 + "" + (expect_error(select_loc(mtcars, f()))) + }) +}) + +test_that("can select with predicate when `allow_rename` is `FALSE` (#225)", { + sel <- eval_select( + expr(where(is.numeric)), + mtcars, + allow_rename = FALSE + ) + expect_equal(sel, set_names(seq_along(mtcars), names(mtcars))) +}) + +test_that("location must resolve to numeric variables throws error", { + expect_error( + select_loc(letters2, !!list()), + class = "vctrs_error_subscript_type" + ) + expect_error( + select_loc(letters2, !!env()), + class = "vctrs_error_subscript_type" + ) +}) + +test_that("order is determined from inputs (#53)", { + expect_identical( + select_loc(mtcars, c(starts_with("c"), starts_with("d"))), + c(cyl = 2L, carb = 11L, disp = 3L, drat = 5L) + ) + expect_identical( + select_loc(mtcars, one_of(c("carb", "mpg"))), + c(carb = 11L, mpg = 1L) + ) +}) + + +test_that("middle (no-match) selector should not clear previous selectors (issue #2275)", { + cn <- setNames(nm = c("x", "y", "z")) + + expect_equal( + select_loc(cn, c(contains("x"), contains("foo"), contains("z"))), + c(x = 1L, z = 3L) + ) + expect_equal( + select_loc(cn, c(contains("x"), -contains("foo"), contains("z"))), + c(x = 1L, z = 3L) + ) +}) + +test_that("selecting with predicate + rename doesn't duplicate", { + x <- list(a = "x", b = "y", c = 1, d = 2) + expect_equal(select_loc(x, c(where(is.numeric), C = c)), c(C = 3, d = 4)) + expect_equal(select_loc(x, c(where(is.numeric), A = a)), c(c = 3, d = 4, A = 1)) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-walk.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-walk.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-eval-walk.R 2022-01-26 16:41:28.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-eval-walk.R 2022-09-20 21:56:55.000000000 +0000 @@ -119,63 +119,16 @@ }) test_that("can use arithmetic operators in non-data context", { - expect_identical(select_loc(letters2, identity(2 * 2 + 2 ^ 2 / 2)), c(f = 6L)) + expect_identical(select_loc(letters2, identity(2 * 2 + 2^2 / 2)), c(f = 6L)) }) test_that("symbol lookup outside data informs caller about better practice", { - skip("Non-deterministic failures") - local_options(tidyselect_verbosity = "verbose") - - vars1 <- c("a", "b") - expect_message(select_loc(letters2, vars1)) - - vars2 <- c("a", "b") # To force a message the second time - expect_snapshot(error = TRUE, { - select_loc(letters2, vars2) - }) -}) - -test_that("symbol evaluation only informs once (#184)", { expect_snapshot({ - "Default" - with_options(tidyselect_verbosity = NULL, { - `_vars_default` <- "cyl" - select_loc(mtcars, `_vars_default`) - select_loc(mtcars, `_vars_default`) - invisible(NULL) - }) - - "Verbose" - with_options(tidyselect_verbosity = "verbose", { - `_vars_verbose` <- "cyl" - select_loc(mtcars, `_vars_verbose`) - select_loc(mtcars, `_vars_verbose`) - invisible(NULL) - }) - - "Quiet" - with_options(tidyselect_verbosity = "quiet", { - `_vars_quiet` <- "cyl" - select_loc(mtcars, `_vars_quiet`) - select_loc(mtcars, `_vars_quiet`) - invisible(NULL) - }) + vars <- c("a", "b") + select_loc(letters2, vars) }) }) -test_that("symbol evaluation informs from global environment but not packages", { - fn <- function(name, select_loc) { - assign(name, 1L) - eval(bquote(select_loc(iris, .(as.symbol(name))))) - } - - environment(fn) <- env(global_env()) - expect_message(fn("from-global-env", select_loc), "ambiguous") - - environment(fn) <- ns_env("rlang") - expect_message(fn("from-ns-env", select_loc), NA) -}) - test_that("selection helpers are in the context mask", { out <- local(envir = env(base_env()), { letters2 <- rlang::set_names(letters) @@ -210,6 +163,13 @@ expect_identical(select_loc(iris, where(is.numeric) | where(is.factor)), set_names(1:5, names(iris))) }) +test_that("can forbid use of predicates", { + expect_snapshot( + select_loc(iris, where(is.factor), allow_predicates = FALSE), + error = TRUE + ) +}) + test_that("inline functions are allowed", { expect_identical( select_loc(iris, !!is.numeric), @@ -269,10 +229,19 @@ }) test_that("can select with .data pronoun (#2715)", { + withr::local_options(lifecycle_verbosity = "quiet") + expect_identical(select_loc(c(foo = "foo"), .data$foo), c(foo = 1L)) expect_identical(select_loc(c(foo = "foo"), .data[["foo"]]), c(foo = 1L)) - expect_identical(select_loc(letters2, .data$a : .data$b), c(a = 1L, b = 2L)) - expect_identical(select_loc(letters2, .data[["a"]] : .data[["b"]]), c(a = 1L, b = 2L)) + expect_identical(select_loc(letters2, .data$a:.data$b), c(a = 1L, b = 2L)) + expect_identical(select_loc(letters2, .data[["a"]]:.data[["b"]]), c(a = 1L, b = 2L)) +}) + +test_that("use of .data is deprecated", { + x <- list(a = 1, b = 2, c = 3) + var <- "a" + expect_snapshot(x <- select_loc(x, .data$a)) + expect_snapshot(x <- select_loc(x, .data[[var]])) }) test_that(".data in env-expression has the lexical definition", { @@ -292,14 +261,20 @@ test_that("can select names with unrepresentable characters", { skip_if_not_installed("rlang", "0.4.2.9000") - withr::with_locale(c(LC_CTYPE = "C"), { - name <- "\u4e2d" - tbl <- setNames(data.frame(a = 1), name) - expect_identical( - select_loc(tbl, !!sym(name)), - set_names(1L, name) - ) - }) + + # R now emits a warning when converting to symbol. Since Windows + # gained UTF-8 support, supporting unrepresentable characters is no + # longer necessary. + suppressWarnings( + withr::with_locale(c(LC_CTYPE = "C"), { + name <- "\u4e2d" + tbl <- setNames(data.frame(a = 1), name) + expect_identical( + select_loc(tbl, !!sym(name)), + set_names(1L, name) + ) + }) + ) }) test_that("`-1:-2` is syntax for `-(1:2)` for compatibility", { @@ -320,7 +295,7 @@ }) test_that("eval_sym() still supports predicate functions starting with `is`", { - local_options(tidyselect_verbosity = "quiet") + local_options(lifecycle_verbosity = "quiet") expect_identical(select_loc(iris, is_integer), select_loc(iris, where(is_integer))) expect_identical(select_loc(iris, is.numeric), select_loc(iris, where(is.numeric))) expect_identical(select_loc(iris, isTRUE), select_loc(iris, where(isTRUE))) @@ -328,7 +303,7 @@ test_that("eval_walk() has informative messages", { expect_snapshot({ - "# Using a predicate without where() warns" + "Using a predicate without where() warns" invisible(select_loc(iris, is_integer)) invisible(select_loc(iris, is.numeric)) invisible(select_loc(iris, isTRUE)) @@ -345,3 +320,21 @@ (expect_error(select_loc(mtcars, .data$"foo"))) }) }) + +test_that("can forbid empty selection", { + expect_snapshot(error = TRUE, { + ensure_named(integer(), allow_empty = FALSE) + ensure_named(integer(), allow_empty = FALSE, allow_rename = FALSE) + }) +}) + +test_that("can make empty selection with allow_rename = FALSE", { + expect_equal( + select_loc(mtcars, character(), allow_rename = FALSE), + set_names(integer(0)) + ) + expect_equal( + select_loc(mtcars, c(cyl, am), allow_rename = FALSE), + c(cyl = 2L, am = 9L) + ) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers-misc.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers-misc.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers-misc.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers-misc.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,14 @@ +test_that("last_col() selects last argument with offset", { + vars <- letters[1:3] + expect_identical(last_col(0, vars), 3L) + expect_identical(last_col(2, vars), 1L) +}) + +test_that("last_col() checks its inputs", { + expect_snapshot(error = TRUE, { + last_col(Inf, letters[1:3]) + last_col(3, letters[1:3]) + last_col(0, character()) + last_col(1:2, letters[1:3]) + }) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers-pattern.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers-pattern.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers-pattern.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers-pattern.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,207 @@ +test_that("no set variables throws error", { + expect_error(starts_with("z"), "`starts_with()` must be used within a *selecting* function", fixed = TRUE) +}) + +test_that("failed match removes all columns", { + local_vars(c("x", "y")) + + expect_equal(starts_with("z"), integer(0)) + expect_equal(ends_with("z"), integer(0)) + expect_equal(contains("z"), integer(0)) + expect_equal(matches("z"), integer(0)) + expect_equal(num_range("z", 1:3), integer(0)) +}) + +test_that("matches return integer locations", { + local_vars(c("abc", "acd", "bbc", "bbd", "eee")) + + expect_equal(starts_with("a"), c(1L, 2L)) + expect_equal(ends_with("d"), c(2L, 4L)) + expect_equal(contains("eee"), 5L) + expect_equal(matches(".b."), c(1L, 3L, 4L)) + expect_equal(matches("(? 1 vectors (#50)", { + expect_identical( + select_loc(iris, starts_with(c("Sep", "Petal"))), + select_loc(iris, starts_with("Sep") | starts_with("Petal")) + ) + expect_identical( + select_loc(iris, ends_with(c("gth", "Width"))), + select_loc(iris, ends_with("gth") | ends_with("Width")) + ) + expect_identical( + select_loc(iris, contains(c("epal", "eta"))), + select_loc(iris, contains("epal") | contains("eta")), + ) + expect_identical( + select_loc(iris, matches(c("epal", "eta"))), + select_loc(iris, matches("epal") | contains("eta")), + ) +}) + + +test_that("initial (single) selector defaults correctly (issue #2275)", { + cn <- setNames(nm = c("x", "y", "z")) + + ### Single Column Selected + + # single columns (present), explicit + expect_equal(select_loc(cn, x), c(x = 1L)) + expect_equal(select_loc(cn, -x), c(y = 2L, z = 3L)) + + # single columns (present), matched + expect_equal(select_loc(cn, contains("x")), c(x = 1L)) + expect_equal(select_loc(cn, -contains("x")), c(y = 2L, z = 3L)) + + # single columns (not present), explicit + expect_error(select_loc(cn, foo), class = "vctrs_error_subscript_oob") + expect_error(select_loc(cn, -foo), class = "vctrs_error_subscript_oob") + + # single columns (not present), matched + expect_equal(select_loc(cn, contains("foo")), named(int())) + expect_equal(select_loc(cn, -contains("foo")), set_names(seq_along(cn), cn)) +}) + +test_that("initial (of multiple) selectors default correctly (issue #2275)", { + cn <- setNames(nm = c("x", "y", "z")) + + ### Multiple Columns Selected + + # explicit(present) + matched(present) + expect_equal(select_loc(cn, c(x, contains("y"))), c(x = 1L, y = 2L)) + expect_equal(select_loc(cn, c(x, -contains("y"))), c(x = 1L)) + expect_equal(select_loc(cn, c(-x, contains("y"))), c(y = 2L, z = 3L)) + expect_equal(select_loc(cn, c(-x, -contains("y"))), c(z = 3L)) + + # explicit(present) + matched(not present) + expect_equal(select_loc(cn, c(x, contains("foo"))), c(x = 1L)) + expect_equal(select_loc(cn, c(x, -contains("foo"))), c(x = 1L)) + expect_equal(select_loc(cn, c(-x, contains("foo"))), c(y = 2L, z = 3L)) + expect_equal(select_loc(cn, c(-x, -contains("foo"))), c(y = 2L, z = 3L)) + + # matched(present) + explicit(present) + expect_equal(select_loc(cn, c(contains("x"), y)), c(x = 1L, y = 2L)) + expect_equal(select_loc(cn, c(contains("x"), -y)), c(x = 1L)) + expect_equal(select_loc(cn, c(-contains("x"), y)), c(y = 2L, z = 3L)) + expect_equal(select_loc(cn, c(-contains("x"), -y)), c(z = 3L)) + + # matched(not present) + explicit(not present) + expect_error(select_loc(cn, c(contains("foo"), bar)), class = "vctrs_error_subscript_oob") + expect_error(select_loc(cn, c(contains("foo"), -bar)), class = "vctrs_error_subscript_oob") + expect_error(select_loc(cn, c(-contains("foo"), bar)), class = "vctrs_error_subscript_oob") + expect_error(select_loc(cn, c(-contains("foo"), -bar)), class = "vctrs_error_subscript_oob") + + # matched(present) + matched(present) + expect_equal(select_loc(cn, c(contains("x"), contains("y"))), c(x = 1L, y = 2L)) + expect_equal(select_loc(cn, c(contains("x"), -contains("y"))), c(x = 1L)) + expect_equal(select_loc(cn, c(-contains("x"), contains("y"))), c(y = 2L, z = 3L)) + expect_equal(select_loc(cn, c(-contains("x"), -contains("y"))), c(z = 3L)) + + # matched(present) + matched(not present) + expect_equal(select_loc(cn, c(contains("x"), contains("foo"))), c(x = 1L)) + expect_equal(select_loc(cn, c(contains("x"), -contains("foo"))), c(x = 1L)) + expect_equal(select_loc(cn, c(-contains("x"), contains("foo"))), c(y = 2L, z = 3L)) + expect_equal(select_loc(cn, c(-contains("x"), -contains("foo"))), c(y = 2L, z = 3L)) + + # matched(not present) + matched(present) + expect_equal(select_loc(cn, c(contains("foo"), contains("x"))), c(x = 1L)) + expect_equal(select_loc(cn, c(contains("foo"), -contains("x"))), named(int())) + expect_equal(select_loc(cn, c(-contains("foo"), contains("x"))), c(x = 1L, y = 2L, z = 3L)) + expect_equal(select_loc(cn, c(-contains("foo"), -contains("x"))), c(y = 2L, z = 3L)) + + # matched(not present) + matched(not present) + expect_equal(select_loc(cn, c(contains("foo"), contains("bar"))), named(int())) + expect_equal(select_loc(cn, c(contains("foo"), -contains("bar"))), named(int())) + expect_equal(select_loc(cn, c(-contains("foo"), contains("bar"))), c(x = 1L, y = 2L, z = 3L)) + expect_equal(select_loc(cn, c(-contains("foo"), -contains("bar"))), c(x = 1L, y = 2L, z = 3L)) +}) + +test_that("matches() can use stringr patterns", { + local_vars(c(".", "x", "X")) + + expect_equal(matches(stringr::fixed(".")), 1) + expect_equal(matches(stringr::coll("x", ignore_case = TRUE)), c(2, 3)) +}) + +test_that("matches() complains about bad stringr pattern usage", { + local_vars(c("x", "y")) + + expect_snapshot(error = TRUE, { + matches(stringr::fixed("a"), perl = TRUE) + matches(stringr::fixed("a"), ignore.case = TRUE) + matches(stringr::fixed(c("a", "b"))) + }) +}) + +test_that("can supply named vectors to pattern helpers (#250)", { + exp <- c(cyl = 2L, carb = 11L) + + expect_equal( + select_loc(mtcars, matches(c(foo = "^c"))), + exp + ) + + expect_equal( + select_loc(mtcars, starts_with(c(foo = "c"))), + exp + ) + + expect_equal( + select_loc(mtcars, ends_with(c(foo = "l", bar = "b"))), + exp + ) + + expect_equal( + select_loc(mtcars, contains(c(foo = "yl", bar = "rb"))), + exp + ) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,63 @@ + +test_that("one_of gives useful errors", { + expect_snapshot({ + (expect_error( + one_of(1L, .vars = c("x", "y")), + class = "vctrs_error_incompatible_index_type" + )) + }) +}) + +test_that("one_of tolerates but warns for unknown columns", { + vars <- c("x", "y") + + expect_warning(res <- one_of("z", .vars = vars), "Unknown columns: `z`") + expect_equal(res, integer(0)) + expect_warning(res <- one_of(c("x", "z"), .vars = vars), "Unknown columns: `z`") + expect_equal(res, 1L) +}) + +test_that("one_of converts names to locations", { + expect_equal(one_of("a", "z", .vars = letters), c(1L, 26L)) +}) + +test_that("one_of works with variables", { + var <- "x" + expect_equal(select_loc(letters2, one_of(var)), c(x = 24L)) + # error messages from rlang + expect_error(select_loc(letters2, one_of(`_x`)), "not found") + expect_error(select_loc(letters2, one_of(`_y`)), "not found") +}) + +test_that("one_of works when passed variable name matches the column name (#2266)", { + x <- "x" + y <- "x" + expect_equal(select_loc(letters2, one_of(!!x)), c(x = 24L)) + expect_equal(select_loc(letters2, one_of(!!y)), c(x = 24L)) + expect_equal(select_loc(letters2, one_of(y)), c(x = 24L)) +}) + +test_that("one_of() supports S3 vectors", { + expect_identical(select_loc(letters2, one_of(factor(c("a", "c")))), c(a = 1L, c = 3L)) +}) + +test_that("one_of() compacts inputs (#110)", { + letters_seq <- set_names(seq_along(letters2), letters2) + expect_identical( + select_loc(letters2, -one_of()), + letters_seq + ) + expect_identical( + select_loc(letters2, -one_of(NULL)), + letters_seq + ) +}) + +test_that("no set variables throws error", { + expect_error(one_of("z"), "`one_of()` must be used within a *selecting* function", fixed = TRUE) +}) + + +test_that("no set variables throws error from the correct function", { + expect_error(one_of(starts_with("z")), "`one_of()` must be used within a *selecting* function", fixed = TRUE) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers-vector.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers-vector.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers-vector.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers-vector.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,77 @@ +test_that("`all_of()` fails even if `.strict` is FALSE", { + expect_snapshot( + error = TRUE, + select_loc(letters2, all_of(c("a", "bar", "c")), strict = FALSE) + ) +}) + +test_that("any_of() and all_of() preserve order (#186)", { + df <- data.frame(x = 1, y = 2) + expect_identical(select_loc(df, any_of(c("y", "x"))), c(y = 2L, x = 1L)) + expect_identical(select_loc(df, all_of(c("y", "x"))), c(y = 2L, x = 1L)) + + df <- data.frame(x = 1, y = 2, z = 3) + expect_identical( + select_loc(df, any_of(c("y", "z", "y", "x", "d", "z"))), + c(y = 2L, z = 3L, x = 1L) + ) +}) + +test_that("all_of() and any_of() handle named vectors", { + expect_identical(select_loc(letters2, all_of(c("a", foo = "b"))), c(a = 1L, foo = 2L)) + expect_identical(select_loc(letters2, any_of(c("a", foo = "b", "bar"))), c(a = 1L, foo = 2L)) +}) + +test_that("all_of() is strict", { + expect_error(select_loc(letters2, all_of(c("a", "foo"))), class = "vctrs_error_subscript_oob") +}) + +test_that("any_of() is lax", { + expect_identical( + select_loc(letters2, any_of(c("a", "foo"))), + select_loc(letters2, a) + ) + expect_identical( + select_loc(letters2, -any_of(c("a", "foo"))), + select_loc(letters2, -a) + ) +}) + +test_that("all_of() and any_of() check their inputs", { + expect_snapshot({ + (expect_error(select_loc(letters2, all_of(NA)))) + (expect_error(select_loc(letters2, any_of(NA)))) + + (expect_error(select_loc(letters2, all_of(TRUE)))) + (expect_error(select_loc(letters2, any_of(TRUE)))) + + (expect_error(select_loc(letters2, any_of(is.factor)))) + (expect_error(select_loc(letters2, all_of(is.factor)))) + }) +}) + +test_that("any_of() errors out of context", { + expect_snapshot({ + (expect_error(any_of())) + }) +}) + +test_that("all_of() is deprecated out of context (#269)", { + expect_snapshot(out <- all_of("x")) + expect_equal(out, "x") +}) + +test_that("any_of generates informative error if ... not empty", { + local_vars(letters) + + expect_snapshot(error = TRUE, { + any_of("b", "c", "d") + }) +}) + +test_that("all_of() returns an integer vector", { + with_vars( + letters, + expect_equal(all_of(c("b", "c", "d")), 2:4) + ) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers-where.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers-where.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-helpers-where.R 2021-11-15 08:43:54.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-helpers-where.R 2022-09-20 21:56:55.000000000 +0000 @@ -4,5 +4,13 @@ }) test_that("where() checks return values", { - expect_error(select_loc(iris, where(~ NA)), "return `TRUE` or `FALSE`") + expect_snapshot(error = TRUE, { + where(NA) + }) + + expect_snapshot(error = TRUE, { + select_loc(iris, where(~NA)) + select_loc(iris, where(~1)) + select_loc(iris, where(mean)) + }) }) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-lifecycle-deprecated.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-lifecycle-deprecated.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-lifecycle-deprecated.R 2021-11-15 08:54:27.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-lifecycle-deprecated.R 2022-09-20 21:56:55.000000000 +0000 @@ -1,8 +1,3 @@ -local_options( - lifecycle_verbosity = "quiet", - tidyselect_verbosity = "quiet" -) - # Once defunct, don't delete the tests, port them to `select_loc()`. # Better have some redundancy than accidentally losing coverage. @@ -25,7 +20,7 @@ }) test_that("can select with character vectors", { - expect_identical(vars_select(letters, "b", !! "z", c("b", "c")), set_names(c("b", "z", "c"))) + expect_identical(vars_select(letters, "b", !!"z", c("b", "c")), set_names(c("b", "z", "c"))) }) test_that("abort on unknown columns", { @@ -34,6 +29,8 @@ }) test_that("data mask is not isolated from context (for now)", { + local_options(lifecycle_verbosity = "quiet") + foo <- 10 expect_identical(vars_select(letters, foo), c(j = "j")) expect_identical(vars_select(letters, ((foo))), c(j = "j")) @@ -54,7 +51,7 @@ test_that("can customise error messages", { vars <- structure(letters, type = c("variable", "variables")) expect_error(vars_select(vars, "foo"), class = "vctrs_error_subscript_oob") - expect_warning(vars_select(vars, one_of("bim")), "Unknown variables:") + # expect_warning(vars_select(vars, one_of("bim")), "Unknown variables:") expect_error(vars_rename(vars, A = "foo"), class = "vctrs_error_subscript_oob") }) @@ -95,8 +92,8 @@ }) test_that("`-` handles character vectors (#35)", { - expect_identical(vars_select(letters, - (!! letters[1:20])), vars_select(letters, -(1:20))) - expect_error(vars_select(letters, - c("foo", "z", "bar")), class = "vctrs_error_subscript_oob") + expect_identical(vars_select(letters, -(!!letters[1:20])), vars_select(letters, -(1:20))) + expect_error(vars_select(letters, -c("foo", "z", "bar")), class = "vctrs_error_subscript_oob") }) test_that("can select `c` despite overscoped c()", { @@ -105,7 +102,7 @@ test_that("vars_select() handles named character vectors", { expect_identical(vars_select(letters, c("A" = "y", "B" = "z")), vars_select(letters, A = y, B = z)) - expect_identical(vars_select(letters, !! c("A" = "y", "B" = "z")), vars_select(letters, A = y, B = z)) + expect_identical(vars_select(letters, !!c("A" = "y", "B" = "z")), vars_select(letters, A = y, B = z)) }) test_that("can select with length > 1 double vectors (#43)", { @@ -113,6 +110,8 @@ }) test_that("missing values are detected in vars_select() (#72)", { + local_options(lifecycle_verbosity = "quiet") + expect_error( vars_select("foo", na_cpl), class = "vctrs_error_subscript_type" @@ -233,17 +232,6 @@ expect_error(vars_select(letters[1:2], A = a, A = b), class = "vctrs_error_names_must_be_unique") }) -test_that("vars_select() fails informatively when renaming to same", { - skip("FIXME") - expect_snapshot(error = TRUE, { - "Renaming to same:" - vars_select(letters, foo = a, bar = b, foo = c, ok = d, bar = e) - - "Renaming to existing:" - vars_select(letters, a = b, ok = c, d = e, everything()) - }) -}) - test_that("vars_select() has consistent location errors", { expect_error(vars_select(letters, foo), class = "vctrs_error_subscript_oob") expect_error(vars_select(letters, -foo), class = "vctrs_error_subscript_oob") @@ -326,6 +314,8 @@ }) test_that("vars_rename() supports `.data` pronoun", { + withr::local_options(lifecycle_verbosity = "quiet") + expect_identical(vars_rename(c("a", "b"), B = .data$b), c(a = "a", B = "b")) }) @@ -338,6 +328,8 @@ }) test_that("missing values are detected in vars_rename() (#72)", { + local_options(lifecycle_verbosity = "quiet") + expect_error( vars_rename(letters, A = na_cpl), class = "vctrs_error_subscript_type" diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-proxy.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-proxy.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-proxy.R 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-proxy.R 2022-09-20 21:56:55.000000000 +0000 @@ -0,0 +1,25 @@ +test_that("eval_*() respects proxy settings", { + foo <- structure(list(), class = "foo") + local_bindings( + tidyselect_data_proxy.foo = function(x) { + data.frame(x = 1, y = 2) + }, + tidyselect_data_has_predicates.foo = function(x) { + FALSE + }, + .env = globalenv() + ) + + expect_equal(eval_relocate(quote(everything()), foo), c(x = 1, y = 2)) + expect_equal(eval_select(quote(everything()), foo), c(x = 1, y = 2)) + expect_equal(eval_rename(quote(c(x = everything())), foo), c(x1 = 1, x2 = 2)) + + expect_snapshot(error = TRUE, { + eval_select(quote(where(is.numeric)), foo) + eval_rename(quote(c(x = where(is.numeric))), foo) + + eval_relocate(quote(where(is.numeric)), foo) + eval_relocate(quote(x), before = quote(where(is.numeric)), foo) + eval_relocate(quote(x), after = quote(where(is.numeric)), foo) + }) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-rename.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-rename.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-rename.R 2021-11-15 08:54:00.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-rename.R 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -test_that("rename_loc() requires named vectors", { - expect_error( - rename_loc(letters, c(foo = a)), - "unnamed vector" - ) -}) - -test_that("rename_loc() partially renames", { - expect_identical( - rename_loc(mtcars, c(foo = cyl, bar = disp)), - int(foo = 2, bar = 3) - ) -}) - -test_that("rename_loc() allows renaming to self", { - expect_identical( - rename_loc(mtcars, c(mpg = mpg, cyl = cyl)), - int(mpg = 1, cyl = 2) - ) -}) - -test_that("rename() always preserves order", { - expect_identical( - rename(mtcars, c(disp = disp, cyl = cyl, mpg = mpg)), - mtcars - ) -}) - -test_that("rename_loc() partially renames", { - expect_identical( - rename_loc(mtcars, c(foo = cyl, bar = disp)), - int(foo = 2, bar = 3) - ) -}) - -test_that("rename_loc() requires unique names", { - expect_error( - rename_loc(mtcars, c(foo = cyl, foo = disp)), - class = "vctrs_error_names_must_be_unique" - ) - expect_error( - rename_loc(mtcars, c(cyl = mpg, foo = disp)), - class = "vctrs_error_names_must_be_unique" - ) -}) - -test_that("rename_loc() disambiguates if necessary", { - expect_identical( - rename_loc(mtcars, c(foo = starts_with("d"))), - int(foo1 = 3, foo2 = 5) - ) - expect_identical( - rename_loc(unclass(mtcars), c(foo = starts_with("d"))), - int(foo = 3, foo = 5) - ) -}) - -test_that("rename_loc() allows renaming to existing variable that is also renamed", { - expect_identical( - rename_loc(mtcars, c(cyl = mpg, foo = cyl)), - int(cyl = 1, foo = 2) - ) -}) - -test_that("rename_loc() allows fixing duplicates by locations", { - dups <- vctrs::new_data_frame(list(x = 1, x = 2)) - expect_identical( - rename_loc(dups, c(foo = 2L)), - int(foo = 2) - ) -}) - -test_that("rename_loc() requires named inputs", { - expect_error(rename_loc(iris, Species), "named") - expect_error(rename_loc(iris, c(contains("Width"))), "named") -}) - -test_that("rename_loc() uses names inside c()", { - expect_identical(rename_loc(iris, c(foo = Species)), c(foo = 5L)) -}) - -test_that("rename_loc() throws helpful errors", { - expect_snapshot(error = TRUE, { - "Unnamed vector" - rename_loc(letters, c(foo = a)) - - "Duplicate names (FIXME)" - rename_loc(mtcars, c(foo = cyl, foo = disp)) - - "Unnamed inputs" - rename_loc(iris, Species) - }) -}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-select-helpers.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-select-helpers.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-select-helpers.R 2021-11-15 08:44:01.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-select-helpers.R 1970-01-01 00:00:00.000000000 +0000 @@ -1,337 +0,0 @@ -test_that("no set variables throws error", { - expect_error(starts_with("z"), "`starts_with()` must be used within a *selecting* function", fixed = TRUE) - expect_error(one_of("z"), "`one_of()` must be used within a *selecting* function", fixed = TRUE) -}) - -test_that("no set variables throws error from the correct function", { - expect_error(one_of(starts_with("z")), "`one_of()` must be used within a *selecting* function", fixed = TRUE) -}) - -test_that("generic error message is thrown if `fn` is not supplied", { - expect_error(peek_vars(), "Selection helpers must be used") -}) - -test_that("custom error message is thrown if `fn` is supplied", { - expect_error(peek_vars(fn = "z"), "`z()` must be used", fixed = TRUE) -}) - -test_that("failed match removes all columns", { - local_vars(c("x", "y")) - - expect_equal(starts_with("z"), integer(0)) - expect_equal(ends_with("z"), integer(0)) - expect_equal(contains("z"), integer(0)) - expect_equal(matches("z"), integer(0)) - expect_equal(num_range("z", 1:3), integer(0)) -}) - - -test_that("matches return integer locations", { - local_vars(c("abc", "acd", "bbc", "bbd", "eee")) - - expect_equal(starts_with("a"), c(1L, 2L)) - expect_equal(ends_with("d"), c(2L, 4L)) - expect_equal(contains("eee"), 5L) - expect_equal(matches(".b."), c(1L, 3L, 4L)) - expect_equal(matches("(? 1 vectors (#50)", { - expect_identical( - select_loc(iris, starts_with(c("Sep", "Petal"))), - select_loc(iris, starts_with("Sep") | starts_with("Petal")) - ) - expect_identical( - select_loc(iris, ends_with(c("gth", "Width"))), - select_loc(iris, ends_with("gth") | ends_with("Width")) - ) - expect_identical( - select_loc(iris, contains(c("epal", "eta"))), - select_loc(iris, contains("epal") | contains("eta")), - ) - expect_identical( - select_loc(iris, matches(c("epal", "eta"))), - select_loc(iris, matches("epal") | contains("eta")), - ) -}) - -test_that("`all_of()` doesn't fail if `.strict` is FALSE", { - expect_identical( - select_loc(letters2, all_of(c("a", "bar", "c")), strict = FALSE), - c(a = 1L, c = 3L) - ) -}) - -test_that("`all_of()` and `any_of()` require indices", { - expect_error( - select(iris, all_of(is.factor)), - class = "vctrs_error_subscript_type" - ) - expect_error( - select(iris, any_of(is.factor)), - class = "vctrs_error_subscript_type" - ) -}) - -test_that("any_of() and all_of() preserve order (#186)", { - df <- data.frame(x = 1, y = 2) - expect_identical(select_loc(df, any_of(c("y", "x"))), c(y = 2L, x = 1L)) - expect_identical(select_loc(df, all_of(c("y", "x"))), c(y = 2L, x = 1L)) - - df <- data.frame(x = 1, y = 2, z = 3) - expect_identical( - select_loc(df, any_of(c("y", "z", "y", "x", "d", "z"))), - c(y = 2L, z = 3L, x = 1L) - ) -}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-select.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-select.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-select.R 2022-01-24 13:12:54.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-select.R 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -test_that("select() is generic", { - expect_identical( - select(set_names(letters), b:c), - c(b = "b", c = "c") - ) - expect_identical( - select(as.list(set_names(letters)), b:c), - list(b = "b", c = "c") - ) -}) - -test_that("select() supports existing duplicates", { - x <- list(a = 1, b = 2, a = 3) - expect_identical(select(x, A = a), list(A = 1, A = 3)) -}) - -test_that("can call `select_loc()` without arguments", { - expect_identical(select_loc(mtcars), set_names(int(), chr())) -}) - -test_that("can specify inclusion and exclusion", { - x <- list(a = 1, b = 2, c = 3) - expect_identical(select_loc(x, int(), include = "b"), c(b = 2L)) - expect_identical(select_loc(x, -int(), exclude = c("a", "c")), c(b = 2L)) -}) - -test_that("variables are excluded with non-strict `any_of()`", { - expect_identical( - select_loc(iris, 1:3, exclude = "foo"), - select_loc(iris, 1:3) - ) -}) - -test_that("select_loc() checks inputs", { - expect_error(select_loc(function() NULL), class = "vctrs_error_scalar_type") -}) - -test_that("select_loc() accepts name spec", { - expect_identical( - select_loc(mtcars, c(foo = c(mpg, cyl)), name_spec = "{outer}_{inner}"), - c(foo_1 = 1L, foo_2 = 2L) - ) -}) - -test_that("result is named even with constant inputs (#173)", { - expect_identical( - eval_select("Sepal.Width", iris), - c(Sepal.Width = 2L) - ) -}) - -test_that("can forbid rename syntax (#178)", { - expect_error(select_loc(mtcars, c(foo = cyl), allow_rename = FALSE), "Can't rename") - expect_error(select_loc(mtcars, c(cyl, foo = cyl), allow_rename = FALSE), "Can't rename") - expect_named(select_loc(mtcars, starts_with("c") | all_of("am"), allow_rename = FALSE), NULL) -}) - -test_that("eval_select() errors mention correct calls", { - f <- function() stop("foo") - expect_snapshot((expect_error(select_loc(mtcars, f())))) -}) - -test_that("eval_select() produces correct backtraces", { - f <- function(base) g(base) - g <- function(base) h(base) - h <- function(base) if (base) stop("foo") else abort("foo") - - local_options( - rlang_trace_trop_env = current_env(), - rlang_trace_format_srcrefs = FALSE - ) - - expect_snapshot({ - print(expect_error(select_loc(mtcars, f(base = TRUE)))) - print(expect_error(select_loc(mtcars, f(base = FALSE)))) - }) -}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-sets.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-sets.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-sets.R 2021-11-15 08:44:05.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-sets.R 2022-09-20 21:56:55.000000000 +0000 @@ -46,4 +46,3 @@ expect_identical(sel_diff(c(1L, foo = 1L, bar = 1L), c(1L, bar = 1L)), c(foo = 1L)) expect_identical(sel_diff(c(1L, bar = 1L, foo = 1L), c(1L, foo = 1L)), c(bar = 1L)) }) - diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-vars-pull.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-vars-pull.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-vars-pull.R 2022-01-24 13:13:39.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-vars-pull.R 2022-09-20 21:56:55.000000000 +0000 @@ -1,8 +1,7 @@ test_that("errors for bad inputs", { - expect_error( - vars_pull(letters, letters), - class = "vctrs_error_subscript_type" - ) + expect_error(vars_pull(letters, character()), "exactly one") + expect_error(vars_pull(letters, c("a", "b")), "exactly one") + expect_error(vars_pull(letters, !!c("a", "b")), "exactly one") # FIXME expect_error( @@ -45,13 +44,12 @@ class = "vctrs_error_subscript_type" ) - expect_error( - vars_pull(letters, !!c("a", "b")), - class = "vctrs_error_subscript_type" - ) expect_snapshot(error = TRUE, { - vars_pull(letters, letters) + vars_pull(letters, character()) + vars_pull(letters, c("a", "b")) + vars_pull(letters, !!c("a", "b")) + vars_pull(letters, aa) vars_pull(letters, 0) vars_pull(letters, 100) @@ -61,10 +59,14 @@ vars_pull(letters, NA) vars_pull(letters, na_int) vars_pull(letters, "foo") - vars_pull(letters, !!c("a", "b")) }) }) +test_that("gives informative error if quosure is missing", { + f <- function(arg) vars_pull(letters, {{ arg }}) + expect_snapshot(f(), error = TRUE) +}) + test_that("can pull variables with missing elements", { expect_identical(vars_pull(c("a", ""), a), "a") expect_identical(vars_pull(c("a", NA), a), "a") @@ -79,6 +81,16 @@ test_that("can pull with strings", { expect_identical(vars_pull(letters, "b"), vars_pull(letters, b)) expect_error(vars_pull(letters, "foo"), class = "vctrs_error_subscript_oob") + + # even if those strings are numbers (#200) + vars <- c("-1", "0", "1") + expect_equal(vars_pull(vars, "-1"), "-1") + expect_equal(vars_pull(vars, "0"), "0") + expect_equal(vars_pull(vars, "1"), "1") +}) + +test_that("can pull with all_of() without warning", { + expect_identical(vars_pull(letters, all_of("z")), "z") }) test_that("can pull with negative values", { diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-vars.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-vars.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat/test-vars.R 2021-11-15 08:44:09.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat/test-vars.R 2022-09-20 21:56:55.000000000 +0000 @@ -60,3 +60,14 @@ test_that("peek_data() fails informatively", { expect_error(peek_data(), "must be used within") }) + +test_that("generic error message is thrown if `fn` is not supplied", { + expect_snapshot(peek_vars(), error = TRUE) + + withr::local_options(cli.hyperlink = TRUE, rlang_interactive = TRUE) + expect_snapshot(peek_vars(), error = TRUE) +}) + +test_that("custom error message is thrown if `fn` is supplied", { + expect_error(peek_vars(fn = "z"), "`z()` must be used", fixed = TRUE) +}) diff -Nru r-cran-tidyselect-1.1.2+dfsg/tests/testthat.R r-cran-tidyselect-1.2.0+dfsg/tests/testthat.R --- r-cran-tidyselect-1.1.2+dfsg/tests/testthat.R 2017-08-24 13:07:31.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/tests/testthat.R 2022-09-20 21:56:55.000000000 +0000 @@ -1,5 +1,4 @@ -library("testthat") -library("rlang") -library("tidyselect") +library(testthat) +library(tidyselect) test_check("tidyselect") diff -Nru r-cran-tidyselect-1.1.2+dfsg/vignettes/syntax.Rmd r-cran-tidyselect-1.2.0+dfsg/vignettes/syntax.Rmd --- r-cran-tidyselect-1.1.2+dfsg/vignettes/syntax.Rmd 2021-04-29 11:23:43.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/vignettes/syntax.Rmd 2022-09-20 21:56:55.000000000 +0000 @@ -61,10 +61,13 @@ renaming a variable to multiple names (see section on Renaming variables). -The syntax of tidyselect is generally designed for set combination. -For instance, `c(foo(), bar())` represents the union of the variables -in `foo()` and those in `bar()`. - +Today, the syntax of tidyselect is generally designed around Boolean algebra, +i.e. we recommend writing `starts_with("a") & !ends_with("z")`. Earlier +versions of tidyselect had more of a flavour of set operations, so that +you'd write `starts_with("a") - ends_with("b")`. While the set operations are +still supported, and is how tidyselect represents variables internally, we no +longer recommend them because Boolean algebra is easy for people to +understand. ### Bare names @@ -73,12 +76,11 @@ expressions are equivalent: ```{r} -mtcars %>% select_loc(mpg:hp, -cyl, vs) +mtcars %>% select_loc(mpg:hp, !cyl, vs) -mtcars %>% select_loc(1:4, -2, 8) +mtcars %>% select_loc(1:4, !2, 8) ``` - ### The `:` operator `:` can be used to select consecutive variables between two locations. @@ -95,16 +97,8 @@ mtcars %>% select_loc(cyl:hp) ``` - ### Boolean operators -Boolean operators provide a more intuitive approach to set -combination. Though sets are internally represented with vectors of -locations, they could equally be represented with a full logical -vector of inclusion indicators (taking the `which()` of this vector -would then recover the locations). The boolean operators should be -considered in terms of the logical representation of sets. - The `|` operator takes the __union__ of two sets: ```{r} @@ -130,11 +124,10 @@ iris %>% select_loc(starts_with("Sepal") & !ends_with("Width")) ``` +### Dots and `c()` -### Dots, `c()`, and unary `-` - -tidyselect functions can take dots like `dplyr::select()`, or a named -argument like `tidyr::pivot_longer()`. In the latter case, the dots +tidyselect functions can take dots, like `dplyr::select()`, or a named +argument, like `tidyr::pivot_longer()`. In the latter case, the dots syntax is accessible via `c()`. In fact `...` syntax is implemented through `c(...)` and is thus completely equivalent. @@ -144,72 +137,14 @@ mtcars %>% select_loc(c(mpg, disp:hp)) ``` -Dots and `c()` are syntax for: - -* Set union or set difference -* Renaming variables - -Non-negative inputs are recursively joined with `union()`. The -precedence is left-associative, just like with boolean operators. -These expressions are all syntax for _set union_: +`c(x, y, z)` is a equivalent to `x | y | z`: ```{r} iris %>% select_loc(starts_with("Sepal"), ends_with("Width"), Species) iris %>% select_loc(starts_with("Sepal") | ends_with("Width") | Species) - -iris %>% select_loc(union(union(starts_with("Sepal"), ends_with("Width")), 5L)) -``` - -Unary `-` is normally syntax for _set difference_: - -```{r} -iris %>% select_loc(starts_with("Sepal"), -ends_with("Width"), -Sepal.Length) - -iris %>% select_loc(setdiff(setdiff(starts_with("Sepal"), ends_with("Width")), 1L)) -``` - -If the first `...` or `c()` input is negative, an implicit -`everything()` is appended. - -```{r} -iris %>% select_loc(-starts_with("Sepal")) - -iris %>% select_loc(everything(), -starts_with("Sepal")) - -iris %>% select_loc(setdiff(everything(), starts_with("Sepal"))) -``` - -In this case, unary `-` is syntax for _set complement_. Unary `-` and -`!` are equivalent: - -```{r} -iris %>% select_loc(-starts_with("Sepal")) - -iris %>% select_loc(!starts_with("Sepal")) -``` - -Each level of `c()` is independent. In particular, a nested `c()` -starting with `-` always stands for set complement: - -```{r} -iris %>% select_loc(c(starts_with("Sepal"), -Sepal.Length)) - -iris %>% select_loc(c(starts_with("Sepal"), c(-Sepal.Length))) ``` -In boolean terms, these expressions are equivalent to: - -```{r} -iris %>% select_loc(starts_with("Sepal") & !Sepal.Length) - -iris %>% select_loc(starts_with("Sepal") | !Sepal.Length) -``` - -In general, when unary `-` is used alone outside `...` or `c()`, it -stands for set complement. - - ### Renaming variables #### Name combination and propagation diff -Nru r-cran-tidyselect-1.1.2+dfsg/vignettes/tidyselect.Rmd r-cran-tidyselect-1.2.0+dfsg/vignettes/tidyselect.Rmd --- r-cran-tidyselect-1.1.2+dfsg/vignettes/tidyselect.Rmd 2021-04-29 11:38:06.000000000 +0000 +++ r-cran-tidyselect-1.2.0+dfsg/vignettes/tidyselect.Rmd 2022-09-20 21:56:55.000000000 +0000 @@ -37,8 +37,7 @@ In this vignette, we describe how to include tidyselect in your own packages. If you just want to know how to use tidyselect syntax in -dplyr or tidyr, please read -instead. +dplyr or tidyr, please read `?language` instead. ## Before we start