diff --git a/.Rbuildignore b/.Rbuildignore
index c440a3d26..25b9f7aee 100644
--- a/.Rbuildignore
+++ b/.Rbuildignore
@@ -14,6 +14,7 @@
^README\.md$
^index\.md$
^LICENSE\.md$
+^CITATION\.cff$
vignettes
man/figures/
^tests/manual_tests$
@@ -48,3 +49,4 @@ tests/testthat/test-utils_profiling.R
tests/testthat/test-write_testthat_file.R
tests/testthat/test-yaml.R
tests/testthat/test-yaml_exec.R
+^.lintr$
diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml
index 1de524a93..064677b49 100644
--- a/.github/workflows/R-CMD-check.yaml
+++ b/.github/workflows/R-CMD-check.yaml
@@ -1,17 +1,23 @@
+# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
+# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
+#
+# NOTE: This workflow is overkill for most R packages and
+# check-standard.yaml is likely a better choice.
+# usethis::use_github_action("check-standard") will install it.
on:
push:
- branches:
- - main
+ branches: [main, master]
pull_request:
- branches:
- - main
+ branches: [main, master]
-name: R-CMD-check
+name: R-CMD-check.yaml
+
+permissions: read-all
jobs:
R-CMD-check:
runs-on: ${{ matrix.config.os }}
-
+
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
@@ -21,27 +27,22 @@ jobs:
- {os: macos-latest, r: 'release'}
- {os: windows-latest, r: 'release'}
- # # use 4.2 to check with rtools42's older compiler
- - {os: windows-latest, r: '4.2'}
- # # use 4.1 to check with rtools40's older compiler
- - {os: windows-latest, r: '4.1'}
- # # Use 3.6 to trigger usage of RTools35
- - {os: windows-latest, r: '3.6'}
-
- - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- - {os: ubuntu-latest, r: 'release'}
- - {os: ubuntu-latest, r: 'oldrel-1'}
- - {os: ubuntu-latest, r: 'oldrel-2'}
- - {os: ubuntu-latest, r: 'oldrel-3'}
- - {os: ubuntu-latest, r: 'oldrel-4'}
+ # use 4.0 or 4.1 to check with rtools40's older compiler
+ - {os: windows-latest, r: 'oldrel-4'}
+
+ - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
+ - {os: ubuntu-latest, r: 'release'}
+ - {os: ubuntu-latest, r: 'oldrel-1'}
+ - {os: ubuntu-latest, r: 'oldrel-2'}
+ - {os: ubuntu-latest, r: 'oldrel-3'}
+ - {os: ubuntu-latest, r: 'oldrel-4'}
env:
- R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
- GITHUB_PAT: ${{ secrets.GHA_PAT }}
+ GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: r-lib/actions/setup-pandoc@v2
@@ -58,4 +59,5 @@ jobs:
- uses: r-lib/actions/check-r-package@v2
with:
- upload-snapshots: true
\ No newline at end of file
+ upload-snapshots: true
+ build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
index fc751766b..018b8db3d 100644
--- a/.github/workflows/lint.yaml
+++ b/.github/workflows/lint.yaml
@@ -1,56 +1,34 @@
-on: [push, pull_request]
+# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
+# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
+on:
+ push:
+ branches: [main, master]
+ pull_request:
+ branches: [main, master]
-name: lint
+name: lint.yaml
+
+permissions: read-all
jobs:
lint:
runs-on: ubuntu-latest
-
env:
- GITHUB_PAT: ${{ secrets.GHA_PAT }}
-
+ GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
- - uses: r-lib/actions/setup-pandoc@v2
-
- uses: r-lib/actions/setup-r-dependencies@v2
with:
- extra-packages: any::pkgdown, local::.
- needs: website
-
- - name: Install package
- run: R CMD INSTALL .
-
- - name: Install dependencies
- run: |
- install.packages(c("remotes"))
- remotes::install_deps(dependencies = TRUE)
- remotes::install_cran("lintr")
- shell: Rscript {0}
+ extra-packages: any::lintr, local::.
+ needs: lint
- name: Lint
- run: |
- out <-
- lintr::lint_package(
- linters = lintr::linters_with_defaults(
- object_usage_linter = NULL,
- trailing_whitespace_linter = NULL,
- cyclocomp_linter = NULL,
- indentation_linter = NULL
- ),
- exclusions = c(
- list.files("tests", recursive = TRUE, full.names = TRUE),
- list.files("man", recursive = TRUE, full.names = TRUE),
- list.files("vignettes", recursive = TRUE, full.names = TRUE),
- list.files("data-raw", recursive = TRUE, full.names = TRUE),
- list.files("inst", recursive = TRUE, full.names = TRUE)
- )
- )
- print(out)
- if (length(out)) stop("lints found")
+ run: lintr::lint_package()
shell: Rscript {0}
+ env:
+ LINTR_ERROR_ON_LINT: true
diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml
index 036c0e8b2..4bbce7508 100644
--- a/.github/workflows/pkgdown.yaml
+++ b/.github/workflows/pkgdown.yaml
@@ -1,37 +1,50 @@
+# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
+# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
push:
- branches: main
+ branches: [main, master]
+ pull_request:
+ branches: [main, master]
+ release:
+ types: [published]
+ workflow_dispatch:
-name: pkgdown
+name: pkgdown.yaml
+
+permissions: read-all
jobs:
pkgdown:
runs-on: ubuntu-latest
# Only restrict concurrency for non-PR jobs
concurrency:
- group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
+ group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
env:
- GITHUB_PAT: ${{ secrets.GHA_PAT }}
-
+ GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+ permissions:
+ contents: write
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
+
+ - uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
-
- - uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::pkgdown, local::.
needs: website
-
- - name: Install package
- run: R CMD INSTALL .
-
- - name: Build and deploy pkgdown site
- run: |
- git config --local user.email "actions@github.com"
- git config --local user.name "GitHub Actions"
- Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)'
+
+ - name: Build site
+ run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
+ shell: Rscript {0}
+
+ - name: Deploy to GitHub pages 🚀
+ if: github.event_name != 'pull_request'
+ uses: JamesIves/github-pages-deploy-action@v4.5.0
+ with:
+ clean: false
+ branch: gh-pages
+ folder: docs
diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml
index dc30a7e81..988226098 100644
--- a/.github/workflows/test-coverage.yaml
+++ b/.github/workflows/test-coverage.yaml
@@ -1,21 +1,23 @@
+# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
+# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
push:
- branches:
- - main
+ branches: [main, master]
pull_request:
- branches:
- - main
+ branches: [main, master]
-name: test-coverage
+name: test-coverage.yaml
+
+permissions: read-all
jobs:
test-coverage:
runs-on: ubuntu-latest
env:
- GITHUB_PAT: ${{ secrets.GHA_PAT }}
+ GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
with:
@@ -23,9 +25,37 @@ jobs:
- uses: r-lib/actions/setup-r-dependencies@v2
with:
- extra-packages: any::covr
+ extra-packages: any::covr, any::xml2
needs: coverage
- name: Test coverage
- run: covr::codecov(quiet = FALSE)
+ run: |
+ cov <- covr::package_coverage(
+ quiet = FALSE,
+ clean = FALSE,
+ install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package")
+ )
+ covr::to_cobertura(cov)
shell: Rscript {0}
+
+ - uses: codecov/codecov-action@v4
+ with:
+ fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }}
+ file: ./cobertura.xml
+ plugin: noop
+ disable_search: true
+ token: ${{ secrets.CODECOV_TOKEN }}
+
+ - name: Show testthat output
+ if: always()
+ run: |
+ ## --------------------------------------------------------------------
+ find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true
+ shell: bash
+
+ - name: Upload test results
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: coverage-test-failures
+ path: ${{ runner.temp }}/package
diff --git a/.lintr b/.lintr
new file mode 100644
index 000000000..1530ed4d4
--- /dev/null
+++ b/.lintr
@@ -0,0 +1,14 @@
+linters: linters_with_defaults(
+ object_usage_linter = NULL,
+ trailing_whitespace_linter = NULL,
+ # cyclocomp_linter is no longer a default linter in lintr 3.2.0
+ cyclocomp_linter = NULL,
+ indentation_linter = NULL
+ )
+exclusions: list(
+ "tests",
+ "man",
+ "vignettes",
+ "data-raw",
+ "inst"
+ )
diff --git a/CITATION.cff b/CITATION.cff
index 82ed469b7..301a21de1 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -3,7 +3,7 @@ message: 'If you wish to cite the "pointblank" package use:'
type: software
license: MIT
title: 'pointblank: Data Validation and Organization of Metadata for Local and Remote Tables'
-version: 0.9.0
+version: 0.12.1
abstract: Validate data in data frames, 'tibble' objects, 'Spark'
'DataFrames', and database tables. Validation pipelines can be made using
easily-readable, consecutive validation steps. Upon execution of the
@@ -21,7 +21,11 @@ authors:
given-names: Mauricio
email: mavargas11@uc.cl
orcid: https://orcid.org/0000-0003-1017-7574
-repository: https://CRAN.R-project.org/package=pointblank
+- family-names: Choe
+ given-names: June
+ email: jchoe001@gmail.com
+ orcid: https://orcid.org/0000-0002-0701-921X
+repository: https://doi.org/10.32614/CRAN.package.pointblank
repository-code: https://github.com/rstudio/pointblank
url: https://rstudio.github.io/pointblank/
contact:
diff --git a/DESCRIPTION b/DESCRIPTION
index abec80d86..2a76e75dd 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,6 +1,6 @@
Type: Package
Package: pointblank
-Version: 0.11.4.9000
+Version: 0.12.1.9000
Title: Data Validation and Organization of Metadata for Local and Remote Tables
Description: Validate data in data frames, 'tibble' objects, 'Spark'
'DataFrames', and database tables. Validation pipelines can be made using
@@ -14,7 +14,9 @@ Authors@R: c(
person("Richard", "Iannone", , "rich@posit.co", c("aut", "cre"),
comment = c(ORCID = "0000-0003-3925-190X")),
person("Mauricio", "Vargas", , "mavargas11@uc.cl", c("aut"),
- comment = c(ORCID = "0000-0003-1017-7574"))
+ comment = c(ORCID = "0000-0003-1017-7574")),
+ person("June", "Choe", , "jchoe001@gmail.com", c("aut"),
+ comment = c(ORCID = "0000-0002-0701-921X"))
)
License: MIT + file LICENSE
URL: https://rstudio.github.io/pointblank/, https://github.com/rstudio/pointblank
@@ -22,7 +24,7 @@ BugReports: https://github.com/rstudio/pointblank/issues
Encoding: UTF-8
LazyData: true
ByteCompile: true
-RoxygenNote: 7.2.3
+RoxygenNote: 7.3.1
Depends:
R (>= 3.5.0)
Imports:
@@ -49,8 +51,6 @@ Imports:
Suggests:
arrow,
bigrquery,
- covr,
- crayon,
data.table,
duckdb,
ggforce,
diff --git a/LICENSE b/LICENSE
index 157d9c97e..43ec72d47 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,2 +1,2 @@
-YEAR: 2017-2023
-COPYRIGHT HOLDER: pointblank authors
+YEAR: 2017-2024
+COPYRIGHT HOLDER: Posit Software, PBC
diff --git a/LICENSE.md b/LICENSE.md
index 0cd23c29f..9c97dc6a3 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
# MIT License
-Copyright (c) 2017-2023 pointblank authors
+Copyright (c) 2017-2024 Posit Software, PBC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/NAMESPACE b/NAMESPACE
index b7dcd56b7..24736fbf4 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -49,7 +49,6 @@ export(col_vals_null)
export(col_vals_regex)
export(col_vals_within_spec)
export(conjointly)
-export(contains)
export(create_agent)
export(create_informant)
export(create_multiagent)
@@ -62,8 +61,6 @@ export(deactivate_steps)
export(draft_validation)
export(email_blast)
export(email_create)
-export(ends_with)
-export(everything)
export(expect_col_count_match)
export(expect_col_exists)
export(expect_col_is_character)
@@ -120,7 +117,6 @@ export(info_snippet)
export(info_tabular)
export(interrogate)
export(log4r_step)
-export(matches)
export(read_disk_multiagent)
export(remove_steps)
export(row_count_match)
@@ -135,7 +131,6 @@ export(snip_list)
export(snip_lowest)
export(snip_stats)
export(specially)
-export(starts_with)
export(stock_msg_body)
export(stock_msg_footer)
export(stop_if_not)
@@ -210,8 +205,3 @@ importFrom(dplyr,case_when)
importFrom(dplyr,vars)
importFrom(magrittr,"%>%")
importFrom(rlang,expr)
-importFrom(tidyselect,contains)
-importFrom(tidyselect,ends_with)
-importFrom(tidyselect,everything)
-importFrom(tidyselect,matches)
-importFrom(tidyselect,starts_with)
diff --git a/NEWS.md b/NEWS.md
index 12142382d..a90a987dc 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,53 @@
# pointblank (development version)
+## Minor improvements and bug fixes
+
+- `col_vals_expr()` now shows used columns in the agent report
+
+- Fixed a regression in `col_vals_*()` functions, where `vars("col")` was evaluating to the string `"col"`. Behavior of `vars("col")` is now aligned back with `vars(col)` - both evaluate to the column name `col`.
+
+- Warnings/errors arising from comparing `columns` to a `value` of different class (for example, comparing a datetime column to a date value `Sys.Date()` instead of another datetime value `Sys.time()`) are now signalled appropriately at `interrogate()`.
+
+- Improved readability of error and warning messages rendered as tooltip to the agent report.
+
+# pointblank 0.12.1
+
+- Ensured that the column string is a symbol before constructing the expression for the `col_vals_*()` functions.
+
+- No longer resolve columns with tidyselect when the target table cannot be materialized.
+
+- Relaxed tests on tidyselect error messages.
+
+# pointblank 0.12.0
+
+## New features
+
+* Complete `{tidyselect}` support for the `columns` argument of *all validation functions*, as well as in `has_columns()` and `info_columns`. The `columns` argument can now take familiar column-selection expressions as one would use inside `dplyr::select()`. This also begins a process of deprecation:
+ - `columns = vars(...)` will continue to work, but `c()` now supersedes `vars()`.
+ - If passing an *external vector* of column names, it should be wrapped in `all_of()`.
+
+* The `label` argument of validation functions now exposes the following string variables via `{glue}` syntax:
+
+ - `"{.step}"`: The validation step name
+ - `"{.col}"`: The current column name
+ - `"{.seg_col}"`: The current segment's column name
+ - `"{.seg_val}"`: The current segment's value/group
+
+ These dynamic values may be useful for validations that get expanded into multiple steps.
+
+* `interrogate()` gains two new options for printing progress in the console output:
+
+ - `progress`: Whether interrogation progress should be printed to the console (`TRUE` for interactive sessions, same as before)
+ - `show_step_label`: Whether each validation step's label value should be printed alongside the progress.
+
+## Minor improvements and bug fixes
+
+* Fixes issue with rendering reports in Quarto HTML documents.
+
+* When no columns are returned from a `{tidyselect}` expression in `columns`, the agent's report now displays the originally supplied *expression* instead of being simply blank (e.g., in `create_agent(small_table) |> col_vals_null(matches("z"))`).
+
+* Fixes issue with the hashing implementation to improve performance and alignment of validation steps in the multiagent.
+
# pointblank 0.11.4
* Fixes issue with gt `0.9.0` compatibility.
diff --git a/R/action_levels.R b/R/action_levels.R
index 53090490a..86ebec30f 100644
--- a/R/action_levels.R
+++ b/R/action_levels.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -154,10 +154,10 @@
#' actions = al
#' ) %>%
#' col_vals_gt(
-#' columns = vars(a), value = 2
+#' columns = a, value = 2
#' ) %>%
#' col_vals_lt(
-#' columns = vars(d), value = 20000
+#' columns = d, value = 20000
#' ) %>%
#' interrogate()
#' ```
@@ -188,11 +188,11 @@
#' actions = al
#' ) %>%
#' col_vals_gt(
-#' columns = vars(a), value = 2,
+#' columns = a, value = 2,
#' actions = warn_on_fail(warn_at = 0.5)
#' ) %>%
#' col_vals_lt(
-#' columns = vars(d), value = 20000
+#' columns = d, value = 20000
#' ) %>%
#' interrogate()
#' ```
@@ -220,7 +220,7 @@
#' ```r
#' small_table %>%
#' col_vals_gt(
-#' columns = vars(a), value = 2,
+#' columns = a, value = 2,
#' actions = warn_on_fail(warn_at = 2)
#' )
#' ```
@@ -256,7 +256,7 @@
#'
#' ```r
#' small_table %>%
-#' col_vals_gt(columns = vars(a), value = 2)
+#' col_vals_gt(columns = a, value = 2)
#' ```
#'
#' ```
@@ -273,7 +273,7 @@
#' ```r
#' small_table %>%
#' col_vals_gt(
-#' columns = vars(a), value = 2,
+#' columns = a, value = 2,
#' actions = stop_on_fail(stop_at = 1)
#' )
#' ```
diff --git a/R/all_passed.R b/R/all_passed.R
index d28b3ee3f..c68e30c1d 100644
--- a/R/all_passed.R
+++ b/R/all_passed.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -77,9 +77,9 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_vals_gt(columns = vars(a), value = 3) %>%
-#' col_vals_lte(columns = vars(a), value = 10) %>%
-#' col_vals_increasing(columns = vars(a)) %>%
+#' col_vals_gt(columns = a, value = 3) %>%
+#' col_vals_lte(columns = a, value = 10) %>%
+#' col_vals_increasing(columns = a) %>%
#' interrogate()
#' ```
#'
diff --git a/R/col_count_match.R b/R/col_count_match.R
index 2efee2074..cfcaae6b4 100644
--- a/R/col_count_match.R
+++ b/R/col_count_match.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -43,9 +43,9 @@
#' against the target table in terms of column count values. If supplying a
#' comparison table, it can either be a table object such as a data frame, a
#' tibble, a `tbl_dbi` object, or a `tbl_spark` object. Alternatively, a
-#' table-prep formula (`~
`) or a function (`function()
-#' `) can be used to lazily read in the comparison table
-#' at interrogation time.
+#' table-prep formula (`~ `) or a function (
+#' `function() `) can be used to lazily read in the
+#' comparison table at interrogation time.
#'
#' @return For the validation function, the return value is either a
#' `ptblank_agent` object or a table object (depending on whether an agent
@@ -103,6 +103,17 @@
#' depending on the situation (the first produces a warning, the other
#' `stop()`s).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
diff --git a/R/col_exists.R b/R/col_exists.R
index c6d752841..7ebc27c0b 100644
--- a/R/col_exists.R
+++ b/R/col_exists.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -34,14 +34,6 @@
#'
#' @inheritParams col_vals_gt
#'
-#' @param columns *The target columns*
-#'
-#' `vector|vars()`` // **required**
-#'
-#' One or more columns from the table in focus. This can be
-#' provided as a vector of column names using `c()` or bare column names
-#' enclosed in [vars()].
-#'
#' @return For the validation function, the return value is either a
#' `ptblank_agent` object or a table object (depending on whether an agent
#' object or a table was passed to `x`). The expectation function invisibly
@@ -69,12 +61,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Actions:
#'
@@ -89,6 +86,18 @@
#' depending on the situation (the first produces a warning, the other
#' `stop()`s).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -113,7 +122,7 @@
#' ```r
#' agent %>%
#' col_exists(
-#' columns = vars(a),
+#' columns = a,
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
#' label = "The `col_exists()` step.",
#' active = FALSE
@@ -125,7 +134,7 @@
#' ```yaml
#' steps:
#' - col_exists:
-#' columns: vars(a)
+#' columns: c(a)
#' actions:
#' warn_fraction: 0.1
#' stop_fraction: 0.2
@@ -164,7 +173,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_exists(columns = vars(a)) %>%
+#' col_exists(columns = a) %>%
#' interrogate()
#' ```
#'
@@ -185,7 +194,7 @@
#' The behavior of side effects can be customized with the `actions` option.
#'
#' ```{r}
-#' tbl %>% col_exists(columns = vars(a))
+#' tbl %>% col_exists(columns = a)
#' ```
#'
#' ## C: Using the expectation function
@@ -194,7 +203,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_exists(tbl, columns = vars(a))
+#' expect_col_exists(tbl, columns = a)
#' ```
#'
#' ## D: Using the test function
@@ -203,7 +212,7 @@
#' us.
#'
#' ```{r}
-#' tbl %>% test_col_exists(columns = vars(a))
+#' tbl %>% test_col_exists(columns = a)
#' ```
#'
#' @family validation functions
@@ -218,7 +227,7 @@ NULL
#' @export
col_exists <- function(
x,
- columns,
+ columns = NULL,
actions = NULL,
step_id = NULL,
label = NULL,
@@ -229,21 +238,26 @@ col_exists <- function(
preconditions <- NULL
values <- NULL
+ # Capture the `columns` expression
+ columns <- rlang::enquo(columns)
# Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
+ columns_expr <- as_columns_expr(columns)
- # Normalize the `columns` expression
- if (inherits(columns, "quosures")) {
-
- columns <-
- vapply(
- columns,
- FUN.VALUE = character(1),
- USE.NAMES = FALSE,
- FUN = function(x) as.character(rlang::get_expr(x))
- )
+ # Resolve the columns based on the expression
+ ## Only for `col_exists()`: error gracefully if column not found
+ columns <- tryCatch(
+ expr = resolve_columns(x = x, var_expr = columns, preconditions = NULL,
+ allow_empty = FALSE),
+ error = function(cnd) cnd$i %||% cnd
+ )
+ ## Missing column selection
+ if (rlang::is_error(columns)) {
+ cnd <- columns
+ if (inherits(cnd, "resolve_eval_err")) {
+ # Evaluation errors should be rethrown
+ rlang::cnd_signal(cnd)
+ }
+ columns <- NA_character_
}
if (is_a_table_object(x)) {
@@ -251,7 +265,7 @@ col_exists <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_exists(
- columns = columns,
+ columns = tidyselect::all_of(columns),
actions = prime_actions(actions),
label = label,
brief = brief,
@@ -281,7 +295,8 @@ col_exists <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
- for (i in seq(columns)) {
+ label <- resolve_label(label, columns)
+ for (i in seq_along(columns)) {
agent <-
create_validation_step(
@@ -293,7 +308,7 @@ col_exists <- function(
preconditions = NULL,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i]],
brief = brief[i],
active = active
)
diff --git a/R/col_is_character.R b/R/col_is_character.R
index 97afe6d62..db0ec3fd0 100644
--- a/R/col_is_character.R
+++ b/R/col_is_character.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -63,12 +63,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Actions:
#'
@@ -84,6 +89,18 @@
#' 1)` or `action_levels(stop_at = 1)` are good choices depending on the
#' situation (the first produces a warning, the other will `stop()`).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -108,7 +125,7 @@
#' ```r
#' agent %>%
#' col_is_character(
-#' columns = vars(a),
+#' columns = a,
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
#' label = "The `col_is_character()` step.",
#' active = FALSE
@@ -120,7 +137,7 @@
#' ```yaml
#' steps:
#' - col_is_character:
-#' columns: vars(a)
+#' columns: c(a)
#' actions:
#' warn_fraction: 0.1
#' stop_fraction: 0.2
@@ -159,7 +176,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_is_character(columns = vars(b)) %>%
+#' col_is_character(columns = b) %>%
#' interrogate()
#' ```
#'
@@ -181,7 +198,7 @@
#'
#' ```{r}
#' tbl %>%
-#' col_is_character(columns = vars(b)) %>%
+#' col_is_character(columns = b) %>%
#' dplyr::slice(1:5)
#' ```
#'
@@ -191,7 +208,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_is_character(tbl, columns = vars(b))
+#' expect_col_is_character(tbl, columns = b)
#' ```
#'
#' ## D: Using the test function
@@ -200,7 +217,7 @@
#' us.
#'
#' ```{r}
-#' tbl %>% test_col_is_character(columns = vars(b))
+#' tbl %>% test_col_is_character(columns = b)
#' ```
#'
#' @family validation functions
@@ -226,13 +243,10 @@ col_is_character <- function(
preconditions <- NULL
values <- NULL
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
@@ -242,7 +256,7 @@ col_is_character <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_is_character(
- columns = columns,
+ columns = tidyselect::all_of(columns),
label = label,
brief = brief,
actions = prime_actions(actions),
@@ -274,7 +288,8 @@ col_is_character <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
- for (i in seq(columns)) {
+ label <- resolve_label(label, columns)
+ for (i in seq_along(columns)) {
agent <-
create_validation_step(
@@ -286,7 +301,7 @@ col_is_character <- function(
preconditions = NULL,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i]],
brief = brief[i],
active = active
)
diff --git a/R/col_is_date.R b/R/col_is_date.R
index 3181f4e3c..b19dcf910 100644
--- a/R/col_is_date.R
+++ b/R/col_is_date.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -63,12 +63,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Actions:
#'
@@ -84,6 +89,18 @@
#' 1)` or `action_levels(stop_at = 1)` are good choices depending on the
#' situation (the first produces a warning, the other will `stop()`).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -108,7 +125,7 @@
#' ```r
#' agent %>%
#' col_is_date(
-#' columns = vars(a),
+#' columns = a,
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
#' label = "The `col_is_date()` step.",
#' active = FALSE
@@ -120,7 +137,7 @@
#' ```yaml
#' steps:
#' - col_is_date:
-#' columns: vars(a)
+#' columns: c(a)
#' actions:
#' warn_fraction: 0.1
#' stop_fraction: 0.2
@@ -151,7 +168,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = small_table) %>%
-#' col_is_date(columns = vars(date)) %>%
+#' col_is_date(columns = date) %>%
#' interrogate()
#' ```
#'
@@ -173,7 +190,7 @@
#'
#' ```{r}
#' small_table %>%
-#' col_is_date(columns = vars(date)) %>%
+#' col_is_date(columns = date) %>%
#' dplyr::slice(1:5)
#' ```
#'
@@ -183,7 +200,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_is_date(small_table, columns = vars(date))
+#' expect_col_is_date(small_table, columns = date)
#' ```
#'
#' ## D: Using the test function
@@ -192,7 +209,7 @@
#' us.
#'
#' ```{r}
-#' small_table %>% test_col_is_date(columns = vars(date))
+#' small_table %>% test_col_is_date(columns = date)
#' ```
#'
#' @family validation functions
@@ -218,13 +235,10 @@ col_is_date <- function(
preconditions <- NULL
values <- NULL
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
@@ -234,7 +248,7 @@ col_is_date <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_is_date(
- columns = columns,
+ columns = tidyselect::all_of(columns),
label = label,
brief = brief,
actions = prime_actions(actions),
@@ -266,7 +280,8 @@ col_is_date <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
- for (i in seq(columns)) {
+ label <- resolve_label(label, columns)
+ for (i in seq_along(columns)) {
agent <-
create_validation_step(
@@ -278,7 +293,7 @@ col_is_date <- function(
preconditions = NULL,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i]],
brief = brief[i],
active = active
)
diff --git a/R/col_is_factor.R b/R/col_is_factor.R
index 7283ca6c6..cd822a31b 100644
--- a/R/col_is_factor.R
+++ b/R/col_is_factor.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -63,12 +63,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Actions:
#'
@@ -84,6 +89,18 @@
#' 1)` or `action_levels(stop_at = 1)` are good choices depending on the
#' situation (the first produces a warning, the other will `stop()`).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -108,7 +125,7 @@
#' ```r
#' agent %>%
#' col_is_factor(
-#' columns = vars(a),
+#' columns = a,
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
#' label = "The `col_is_factor()` step.",
#' active = FALSE
@@ -120,7 +137,7 @@
#' ```yaml
#' steps:
#' - col_is_factor:
-#' columns: vars(a)
+#' columns: c(a)
#' actions:
#' warn_fraction: 0.1
#' stop_fraction: 0.2
@@ -157,7 +174,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_is_factor(columns = vars(f)) %>%
+#' col_is_factor(columns = f) %>%
#' interrogate()
#' ```
#'
@@ -179,7 +196,7 @@
#'
#' ```{r}
#' tbl %>%
-#' col_is_factor(columns = vars(f)) %>%
+#' col_is_factor(columns = f) %>%
#' dplyr::slice(1:5)
#' ```
#'
@@ -189,7 +206,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_is_factor(tbl, vars(f))
+#' expect_col_is_factor(tbl, f)
#' ```
#'
#' ## D: Using the test function
@@ -198,7 +215,7 @@
#' us.
#'
#' ```{r}
-#' tbl %>% test_col_is_factor(columns = vars(f))
+#' tbl %>% test_col_is_factor(columns = f)
#' ```
#'
#' @family validation functions
@@ -224,13 +241,10 @@ col_is_factor <- function(
preconditions <- NULL
values <- NULL
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
@@ -240,7 +254,7 @@ col_is_factor <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_is_factor(
- columns = columns,
+ columns = tidyselect::all_of(columns),
label = label,
brief = brief,
actions = prime_actions(actions),
@@ -272,7 +286,8 @@ col_is_factor <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
- for (i in seq(columns)) {
+ label <- resolve_label(label, columns)
+ for (i in seq_along(columns)) {
agent <-
create_validation_step(
@@ -284,12 +299,12 @@ col_is_factor <- function(
preconditions = NULL,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i]],
brief = brief[i],
active = active
)
}
-
+
agent
}
diff --git a/R/col_is_integer.R b/R/col_is_integer.R
index 4247b8cfc..36eb78cf3 100644
--- a/R/col_is_integer.R
+++ b/R/col_is_integer.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -63,12 +63,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Actions:
#'
@@ -84,6 +89,18 @@
#' 1)` or `action_levels(stop_at = 1)` are good choices depending on the
#' situation (the first produces a warning, the other will `stop()`).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -108,7 +125,7 @@
#' ```r
#' agent %>%
#' col_is_integer(
-#' columns = vars(a),
+#' columns = a,
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
#' label = "The `col_is_integer()` step.",
#' active = FALSE
@@ -120,7 +137,7 @@
#' ```yaml
#' steps:
#' - col_is_integer:
-#' columns: vars(a)
+#' columns: c(a)
#' actions:
#' warn_fraction: 0.1
#' stop_fraction: 0.2
@@ -157,7 +174,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_is_integer(columns = vars(b)) %>%
+#' col_is_integer(columns = b) %>%
#' interrogate()
#' ```
#'
@@ -178,7 +195,7 @@
#' behavior of side effects can be customized with the `actions` option.
#'
#' ```{r}
-#' tbl %>% col_is_integer(columns = vars(b))
+#' tbl %>% col_is_integer(columns = b)
#' ```
#'
#' ## C: Using the expectation function
@@ -187,7 +204,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_is_integer(tbl, columns = vars(b))
+#' expect_col_is_integer(tbl, columns = b)
#' ```
#'
#' ## D: Using the test function
@@ -196,7 +213,7 @@
#' us.
#'
#' ```{r}
-#' tbl %>% test_col_is_integer(columns = vars(b))
+#' tbl %>% test_col_is_integer(columns = b)
#' ```
#'
#' @family validation functions
@@ -222,13 +239,10 @@ col_is_integer <- function(
preconditions <- NULL
values <- NULL
- # Capture the `column` expression
+ # Capture the `columns` expression
columns <- rlang::enquo(columns)
-
# Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
@@ -238,7 +252,7 @@ col_is_integer <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_is_integer(
- columns = columns,
+ columns = tidyselect::all_of(columns),
label = label,
brief = brief,
actions = prime_actions(actions),
@@ -270,7 +284,8 @@ col_is_integer <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
- for (i in seq(columns)) {
+ label <- resolve_label(label, columns)
+ for (i in seq_along(columns)) {
agent <-
create_validation_step(
@@ -282,7 +297,7 @@ col_is_integer <- function(
preconditions = NULL,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i]],
brief = brief[i],
active = active
)
diff --git a/R/col_is_logical.R b/R/col_is_logical.R
index a3a4c3195..c2cb4663f 100644
--- a/R/col_is_logical.R
+++ b/R/col_is_logical.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -63,12 +63,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Actions:
#'
@@ -84,6 +89,18 @@
#' 1)` or `action_levels(stop_at = 1)` are good choices depending on the
#' situation (the first produces a warning, the other will `stop()`).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -108,7 +125,7 @@
#' ```r
#' agent %>%
#' col_is_logical(
-#' columns = vars(a),
+#' columns = a,
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
#' label = "The `col_is_logical()` step.",
#' active = FALSE
@@ -120,7 +137,7 @@
#' ```yaml
#' steps:
#' - col_is_logical:
-#' columns: vars(a)
+#' columns: c(a)
#' actions:
#' warn_fraction: 0.1
#' stop_fraction: 0.2
@@ -152,7 +169,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = small_table) %>%
-#' col_is_logical(columns = vars(e)) %>%
+#' col_is_logical(columns = e) %>%
#' interrogate()
#' ```
#'
@@ -174,7 +191,7 @@
#'
#' ```{r}
#' small_table %>%
-#' col_is_logical(columns = vars(e)) %>%
+#' col_is_logical(columns = e) %>%
#' dplyr::slice(1:5)
#' ```
#'
@@ -184,7 +201,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_is_logical(small_table, columns = vars(e))
+#' expect_col_is_logical(small_table, columns = e)
#' ```
#'
#' ## D: Using the test function
@@ -193,7 +210,7 @@
#' us.
#'
#' ```{r}
-#' small_table %>% test_col_is_logical(columns = vars(e))
+#' small_table %>% test_col_is_logical(columns = e)
#' ```
#'
#' @family validation functions
@@ -219,13 +236,10 @@ col_is_logical <- function(
preconditions <- NULL
values <- NULL
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
@@ -235,7 +249,7 @@ col_is_logical <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_is_logical(
- columns = columns,
+ columns = tidyselect::all_of(columns),
label = label,
brief = brief,
actions = prime_actions(actions),
@@ -267,7 +281,8 @@ col_is_logical <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
- for (i in seq(columns)) {
+ label <- resolve_label(label, columns)
+ for (i in seq_along(columns)) {
agent <-
create_validation_step(
@@ -279,12 +294,12 @@ col_is_logical <- function(
preconditions = NULL,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i]],
brief = brief[i],
active = active
)
}
-
+
agent
}
diff --git a/R/col_is_numeric.R b/R/col_is_numeric.R
index a92ec6675..40ecf1c9b 100644
--- a/R/col_is_numeric.R
+++ b/R/col_is_numeric.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -63,12 +63,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Actions:
#'
@@ -84,6 +89,18 @@
#' 1)` or `action_levels(stop_at = 1)` are good choices depending on the
#' situation (the first produces a warning, the other will `stop()`).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -108,7 +125,7 @@
#' ```r
#' agent %>%
#' col_is_numeric(
-#' columns = vars(a),
+#' columns = a,
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
#' label = "The `col_is_numeric()` step.",
#' active = FALSE
@@ -120,7 +137,7 @@
#' ```yaml
#' steps:
#' - col_is_numeric:
-#' columns: vars(a)
+#' columns: c(a)
#' actions:
#' warn_fraction: 0.1
#' stop_fraction: 0.2
@@ -152,7 +169,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = small_table) %>%
-#' col_is_numeric(columns = vars(d)) %>%
+#' col_is_numeric(columns = d) %>%
#' interrogate()
#' ```
#'
@@ -174,7 +191,7 @@
#'
#' ```{r}
#' small_table %>%
-#' col_is_numeric(columns = vars(d)) %>%
+#' col_is_numeric(columns = d) %>%
#' dplyr::slice(1:5)
#' ```
#'
@@ -184,7 +201,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_is_numeric(small_table, columns = vars(d))
+#' expect_col_is_numeric(small_table, columns = d)
#' ```
#'
#' ## D: Using the test function
@@ -193,7 +210,7 @@
#' us.
#'
#' ```{r}
-#' small_table %>% test_col_is_numeric(columns = vars(d))
+#' small_table %>% test_col_is_numeric(columns = d)
#' ```
#'
#' @family validation functions
@@ -219,13 +236,10 @@ col_is_numeric <- function(
preconditions <- NULL
values <- NULL
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
@@ -235,7 +249,7 @@ col_is_numeric <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_is_numeric(
- columns = columns,
+ columns = tidyselect::all_of(columns),
label = label,
brief = brief,
actions = prime_actions(actions),
@@ -267,7 +281,8 @@ col_is_numeric <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
- for (i in seq(columns)) {
+ label <- resolve_label(label, columns)
+ for (i in seq_along(columns)) {
agent <-
create_validation_step(
@@ -279,7 +294,7 @@ col_is_numeric <- function(
preconditions = NULL,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i]],
brief = brief[i],
active = active
)
diff --git a/R/col_is_posix.R b/R/col_is_posix.R
index 49a1b8926..368093bed 100644
--- a/R/col_is_posix.R
+++ b/R/col_is_posix.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -63,12 +63,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Actions:
#'
@@ -84,6 +89,18 @@
#' 1)` or `action_levels(stop_at = 1)` are good choices depending on the
#' situation (the first produces a warning, the other will `stop()`).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -108,7 +125,7 @@
#' ```r
#' agent %>%
#' col_is_posix(
-#' columns = vars(a),
+#' columns = a,
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
#' label = "The `col_is_posix()` step.",
#' active = FALSE
@@ -120,7 +137,7 @@
#' ```yaml
#' steps:
#' - col_is_posix:
-#' columns: vars(a)
+#' columns: c(a)
#' actions:
#' warn_fraction: 0.1
#' stop_fraction: 0.2
@@ -152,7 +169,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = small_table) %>%
-#' col_is_posix(columns = vars(date_time)) %>%
+#' col_is_posix(columns = date_time) %>%
#' interrogate()
#' ```
#'
@@ -174,7 +191,7 @@
#'
#' ```{r}
#' small_table %>%
-#' col_is_posix(columns = vars(date_time)) %>%
+#' col_is_posix(columns = date_time) %>%
#' dplyr::slice(1:5)
#' ```
#'
@@ -184,7 +201,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_is_posix(small_table, columns = vars(date_time))
+#' expect_col_is_posix(small_table, columns = date_time)
#' ```
#'
#' ## D: Using the test function
@@ -193,7 +210,7 @@
#' us.
#'
#' ```{r}
-#' small_table %>% test_col_is_posix(columns = vars(date_time))
+#' small_table %>% test_col_is_posix(columns = date_time)
#' ```
#'
#' @family validation functions
@@ -219,13 +236,10 @@ col_is_posix <- function(
preconditions <- NULL
values <- NULL
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
@@ -235,7 +249,7 @@ col_is_posix <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_is_posix(
- columns = columns,
+ columns = tidyselect::all_of(columns),
label = label,
brief = brief,
actions = prime_actions(actions),
@@ -267,7 +281,8 @@ col_is_posix <- function(
# Add one or more validation steps based on the
# length of the `column` variable
- for (i in seq(columns)) {
+ label <- resolve_label(label, columns)
+ for (i in seq_along(columns)) {
agent <-
create_validation_step(
@@ -279,12 +294,12 @@ col_is_posix <- function(
preconditions = NULL,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i]],
brief = brief[i],
active = active
)
}
-
+
agent
}
diff --git a/R/col_schema_match.R b/R/col_schema_match.R
index b775adea6..9e0260490 100644
--- a/R/col_schema_match.R
+++ b/R/col_schema_match.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -131,6 +131,17 @@
#' depending on the situation (the first produces a warning, the other
#' `stop()`s).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -508,8 +519,8 @@ test_col_schema_match <- function(
#' then any values provided to `...` will be ignored. This can either be a
#' table object, a table-prep formula.This can be a table object such as a
#' data frame, a tibble, a `tbl_dbi` object, or a `tbl_spark` object.
-#' Alternatively, a table-prep formula (`~ `) or a
-#' function (`function() `) can be used to lazily read in
+#' Alternatively, a table-prep formula (`~ `) or a
+#' function (`function() `) can be used to lazily read in
#' the table at interrogation time.
#'
#' @param .db_col_types *Use R column types or database column types?*
@@ -606,7 +617,7 @@ col_schema <- function(
db_col_types <- match.arg(.db_col_types)
- x <- list(...)
+ x <- rlang::list2(...)
# Transform SQL column types to lowercase to allow
# both uppercase and lowercase conventions while
diff --git a/R/col_vals_between.R b/R/col_vals_between.R
index e4d21464f..24e264ba1 100644
--- a/R/col_vals_between.R
+++ b/R/col_vals_between.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -95,12 +95,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names to `columns`, the result will be an
-#' expansion of validation steps to that number of column names (e.g.,
-#' `vars(col_a, col_b)` will result in the entry of two validation steps). Aside
-#' from column names in quotes and in `vars()`, **tidyselect** helper functions
-#' are available for specifying columns. They are: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -175,6 +180,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -199,7 +218,7 @@
#' ```r
#' agent %>%
#' col_vals_between(
-#' columns = vars(a),
+#' columns = a,
#' left = 1,
#' right = 2,
#' inclusive = c(TRUE, FALSE),
@@ -217,7 +236,7 @@
#' ```yaml
#' steps:
#' - col_vals_between:
-#' columns: vars(a)
+#' columns: c(a)
#' left: 1.0
#' right: 2.0
#' inclusive:
@@ -260,7 +279,7 @@
#' agent <-
#' create_agent(tbl = small_table) %>%
#' col_vals_between(
-#' columns = vars(c),
+#' columns = c,
#' left = 1, right = 9,
#' na_pass = TRUE
#' ) %>%
@@ -286,7 +305,7 @@
#' ```{r}
#' small_table %>%
#' col_vals_between(
-#' columns = vars(c),
+#' columns = c,
#' left = 1, right = 9,
#' na_pass = TRUE
#' ) %>%
@@ -300,7 +319,7 @@
#'
#' ```r
#' expect_col_vals_between(
-#' small_table, columns = vars(c),
+#' small_table, columns = c,
#' left = 1, right = 9,
#' na_pass = TRUE
#' )
@@ -314,7 +333,7 @@
#' ```{r}
#' small_table %>%
#' test_col_vals_between(
-#' columns = vars(c),
+#' columns = c,
#' left = 1, right = 9,
#' na_pass = TRUE
#' )
@@ -331,7 +350,7 @@
#' ```{r}
#' small_table %>%
#' test_col_vals_between(
-#' columns = vars(c), left = 1, right = 9,
+#' columns = c, left = 1, right = 9,
#' inclusive = c(TRUE, FALSE),
#' na_pass = TRUE
#' )
@@ -365,13 +384,10 @@ col_vals_between <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -393,7 +409,7 @@ col_vals_between <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_between(
- columns = columns,
+ columns = tidyselect::all_of(columns),
left = left,
right = right,
inclusive = inclusive,
@@ -436,6 +452,7 @@ col_vals_between <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -457,7 +474,7 @@ col_vals_between <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_decreasing.R b/R/col_vals_decreasing.R
index 21efe8729..9998f142f 100644
--- a/R/col_vals_decreasing.R
+++ b/R/col_vals_decreasing.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -85,12 +85,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names to `columns`, the result will be an
-#' expansion of validation steps to that number of column names (e.g.,
-#' `vars(col_a, col_b)` will result in the entry of two validation steps). Aside
-#' from column names in quotes and in `vars()`, **tidyselect** helper functions
-#' are available for specifying columns. They are: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -165,6 +170,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -189,7 +208,7 @@
#' ```r
#' agent %>%
#' col_vals_decreasing(
-#' columns = vars(a),
+#' columns = a,
#' allow_stationary = TRUE,
#' increasing_tol = 0.5,
#' na_pass = TRUE,
@@ -206,7 +225,7 @@
#' ```yaml
#' steps:
#' - col_vals_decreasing:
-#' columns: vars(a)
+#' columns: c(a)
#' allow_stationary: true
#' increasing_tol: 0.5
#' na_pass: true
@@ -259,7 +278,7 @@
#' agent <-
#' create_agent(tbl = game_revenue_2) %>%
#' col_vals_decreasing(
-#' columns = vars(time_left),
+#' columns = time_left,
#' allow_stationary = TRUE
#' ) %>%
#' interrogate()
@@ -284,7 +303,7 @@
#' ```{r}
#' game_revenue_2 %>%
#' col_vals_decreasing(
-#' columns = vars(time_left),
+#' columns = time_left,
#' allow_stationary = TRUE
#' ) %>%
#' dplyr::select(time_left) %>%
@@ -300,7 +319,7 @@
#' ```r
#' expect_col_vals_decreasing(
#' game_revenue_2,
-#' columns = vars(time_left),
+#' columns = time_left,
#' allow_stationary = TRUE
#' )
#' ```
@@ -313,7 +332,7 @@
#' ```{r}
#' game_revenue_2 %>%
#' test_col_vals_decreasing(
-#' columns = vars(time_left),
+#' columns = time_left,
#' allow_stationary = TRUE
#' )
#' ```
@@ -346,13 +365,10 @@ col_vals_decreasing <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -379,7 +395,7 @@ col_vals_decreasing <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_decreasing(
- columns = columns,
+ columns = tidyselect::all_of(columns),
allow_stationary = allow_stationary,
increasing_tol = increasing_tol,
na_pass = na_pass,
@@ -421,6 +437,7 @@ col_vals_decreasing <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -442,7 +459,7 @@ col_vals_decreasing <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_equal.R b/R/col_vals_equal.R
index f8ffd8804..c2d56bfdc 100644
--- a/R/col_vals_equal.R
+++ b/R/col_vals_equal.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -71,12 +71,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names to `columns`, the result will be an
-#' expansion of validation steps to that number of column names (e.g.,
-#' `vars(col_a, col_b)` will result in the entry of two validation steps). Aside
-#' from column names in quotes and in `vars()`, **tidyselect** helper functions
-#' are available for specifying columns. They are: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -151,6 +156,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -175,7 +194,7 @@
#' ```r
#' agent %>%
#' col_vals_equal(
-#' columns = vars(a),
+#' columns = a,
#' value = 1,
#' na_pass = TRUE,
#' preconditions = ~ . %>% dplyr::filter(a < 10),
@@ -191,7 +210,7 @@
#' ```yaml
#' steps:
#' - col_vals_equal:
-#' columns: vars(a)
+#' columns: c(a)
#' value: 1.0
#' na_pass: true
#' preconditions: ~. %>% dplyr::filter(a < 10)
@@ -238,7 +257,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_vals_equal(columns = vars(a), value = 5) %>%
+#' col_vals_equal(columns = a, value = 5) %>%
#' interrogate()
#' ```
#'
@@ -260,7 +279,7 @@
#'
#' ```{r}
#' tbl %>%
-#' col_vals_equal(columns = vars(a), value = 5) %>%
+#' col_vals_equal(columns = a, value = 5) %>%
#' dplyr::pull(a)
#' ```
#'
@@ -270,7 +289,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_vals_equal(tbl, columns = vars(a), value = 5)
+#' expect_col_vals_equal(tbl, columns = a, value = 5)
#' ```
#'
#' ## D: Using the test function
@@ -279,7 +298,7 @@
#' us.
#'
#' ```{r}
-#' test_col_vals_equal(tbl, columns = vars(a), value = 5)
+#' test_col_vals_equal(tbl, columns = a, value = 5)
#' ```
#'
#' @family validation functions
@@ -308,13 +327,10 @@ col_vals_equal <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -332,7 +348,7 @@ col_vals_equal <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_equal(
- columns = columns,
+ columns = tidyselect::all_of(columns),
value = value,
na_pass = na_pass,
preconditions = preconditions,
@@ -373,6 +389,7 @@ col_vals_equal <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -394,7 +411,7 @@ col_vals_equal <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_expr.R b/R/col_vals_expr.R
index ba16383cd..9d09cc0d3 100644
--- a/R/col_vals_expr.R
+++ b/R/col_vals_expr.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -134,6 +134,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -325,6 +339,10 @@ col_vals_expr <- function(
}
}
+ # Extract columns from expr
+ data_cols <- colnames(apply_preconditions_for_cols(x, preconditions))
+ columns <- all_data_vars(expr, data_cols)
+
# Resolve segments into list
segments_list <-
resolve_segments(
@@ -374,6 +392,7 @@ col_vals_expr <- function(
# Add one or more validation steps based on the
# length of `segments_list`
+ label <- resolve_label(label, segments = segments_list)
for (i in seq_along(segments_list)) {
seg_col <- names(segments_list[i])
@@ -385,7 +404,7 @@ col_vals_expr <- function(
assertion_type = "col_vals_expr",
i_o = i_o,
columns_expr = NA_character_,
- column = NA_character_,
+ column = columns,
values = expr,
preconditions = preconditions,
seg_expr = segments,
@@ -393,7 +412,7 @@ col_vals_expr <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id,
- label = label,
+ label = label[[i]],
brief = brief,
active = active
)
diff --git a/R/col_vals_gt.R b/R/col_vals_gt.R
index 1ebbd99e8..5f0d8a4cb 100644
--- a/R/col_vals_gt.R
+++ b/R/col_vals_gt.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -53,10 +53,11 @@
#'
#' @param columns *The target columns*
#'
-#' `` // **required**
+#' `` // **required**
#'
-#' The column (or a set of columns, provided as a character vector) to which
-#' this validation should be applied.
+#' A column-selecting expression, as one would use inside `dplyr::select()`.
+#' Specifies the column (or a set of columns) to which this validation should
+#' be applied. See the *Column Names* section for more information.
#'
#' @param value *Value for comparison*
#'
@@ -131,12 +132,13 @@
#' means that 15 percent of failing test units results in an overall test
#' failure.
#'
-#' @param label *An optional label for the validation step*
+#' @param label *Optional label for the validation step*
#'
-#' `scalar` // *default:* `NULL` (`optional`)
+#' `vector` // *default:* `NULL` (`optional`)
#'
-#' An optional label for the validation step. This label appears in the
-#' *agent* report and, for the best appearance, it should be kept quite short.
+#' Optional label for the validation step. This label appears in the *agent*
+#' report and, for the best appearance, it should be kept quite short. See
+#' the *Labels* section for more information.
#'
#' @param brief *Brief description for the validation step*
#'
@@ -164,7 +166,7 @@
#' logical value. With this approach, the **pointblank** function
#' [has_columns()] can be used to determine whether to make a validation step
#' active on the basis of one or more columns existing in the table
-#' (e.g., `~ . %>% has_columns(vars(d, e))`).
+#' (e.g., `~ . %>% has_columns(c(d, e))`).
#'
#' @return For the validation function, the return value is either a
#' `ptblank_agent` object or a table object (depending on whether an *agent*
@@ -193,12 +195,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names to `columns`, the result will be an
-#' expansion of validation steps to that number of column names (e.g.,
-#' `vars(col_a, col_b)` will result in the entry of two validation steps). Aside
-#' from column names in quotes and in `vars()`, **tidyselect** helper functions
-#' are available for specifying columns. They are: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -273,6 +280,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -297,7 +318,7 @@
#' ```r
#' agent %>%
#' col_vals_gt(
-#' columns = vars(a),
+#' columns = a,
#' value = 1,
#' na_pass = TRUE,
#' preconditions = ~ . %>% dplyr::filter(a < 10),
@@ -313,7 +334,7 @@
#' ```yaml
#' steps:
#' - col_vals_gt:
-#' columns: vars(a)
+#' columns: c(a)
#' value: 1.0
#' na_pass: true
#' preconditions: ~. %>% dplyr::filter(a < 10)
@@ -360,7 +381,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_vals_gt(columns = vars(a), value = 4) %>%
+#' col_vals_gt(columns = a, value = 4) %>%
#' interrogate()
#' ```
#'
@@ -381,7 +402,7 @@
#' behavior of side effects can be customized with the `actions` option.
#'
#' ```{r}
-#' tbl %>% col_vals_gt(columns = vars(a), value = 4)
+#' tbl %>% col_vals_gt(columns = a, value = 4)
#' ```
#'
#' ## C: Using the expectation function
@@ -390,7 +411,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_vals_gt(tbl, columns = vars(a), value = 4)
+#' expect_col_vals_gt(tbl, columns = a, value = 4)
#' ```
#'
#' ## D: Using the test function
@@ -399,7 +420,7 @@
#' us.
#'
#' ```{r}
-#' test_col_vals_gt(tbl, columns = vars(a), value = 4)
+#' test_col_vals_gt(tbl, columns = a, value = 4)
#' ```
#'
#' @family validation functions
@@ -428,13 +449,10 @@ col_vals_gt <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -452,7 +470,7 @@ col_vals_gt <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_gt(
- columns = columns,
+ columns = tidyselect::all_of(columns),
value = value,
na_pass = na_pass,
preconditions = preconditions,
@@ -493,6 +511,7 @@ col_vals_gt <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -514,7 +533,7 @@ col_vals_gt <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_gte.R b/R/col_vals_gte.R
index 5b6e14109..2498ebf7f 100644
--- a/R/col_vals_gte.R
+++ b/R/col_vals_gte.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -73,12 +73,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names to `columns`, the result will be an
-#' expansion of validation steps to that number of column names (e.g.,
-#' `vars(col_a, col_b)` will result in the entry of two validation steps). Aside
-#' from column names in quotes and in `vars()`, **tidyselect** helper functions
-#' are available for specifying columns. They are: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -152,6 +157,20 @@
#' situation (the first produces a warning when a quarter of the total test
#' units fails, the other `stop()`s at the same threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -176,7 +195,7 @@
#' ```r
#' agent %>%
#' col_vals_gte(
-#' columns = vars(a),
+#' columns = a,
#' value = 1,
#' na_pass = TRUE,
#' preconditions = ~ . %>% dplyr::filter(a < 10),
@@ -192,7 +211,7 @@
#' ```yaml
#' steps:
#' - col_vals_gte:
-#' columns: vars(a)
+#' columns: c(a)
#' value: 1.0
#' na_pass: true
#' preconditions: ~. %>% dplyr::filter(a < 10)
@@ -239,7 +258,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_vals_gte(columns = vars(a), value = 5) %>%
+#' col_vals_gte(columns = a, value = 5) %>%
#' interrogate()
#' ```
#'
@@ -260,7 +279,7 @@
#' behavior of side effects can be customized with the `actions` option.
#'
#' ```{r}
-#' tbl %>% col_vals_gte(columns = vars(a), value = 5)
+#' tbl %>% col_vals_gte(columns = a, value = 5)
#' ```
#'
#' ## C: Using the expectation function
@@ -269,7 +288,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_vals_gte(tbl, columns = vars(a), value = 5)
+#' expect_col_vals_gte(tbl, columns = a, value = 5)
#' ```
#'
#' ## D: Using the test function
@@ -278,7 +297,7 @@
#' us.
#'
#' ```{r}
-#' test_col_vals_gte(tbl, columns = vars(a), value = 5)
+#' test_col_vals_gte(tbl, columns = a, value = 5)
#' ```
#'
#' @family validation functions
@@ -307,13 +326,10 @@ col_vals_gte <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -331,7 +347,7 @@ col_vals_gte <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_gte(
- columns = columns,
+ columns = tidyselect::all_of(columns),
value = value,
na_pass = na_pass,
preconditions = preconditions,
@@ -372,6 +388,7 @@ col_vals_gte <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -393,7 +410,7 @@ col_vals_gte <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_in_set.R b/R/col_vals_in_set.R
index e4b7557cc..7635008f1 100644
--- a/R/col_vals_in_set.R
+++ b/R/col_vals_in_set.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -69,12 +69,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Preconditions:
#'
@@ -142,6 +147,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -166,7 +185,7 @@
#' ```r
#' agent %>%
#' col_vals_in_set(
-#' columns = vars(a),
+#' columns = a,
#' set = c(1, 2, 3, 4),
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' segments = b ~ c("group_1", "group_2"),
@@ -181,7 +200,7 @@
#' ```yaml
#' steps:
#' - col_vals_in_set:
-#' columns: vars(a)
+#' columns: c(a)
#' set:
#' - 1.0
#' - 2.0
@@ -222,7 +241,7 @@
#' agent <-
#' create_agent(tbl = small_table) %>%
#' col_vals_in_set(
-#' columns = vars(f), set = c("low", "mid", "high")
+#' columns = f, set = c("low", "mid", "high")
#' ) %>%
#' interrogate()
#' ```
@@ -246,7 +265,7 @@
#' ```{r}
#' small_table %>%
#' col_vals_in_set(
-#' columns = vars(f), set = c("low", "mid", "high")
+#' columns = f, set = c("low", "mid", "high")
#' ) %>%
#' dplyr::pull(f) %>%
#' unique()
@@ -260,7 +279,7 @@
#' ```r
#' expect_col_vals_in_set(
#' small_table,
-#' columns = vars(f), set = c("low", "mid", "high")
+#' columns = f, set = c("low", "mid", "high")
#' )
#' ```
#'
@@ -272,7 +291,7 @@
#' ```{r}
#' small_table %>%
#' test_col_vals_in_set(
-#' columns = vars(f), set = c("low", "mid", "high")
+#' columns = f, set = c("low", "mid", "high")
#' )
#' ```
#'
@@ -301,13 +320,10 @@ col_vals_in_set <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -325,7 +341,7 @@ col_vals_in_set <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_in_set(
- columns = columns,
+ columns = tidyselect::all_of(columns),
set = set,
preconditions = preconditions,
segments = segments,
@@ -365,6 +381,7 @@ col_vals_in_set <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -385,7 +402,7 @@ col_vals_in_set <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_increasing.R b/R/col_vals_increasing.R
index 7d77bf6d9..44060c080 100644
--- a/R/col_vals_increasing.R
+++ b/R/col_vals_increasing.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -85,12 +85,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names to `columns`, the result will be an
-#' expansion of validation steps to that number of column names (e.g.,
-#' `vars(col_a, col_b)` will result in the entry of two validation steps). Aside
-#' from column names in quotes and in `vars()`, **tidyselect** helper functions
-#' are available for specifying columns. They are: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -165,6 +170,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -189,7 +208,7 @@
#' ```r
#' agent %>%
#' col_vals_increasing(
-#' columns = vars(a),
+#' columns = a,
#' allow_stationary = TRUE,
#' decreasing_tol = 0.5,
#' na_pass = TRUE,
@@ -206,7 +225,7 @@
#' ```yaml
#' steps:
#' - col_vals_increasing:
-#' columns: vars(a)
+#' columns: c(a)
#' allow_stationary: true
#' decreasing_tol: 0.5
#' na_pass: true
@@ -247,7 +266,7 @@
#' agent <-
#' create_agent(tbl = game_revenue) %>%
#' col_vals_increasing(
-#' columns = vars(session_start),
+#' columns = session_start,
#' allow_stationary = TRUE
#' ) %>%
#' interrogate()
@@ -272,7 +291,7 @@
#' ```{r}
#' game_revenue %>%
#' col_vals_increasing(
-#' columns = vars(session_start),
+#' columns = session_start,
#' allow_stationary = TRUE
#' ) %>%
#' dplyr::select(session_start) %>%
@@ -288,7 +307,7 @@
#' ```r
#' expect_col_vals_increasing(
#' game_revenue,
-#' columns = vars(session_start),
+#' columns = session_start,
#' allow_stationary = TRUE
#' )
#' ```
@@ -301,7 +320,7 @@
#' ```{r}
#' game_revenue %>%
#' test_col_vals_increasing(
-#' columns = vars(session_start),
+#' columns = session_start,
#' allow_stationary = TRUE
#' )
#' ```
@@ -334,13 +353,10 @@ col_vals_increasing <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -367,7 +383,7 @@ col_vals_increasing <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_increasing(
- columns = columns,
+ columns = tidyselect::all_of(columns),
allow_stationary = allow_stationary,
decreasing_tol = decreasing_tol,
na_pass = na_pass,
@@ -409,6 +425,7 @@ col_vals_increasing <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -430,7 +447,7 @@ col_vals_increasing <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_lt.R b/R/col_vals_lt.R
index d8553a2b0..0e8a05b7b 100644
--- a/R/col_vals_lt.R
+++ b/R/col_vals_lt.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -72,12 +72,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names to `columns`, the result will be an
-#' expansion of validation steps to that number of column names (e.g.,
-#' `vars(col_a, col_b)` will result in the entry of two validation steps). Aside
-#' from column names in quotes and in `vars()`, **tidyselect** helper functions
-#' are available for specifying columns. They are: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -152,6 +157,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -176,7 +195,7 @@
#' ```r
#' agent %>%
#' col_vals_lt(
-#' columns = vars(a),
+#' columns = a,
#' value = 1,
#' na_pass = TRUE,
#' preconditions = ~ . %>% dplyr::filter(a < 10),
@@ -192,7 +211,7 @@
#' ```yaml
#' steps:
#' - col_vals_lt:
-#' columns: vars(a)
+#' columns: c(a)
#' value: 1.0
#' na_pass: true
#' preconditions: ~. %>% dplyr::filter(a < 10)
@@ -239,7 +258,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_vals_lt(columns = vars(c), value = 5) %>%
+#' col_vals_lt(columns = c, value = 5) %>%
#' interrogate()
#' ```
#'
@@ -261,7 +280,7 @@
#'
#' ```{r}
#' tbl %>%
-#' col_vals_lt(columns = vars(c), value = 5) %>%
+#' col_vals_lt(columns = c, value = 5) %>%
#' dplyr::pull(c)
#' ```
#'
@@ -271,7 +290,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_vals_lt(tbl, columns = vars(c), value = 5)
+#' expect_col_vals_lt(tbl, columns = c, value = 5)
#' ```
#'
#' ## D: Using the test function
@@ -280,7 +299,7 @@
#' us.
#'
#' ```{r}
-#' test_col_vals_lt(tbl, columns = vars(c), value = 5)
+#' test_col_vals_lt(tbl, columns = c, value = 5)
#' ```
#'
#' @family validation functions
@@ -309,13 +328,10 @@ col_vals_lt <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -333,7 +349,7 @@ col_vals_lt <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_lt(
- columns = columns,
+ columns = tidyselect::all_of(columns),
value = value,
na_pass = na_pass,
preconditions = preconditions,
@@ -374,6 +390,7 @@ col_vals_lt <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -395,7 +412,7 @@ col_vals_lt <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_lte.R b/R/col_vals_lte.R
index 56f14b4c2..a3440d649 100644
--- a/R/col_vals_lte.R
+++ b/R/col_vals_lte.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -73,12 +73,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names to `columns`, the result will be an
-#' expansion of validation steps to that number of column names (e.g.,
-#' `vars(col_a, col_b)` will result in the entry of two validation steps). Aside
-#' from column names in quotes and in `vars()`, **tidyselect** helper functions
-#' are available for specifying columns. They are: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -153,6 +158,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -177,7 +196,7 @@
#' ```r
#' agent %>%
#' col_vals_lte(
-#' columns = vars(a),
+#' columns = a,
#' value = 1,
#' na_pass = TRUE,
#' preconditions = ~ . %>% dplyr::filter(a < 10),
@@ -193,7 +212,7 @@
#' ```yaml
#' steps:
#' - col_vals_lte:
-#' columns: vars(a)
+#' columns: c(a)
#' value: 1.0
#' na_pass: true
#' preconditions: ~. %>% dplyr::filter(a < 10)
@@ -240,7 +259,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_vals_lte(columns = vars(c), value = 4) %>%
+#' col_vals_lte(columns = c, value = 4) %>%
#' interrogate()
#' ```
#'
@@ -262,7 +281,7 @@
#'
#' ```{r}
#' tbl %>%
-#' col_vals_lte(columns = vars(c), value = 4) %>%
+#' col_vals_lte(columns = c, value = 4) %>%
#' dplyr::pull(c)
#' ```
#'
@@ -272,7 +291,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_vals_lte(tbl, columns = vars(c), value = 4)
+#' expect_col_vals_lte(tbl, columns = c, value = 4)
#' ```
#'
#' ## D: Using the test function
@@ -281,7 +300,7 @@
#' us.
#'
#' ```{r}
-#' test_col_vals_lte(tbl, columns = vars(c), value = 4)
+#' test_col_vals_lte(tbl, columns = c, value = 4)
#' ```
#'
#' @family validation functions
@@ -310,13 +329,10 @@ col_vals_lte <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -334,7 +350,7 @@ col_vals_lte <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_lte(
- columns = columns,
+ columns = tidyselect::all_of(columns),
value = value,
na_pass = na_pass,
preconditions = preconditions,
@@ -375,6 +391,7 @@ col_vals_lte <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -396,7 +413,7 @@ col_vals_lte <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_make_set.R b/R/col_vals_make_set.R
index f6323ab52..ca0209e2f 100644
--- a/R/col_vals_make_set.R
+++ b/R/col_vals_make_set.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -73,12 +73,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Preconditions:
#'
@@ -146,6 +151,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -170,7 +189,7 @@
#' ```r
#' agent %>%
#' col_vals_make_set(
-#' columns = vars(a),
+#' columns = a,
#' set = c(1, 2, 3, 4),
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' segments = b ~ c("group_1", "group_2"),
@@ -185,7 +204,7 @@
#' ```yaml
#' steps:
#' - col_vals_make_set:
-#' columns: vars(a)
+#' columns: c(a)
#' set:
#' - 1.0
#' - 2.0
@@ -226,7 +245,7 @@
#' agent <-
#' create_agent(tbl = small_table) %>%
#' col_vals_make_set(
-#' columns = vars(f), set = c("low", "mid", "high")
+#' columns = f, set = c("low", "mid", "high")
#' ) %>%
#' interrogate()
#' ```
@@ -250,7 +269,7 @@
#' ```{r}
#' small_table %>%
#' col_vals_make_set(
-#' columns = vars(f), set = c("low", "mid", "high")
+#' columns = f, set = c("low", "mid", "high")
#' ) %>%
#' dplyr::pull(f) %>%
#' unique()
@@ -264,7 +283,7 @@
#' ```r
#' expect_col_vals_make_set(
#' small_table,
-#' columns = vars(f), set = c("low", "mid", "high")
+#' columns = f, set = c("low", "mid", "high")
#' )
#' ```
#'
@@ -276,7 +295,7 @@
#' ```{r}
#' small_table %>%
#' test_col_vals_make_set(
-#' columns = vars(f), set = c("low", "mid", "high")
+#' columns = f, set = c("low", "mid", "high")
#' )
#' ```
#'
@@ -303,13 +322,10 @@ col_vals_make_set <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -327,7 +343,7 @@ col_vals_make_set <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_make_set(
- columns = columns,
+ columns = tidyselect::all_of(columns),
set = set,
preconditions = preconditions,
segments = segments,
@@ -367,6 +383,7 @@ col_vals_make_set <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -387,7 +404,7 @@ col_vals_make_set <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_make_subset.R b/R/col_vals_make_subset.R
index e88fbe6d3..045affd87 100644
--- a/R/col_vals_make_subset.R
+++ b/R/col_vals_make_subset.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -69,12 +69,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Preconditions:
#'
@@ -142,6 +147,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -166,7 +185,7 @@
#' ```r
#' agent %>%
#' col_vals_make_subset(
-#' columns = vars(a),
+#' columns = a,
#' set = c(1, 2, 3, 4),
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' segments = b ~ c("group_1", "group_2"),
@@ -181,7 +200,7 @@
#' ```yaml
#' steps:
#' - col_vals_make_subset:
-#' columns: vars(a)
+#' columns: c(a)
#' set:
#' - 1.0
#' - 2.0
@@ -223,7 +242,7 @@
#' agent <-
#' create_agent(tbl = small_table) %>%
#' col_vals_make_subset(
-#' columns = vars(f), set = c("low", "high")
+#' columns = f, set = c("low", "high")
#' ) %>%
#' interrogate()
#' ```
@@ -247,7 +266,7 @@
#' ```{r}
#' small_table %>%
#' col_vals_make_subset(
-#' columns = vars(f), set = c("low", "high")
+#' columns = f, set = c("low", "high")
#' ) %>%
#' dplyr::pull(f) %>%
#' unique()
@@ -261,7 +280,7 @@
#' ```r
#' expect_col_vals_make_subset(
#' small_table,
-#' columns = vars(f), set = c("low", "high")
+#' columns = f, set = c("low", "high")
#' )
#' ```
#'
@@ -273,7 +292,7 @@
#' ```{r}
#' small_table %>%
#' test_col_vals_make_subset(
-#' columns = vars(f), set = c("low", "high")
+#' columns = f, set = c("low", "high")
#' )
#' ```
#'
@@ -300,13 +319,10 @@ col_vals_make_subset <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -324,7 +340,7 @@ col_vals_make_subset <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_make_subset(
- columns = columns,
+ columns = tidyselect::all_of(columns),
set = set,
preconditions = preconditions,
segments = segments,
@@ -364,6 +380,7 @@ col_vals_make_subset <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -384,7 +401,7 @@ col_vals_make_subset <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_not_between.R b/R/col_vals_not_between.R
index ccc12c229..1232882ca 100644
--- a/R/col_vals_not_between.R
+++ b/R/col_vals_not_between.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -96,12 +96,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names to `columns`, the result will be an
-#' expansion of validation steps to that number of column names (e.g.,
-#' `vars(col_a, col_b)` will result in the entry of two validation steps). Aside
-#' from column names in quotes and in `vars()`, **tidyselect** helper functions
-#' are available for specifying columns. They are: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -176,6 +181,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -200,7 +219,7 @@
#' ```r
#' agent %>%
#' col_vals_not_between(
-#' columns = vars(a),
+#' columns = a,
#' left = 1,
#' right = 2,
#' inclusive = c(TRUE, FALSE),
@@ -218,7 +237,7 @@
#' ```yaml
#' steps:
#' - col_vals_not_between:
-#' columns: vars(a)
+#' columns: c(a)
#' left: 1.0
#' right: 2.0
#' inclusive:
@@ -262,7 +281,7 @@
#' agent <-
#' create_agent(tbl = small_table) %>%
#' col_vals_not_between(
-#' columns = vars(c),
+#' columns = c,
#' left = 10, right = 20,
#' na_pass = TRUE
#' ) %>%
@@ -288,7 +307,7 @@
#' ```{r}
#' small_table %>%
#' col_vals_not_between(
-#' columns = vars(c),
+#' columns = c,
#' left = 10, right = 20,
#' na_pass = TRUE
#' ) %>%
@@ -302,7 +321,7 @@
#'
#' ```r
#' expect_col_vals_not_between(
-#' small_table, columns = vars(c),
+#' small_table, columns = c,
#' left = 10, right = 20,
#' na_pass = TRUE
#' )
@@ -316,7 +335,7 @@
#' ```{r}
#' small_table %>%
#' test_col_vals_not_between(
-#' columns = vars(c),
+#' columns = c,
#' left = 10, right = 20,
#' na_pass = TRUE
#' )
@@ -333,7 +352,7 @@
#' ```{r}
#' small_table %>%
#' test_col_vals_not_between(
-#' columns = vars(c),
+#' columns = c,
#' left = 9, right = 20,
#' inclusive = c(FALSE, TRUE),
#' na_pass = TRUE
@@ -368,13 +387,10 @@ col_vals_not_between <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -396,7 +412,7 @@ col_vals_not_between <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_not_between(
- columns = columns,
+ columns = tidyselect::all_of(columns),
left = left,
right = right,
inclusive = inclusive,
@@ -439,6 +455,7 @@ col_vals_not_between <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -460,7 +477,7 @@ col_vals_not_between <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_not_equal.R b/R/col_vals_not_equal.R
index 43ecef4c4..a07e1284d 100644
--- a/R/col_vals_not_equal.R
+++ b/R/col_vals_not_equal.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -70,12 +70,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -150,6 +155,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -174,7 +193,7 @@
#' ```r
#' agent %>%
#' col_vals_not_equal(
-#' columns = vars(a),
+#' columns = a,
#' value = 1,
#' na_pass = TRUE,
#' preconditions = ~ . %>% dplyr::filter(a < 10),
@@ -190,7 +209,7 @@
#' ```yaml
#' steps:
#' - col_vals_not_equal:
-#' columns: vars(a)
+#' columns: c(a)
#' value: 1.0
#' na_pass: true
#' preconditions: ~. %>% dplyr::filter(a < 10)
@@ -237,7 +256,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_vals_not_equal(columns = vars(a), value = 6) %>%
+#' col_vals_not_equal(columns = a, value = 6) %>%
#' interrogate()
#' ```
#'
@@ -259,7 +278,7 @@
#'
#' ```{r}
#' tbl %>%
-#' col_vals_not_equal(columns = vars(a), value = 6) %>%
+#' col_vals_not_equal(columns = a, value = 6) %>%
#' dplyr::pull(a)
#' ```
#'
@@ -269,7 +288,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_vals_not_equal(tbl, columns = vars(a), value = 6)
+#' expect_col_vals_not_equal(tbl, columns = a, value = 6)
#' ```
#'
#' ## D: Using the test function
@@ -278,7 +297,7 @@
#' us.
#'
#' ```{r}
-#' test_col_vals_not_equal(tbl, columns = vars(a), value = 6)
+#' test_col_vals_not_equal(tbl, columns = a, value = 6)
#' ```
#'
#' @family validation functions
@@ -307,13 +326,10 @@ col_vals_not_equal <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -331,7 +347,7 @@ col_vals_not_equal <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_not_equal(
- columns = columns,
+ columns = tidyselect::all_of(columns),
value = value,
na_pass = na_pass,
preconditions = preconditions,
@@ -372,6 +388,7 @@ col_vals_not_equal <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -393,7 +410,7 @@ col_vals_not_equal <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_not_in_set.R b/R/col_vals_not_in_set.R
index 6595770bf..a9d2c232e 100644
--- a/R/col_vals_not_in_set.R
+++ b/R/col_vals_not_in_set.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -69,12 +69,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Preconditions:
#'
@@ -142,6 +147,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -166,7 +185,7 @@
#' ```r
#' agent %>%
#' col_vals_not_in_set(
-#' columns = vars(a),
+#' columns = a,
#' set = c(1, 2, 3, 4),
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' segments = b ~ c("group_1", "group_2"),
@@ -181,7 +200,7 @@
#' ```yaml
#' steps:
#' - col_vals_not_in_set:
-#' columns: vars(a)
+#' columns: c(a)
#' set:
#' - 1.0
#' - 2.0
@@ -218,7 +237,7 @@
#' agent <-
#' create_agent(tbl = small_table) %>%
#' col_vals_not_in_set(
-#' columns = vars(f), set = c("lows", "mids", "highs")
+#' columns = f, set = c("lows", "mids", "highs")
#' ) %>%
#' interrogate()
#' ```
@@ -242,7 +261,7 @@
#' ```
#' small_table %>%
#' col_vals_not_in_set(
-#' columns = vars(f), set = c("lows", "mids", "highs")
+#' columns = f, set = c("lows", "mids", "highs")
#' ) %>%
#' dplyr::pull(f) %>%
#' unique()
@@ -256,7 +275,7 @@
#' ```r
#' expect_col_vals_not_in_set(
#' small_table,
-#' columns = vars(f), set = c("lows", "mids", "highs")
+#' columns = f, set = c("lows", "mids", "highs")
#' )
#' ```
#'
@@ -268,7 +287,7 @@
#' ```{r}
#' small_table %>%
#' test_col_vals_not_in_set(
-#' columns = vars(f), set = c("lows", "mids", "highs")
+#' columns = f, set = c("lows", "mids", "highs")
#' )
#' ```
#'
@@ -297,13 +316,10 @@ col_vals_not_in_set <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -321,7 +337,7 @@ col_vals_not_in_set <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_not_in_set(
- columns = columns,
+ columns = tidyselect::all_of(columns),
set = set,
preconditions = preconditions,
segments = segments,
@@ -361,6 +377,7 @@ col_vals_not_in_set <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -381,7 +398,7 @@ col_vals_not_in_set <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_not_null.R b/R/col_vals_not_null.R
index 4065aad83..d903a340a 100644
--- a/R/col_vals_not_null.R
+++ b/R/col_vals_not_null.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -63,12 +63,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Preconditions:
#'
@@ -136,6 +141,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -160,7 +179,7 @@
#' ```r
#' agent %>%
#' col_vals_not_null(
-#' columns = vars(a),
+#' columns = a,
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' segments = b ~ c("group_1", "group_2"),
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
@@ -174,7 +193,7 @@
#' ```yaml
#' steps:
#' - col_vals_not_null:
-#' columns: vars(a)
+#' columns: c(a)
#' preconditions: ~. %>% dplyr::filter(a < 10)
#' segments: b ~ c("group_1", "group_2")
#' actions:
@@ -218,7 +237,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_vals_not_null(columns = vars(b)) %>%
+#' col_vals_not_null(columns = b) %>%
#' interrogate()
#' ```
#'
@@ -240,7 +259,7 @@
#'
#' ```{r}
#' tbl %>%
-#' col_vals_not_null(columns = vars(b)) %>%
+#' col_vals_not_null(columns = b) %>%
#' dplyr::pull(b)
#' ```
#'
@@ -250,7 +269,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_vals_not_null(tbl, columns = vars(b))
+#' expect_col_vals_not_null(tbl, columns = b)
#' ```
#'
#' ## D: Using the test function
@@ -259,7 +278,7 @@
#' us.
#'
#' ```{r}
-#' tbl %>% test_col_vals_not_null(columns = vars(b))
+#' tbl %>% test_col_vals_not_null(columns = b)
#' ```
#'
#' @family validation functions
@@ -288,13 +307,10 @@ col_vals_not_null <- function(
values <- NULL
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -312,7 +328,7 @@ col_vals_not_null <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_not_null(
- columns = columns,
+ columns = tidyselect::all_of(columns),
preconditions = preconditions,
segments = segments,
label = label,
@@ -351,6 +367,7 @@ col_vals_not_null <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -370,7 +387,7 @@ col_vals_not_null <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_null.R b/R/col_vals_null.R
index 258a436c7..167981165 100644
--- a/R/col_vals_null.R
+++ b/R/col_vals_null.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -62,12 +62,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Preconditions:
#'
@@ -135,6 +140,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -159,7 +178,7 @@
#' ```r
#' agent %>%
#' col_vals_null(
-#' columns = vars(a),
+#' columns = a,
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' segments = b ~ c("group_1", "group_2"),
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
@@ -173,7 +192,7 @@
#' ```yaml
#' steps:
#' - col_vals_null:
-#' columns: vars(a)
+#' columns: c(a)
#' preconditions: ~. %>% dplyr::filter(a < 10)
#' segments: b ~ c("group_1", "group_2")
#' actions:
@@ -217,7 +236,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' col_vals_null(columns = vars(c)) %>%
+#' col_vals_null(columns = c) %>%
#' interrogate()
#' ```
#'
@@ -239,7 +258,7 @@
#'
#' ```{r}
#' tbl %>%
-#' col_vals_null(columns = vars(c)) %>%
+#' col_vals_null(columns = c) %>%
#' dplyr::pull(c)
#' ```
#'
@@ -249,7 +268,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_vals_null(tbl, columns = vars(c))
+#' expect_col_vals_null(tbl, columns = c)
#' ```
#'
#' ## D: Using the test function
@@ -258,7 +277,7 @@
#' us.
#'
#' ```{r}
-#' tbl %>% test_col_vals_null(columns = vars(c))
+#' tbl %>% test_col_vals_null(columns = c)
#' ```
#'
#' @family validation functions
@@ -287,13 +306,10 @@ col_vals_null <- function(
values <- NULL
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -311,7 +327,7 @@ col_vals_null <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_null(
- columns = columns,
+ columns = tidyselect::all_of(columns),
preconditions = preconditions,
segments = segments,
label = label,
@@ -350,6 +366,7 @@ col_vals_null <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -369,7 +386,7 @@ col_vals_null <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_regex.R b/R/col_vals_regex.R
index 80a567388..d9350f468 100644
--- a/R/col_vals_regex.R
+++ b/R/col_vals_regex.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -69,12 +69,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -149,6 +154,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -173,7 +192,7 @@
#' ```
#' agent %>%
#' col_vals_regex(
-#' columns = vars(a),
+#' columns = a,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}",
#' na_pass = TRUE,
#' preconditions = ~ . %>% dplyr::filter(a < 10),
@@ -189,7 +208,7 @@
#' ```yaml
#' steps:
#' - col_vals_regex:
-#' columns: vars(a)
+#' columns: c(a)
#' regex: '[0-9]-[a-z]{3}-[0-9]{3}'
#' na_pass: true
#' preconditions: ~. %>% dplyr::filter(a < 10)
@@ -233,7 +252,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = small_table) %>%
-#' col_vals_regex(columns = vars(b), regex = pattern) %>%
+#' col_vals_regex(columns = b, regex = pattern) %>%
#' interrogate()
#' ```
#'
@@ -255,7 +274,7 @@
#'
#' ```{r}
#' small_table %>%
-#' col_vals_regex(columns = vars(b), regex = pattern) %>%
+#' col_vals_regex(columns = b, regex = pattern) %>%
#' dplyr::slice(1:5)
#' ```
#'
@@ -265,7 +284,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_col_vals_regex(small_table, columns = vars(b), regex = pattern)
+#' expect_col_vals_regex(small_table, columns = b, regex = pattern)
#' ```
#'
#' ## D: Using the test function
@@ -274,7 +293,7 @@
#' us.
#'
#' ```{r}
-#' small_table %>% test_col_vals_regex(columns = vars(b), regex = pattern)
+#' small_table %>% test_col_vals_regex(columns = b, regex = pattern)
#' ```
#'
#' @family validation functions
@@ -301,13 +320,10 @@ col_vals_regex <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -325,7 +341,7 @@ col_vals_regex <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_regex(
- columns = columns,
+ columns = tidyselect::all_of(columns),
regex = regex,
na_pass = na_pass,
preconditions = preconditions,
@@ -366,6 +382,7 @@ col_vals_regex <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -387,7 +404,7 @@ col_vals_regex <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/col_vals_within_spec.R b/R/col_vals_within_spec.R
index e72167f82..3e815b418 100644
--- a/R/col_vals_within_spec.R
+++ b/R/col_vals_within_spec.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -119,12 +119,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names, the result will be an expansion of
-#' validation steps to that number of column names (e.g., `vars(col_a, col_b)`
-#' will result in the entry of two validation steps). Aside from column names in
-#' quotes and in `vars()`, **tidyselect** helper functions are available for
-#' specifying columns. They are: `starts_with()`, `ends_with()`, `contains()`,
-#' `matches()`, and `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Missing Values:
#'
@@ -199,6 +204,20 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -223,7 +242,7 @@
#' ```r
#' agent %>%
#' col_vals_within_spec(
-#' columns = vars(a),
+#' columns = a,
#' spec = "email",
#' na_pass = TRUE,
#' preconditions = ~ . %>% dplyr::filter(b < 10),
@@ -239,7 +258,7 @@
#' ```yaml
#' steps:
#' - col_vals_within_spec:
-#' columns: vars(a)
+#' columns: c(a)
#' spec: email
#' na_pass: true
#' preconditions: ~. %>% dplyr::filter(b < 10)
@@ -282,7 +301,7 @@
#' agent <-
#' create_agent(tbl = spec_slice) %>%
#' col_vals_within_spec(
-#' columns = vars(email_addresses),
+#' columns = email_addresses,
#' spec = "email"
#' ) %>%
#' interrogate()
@@ -307,7 +326,7 @@
#' ```{r}
#' spec_slice %>%
#' col_vals_within_spec(
-#' columns = vars(email_addresses),
+#' columns = email_addresses,
#' spec = "email"
#' ) %>%
#' dplyr::select(email_addresses)
@@ -321,7 +340,7 @@
#' ```r
#' expect_col_vals_within_spec(
#' spec_slice,
-#' columns = vars(email_addresses),
+#' columns = email_addresses,
#' spec = "email"
#' )
#' ```
@@ -334,7 +353,7 @@
#' ```{r}
#' spec_slice %>%
#' test_col_vals_within_spec(
-#' columns = vars(email_addresses),
+#' columns = email_addresses,
#' spec = "email"
#' )
#' ```
@@ -363,13 +382,10 @@ col_vals_within_spec <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
# Resolve the columns based on the expression
columns <- resolve_columns(x = x, var_expr = columns, preconditions)
@@ -390,7 +406,7 @@ col_vals_within_spec <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
col_vals_within_spec(
- columns = columns,
+ columns = tidyselect::all_of(columns),
spec = spec,
na_pass = na_pass,
preconditions = preconditions,
@@ -431,6 +447,7 @@ col_vals_within_spec <- function(
# Add one or more validation steps based on the
# length of the `columns` variable
+ label <- resolve_label(label, columns, segments_list)
for (i in seq_along(columns)) {
for (j in seq_along(segments_list)) {
@@ -452,7 +469,7 @@ col_vals_within_spec <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id[i],
- label = label,
+ label = label[[i, j]],
brief = brief[i],
active = active
)
diff --git a/R/column_roles.R b/R/column_roles.R
index 6d119d72a..a6b234d25 100644
--- a/R/column_roles.R
+++ b/R/column_roles.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -805,7 +805,7 @@ get_column_role_character <- function(data_column) {
}
- return("string")
+ "string"
}
get_column_role_numeric <- function(data_column) {
@@ -864,7 +864,7 @@ get_column_role_numeric <- function(data_column) {
return(paste0(role, "numeric.continuous"))
}
- return(paste0(role, "numeric"))
+ paste0(role, "numeric")
}
strptime_8601_formats <-
diff --git a/R/conjointly.R b/R/conjointly.R
index d428bc3cd..4e4078431 100644
--- a/R/conjointly.R
+++ b/R/conjointly.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -54,7 +54,7 @@
#' A collection one-sided formulas that consist of validation functions that
#' validate row units (the `col_vals_*()` series), column existence
#' ([col_exists()]), or column type (the `col_is_*()` series). An example of
-#' this is `~ col_vals_gte(., vars(a), 5.5), ~ col_vals_not_null(., vars(b)`).
+#' this is `~ col_vals_gte(., a, 5.5), ~ col_vals_not_null(., b`).
#'
#' @param .list *Alternative to `...`*
#'
@@ -89,12 +89,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names in any of the supplied validation steps,
-#' the result will be an expansion of sub-validation steps to that number of
-#' column names. Aside from column names in quotes and in `vars()`,
-#' **tidyselect** helper functions are available for specifying columns. They
-#' are: `starts_with()`, `ends_with()`, `contains()`, `matches()`, and
-#' `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Preconditions:
#'
@@ -162,6 +167,19 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -186,9 +204,9 @@
#' ```r
#' agent %>%
#' conjointly(
-#' ~ col_vals_lt(., columns = vars(a), value = 8),
-#' ~ col_vals_gt(., columns = vars(c), value = vars(a)),
-#' ~ col_vals_not_null(., columns = vars(b)),
+#' ~ col_vals_lt(., columns = a, value = 8),
+#' ~ col_vals_gt(., columns = c, value = vars(a)),
+#' ~ col_vals_not_null(., columns = b),
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' segments = b ~ c("group_1", "group_2"),
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
@@ -203,9 +221,9 @@
#' steps:
#' - conjointly:
#' fns:
-#' - ~col_vals_lt(., columns = vars(a), value = 8)
-#' - ~col_vals_gt(., columns = vars(c), value = vars(a))
-#' - ~col_vals_not_null(., columns = vars(b))
+#' - ~col_vals_lt(., columns = a, value = 8)
+#' - ~col_vals_gt(., columns = c, value = vars(a))
+#' - ~col_vals_not_null(., columns = b)
#' preconditions: ~. %>% dplyr::filter(a < 10)
#' segments: b ~ c("group_1", "group_2")
#' actions:
@@ -252,9 +270,9 @@
#' agent <-
#' create_agent(tbl = tbl) %>%
#' conjointly(
-#' ~ col_vals_lt(., columns = vars(a), value = 8),
-#' ~ col_vals_gt(., columns = vars(c), value = vars(a)),
-#' ~ col_vals_not_null(., columns = vars(b))
+#' ~ col_vals_lt(., columns = a, value = 8),
+#' ~ col_vals_gt(., columns = c, value = vars(a)),
+#' ~ col_vals_not_null(., columns = b)
#' ) %>%
#' interrogate()
#' ```
@@ -283,9 +301,9 @@
#' ```{r}
#' tbl %>%
#' conjointly(
-#' ~ col_vals_lt(., columns = vars(a), value = 8),
-#' ~ col_vals_gt(., columns = vars(c), value = vars(a)),
-#' ~ col_vals_not_null(., columns = vars(b))
+#' ~ col_vals_lt(., columns = a, value = 8),
+#' ~ col_vals_gt(., columns = c, value = vars(a)),
+#' ~ col_vals_not_null(., columns = b)
#' )
#' ```
#'
@@ -297,9 +315,9 @@
#' ```r
#' expect_conjointly(
#' tbl,
-#' ~ col_vals_lt(., columns = vars(a), value = 8),
-#' ~ col_vals_gt(., columns = vars(c), value = vars(a)),
-#' ~ col_vals_not_null(., columns = vars(b))
+#' ~ col_vals_lt(., columns = a, value = 8),
+#' ~ col_vals_gt(., columns = c, value = vars(a)),
+#' ~ col_vals_not_null(., columns = b)
#' )
#' ```
#'
@@ -311,9 +329,9 @@
#' ```{r}
#' tbl %>%
#' test_conjointly(
-#' ~ col_vals_lt(., columns = vars(a), value = 8),
-#' ~ col_vals_gt(., columns = vars(c), value = vars(a)),
-#' ~ col_vals_not_null(., columns = vars(b))
+#' ~ col_vals_lt(., columns = a, value = 8),
+#' ~ col_vals_gt(., columns = c, value = vars(a)),
+#' ~ col_vals_not_null(., columns = b)
#' )
#' ```
#'
@@ -406,6 +424,7 @@ conjointly <- function(
# Add one or more validation steps based on the
# length of `segments_list`
+ label <- resolve_label(label, segments = segments_list)
for (i in seq_along(segments_list)) {
seg_col <- names(segments_list[i])
@@ -426,7 +445,7 @@ conjointly <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id,
- label = label,
+ label = label[[i]],
brief = brief,
active = active
)
diff --git a/R/create_agent.R b/R/create_agent.R
index 2caed19f3..f2ac0e0b2 100644
--- a/R/create_agent.R
+++ b/R/create_agent.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -44,15 +44,15 @@
#'
#' @param tbl *Table or expression for reading in one*
#'
-#' `obj:|` // **required**
+#' `obj:|` // **required**
#'
#' The input table. This can be a data frame, a tibble, a `tbl_dbi` object, or
#' a `tbl_spark` object. Alternatively, an expression can be supplied to serve
#' as instructions on how to retrieve the target table at interrogation-time.
#' There are two ways to specify an association to a target table: (1) as a
#' table-prep formula, which is a right-hand side (RHS) formula expression
-#' (e.g., `~ { }`), or (2) as a function (e.g.,
-#' `function() { }`).
+#' (e.g., `~ { }`), or (2) as a function (e.g.,
+#' `function() { }`).
#'
#' @param tbl_name *A table name*
#'
@@ -394,16 +394,16 @@
#' ```r
#' agent <-
#' agent %>%
-#' col_exists(columns = vars(date, date_time)) %>%
+#' col_exists(columns = date, date_time) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}"
#' ) %>%
#' rows_distinct() %>%
-#' col_vals_gt(columns = vars(d), value = 100) %>%
-#' col_vals_lte(columns = vars(c), value = 5) %>%
+#' col_vals_gt(columns = d, value = 100) %>%
+#' col_vals_lte(columns = c, value = 5) %>%
#' col_vals_between(
-#' columns = vars(c),
+#' columns = c,
#' left = vars(a), right = vars(d),
#' na_pass = TRUE
#' ) %>%
diff --git a/R/create_informant.R b/R/create_informant.R
index b7f7b990d..8482ee288 100644
--- a/R/create_informant.R
+++ b/R/create_informant.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -55,15 +55,15 @@
#'
#' @param tbl *Table or expression for reading in one*
#'
-#' `obj:|` // **required**
+#' `obj:|` // **required**
#'
#' The input table. This can be a data frame, a tibble, a `tbl_dbi` object, or
#' a `tbl_spark` object. Alternatively, an expression can be supplied to serve
#' as instructions on how to retrieve the target table at incorporation-time.
#' There are two ways to specify an association to a target table: (1) as a
#' table-prep formula, which is a right-hand side (RHS) formula expression
-#' (e.g., `~ { }`), or (2) as a function (e.g.,
-#' `function() { }`).
+#' (e.g., `~ { }`), or (2) as a function (e.g.,
+#' `function() { }`).
#'
#' @param agent *The pointblank agent object*
#'
@@ -399,6 +399,10 @@ create_informant <- function(
}
}
+ private <- list(
+ col_ptypes = tbl_info$col_ptypes
+ )
+
metadata_list <-
c(
list(
@@ -409,7 +413,8 @@ create_informant <- function(
`_type` = table_type
)
),
- column_list
+ column_list,
+ list(`_private` = private)
)
# Create the metadata list object
diff --git a/R/create_multiagent.R b/R/create_multiagent.R
index a2c225118..dfe1101b5 100644
--- a/R/create_multiagent.R
+++ b/R/create_multiagent.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -107,7 +107,7 @@
#' tbl_name = "tbl_1",
#' label = "Example table 1."
#' ) %>%
-#' col_vals_gt(columns = vars(a), value = 4) %>%
+#' col_vals_gt(columns = a, value = 4) %>%
#' interrogate()
#' ```
#'
@@ -120,7 +120,7 @@
#' tbl_name = "tbl_2",
#' label = "Example table 2."
#' ) %>%
-#' col_is_character(columns = vars(b)) %>%
+#' col_is_character(columns = b) %>%
#' interrogate()
#' ```
#'
@@ -159,19 +159,17 @@ create_multiagent <- function(
locale = NULL
) {
- agent_list <- list(...)
-
+ agent_list <- rlang::list2(...)
+ if (!all(sapply(agent_list, is_ptblank_agent))) {
+ rlang::abort("All components of `...` must be an agent")
+ }
+ agent_list <- rehash_agent_list(agent_list)
agent_list <-
lapply(
agent_list,
FUN = function(agent) {
-
- # TODO: Ensure that each `agent` in `agent_list` is
- # actually an agent with `is_ptblank_agent()`
-
class(agent) <-
c(setdiff(class(agent), "ptblank_agent"), "ptblank_agent_i")
-
agent
}
)
@@ -185,3 +183,50 @@ create_multiagent <- function(
class(agent_series) <- "ptblank_multiagent"
agent_series
}
+
+rehash_agent_list <- function(agent_list) {
+
+ hash_versions <- lapply(agent_list, function(x) {
+ gsub("^.*(-|$)", "", x$validation_set$sha1)
+ })
+ hash_versions <- unique(unlist(hash_versions))
+
+ # agents using any of these hash versions are rehashed
+ to_rehash <- c("")
+
+ if (any(to_rehash %in% hash_versions) || length(hash_versions) > 1) {
+ lapply(agent_list, rehash_agent)
+ } else {
+ agent_list
+ }
+
+}
+
+rehash_agent <- function(agent) {
+
+ cur_hash_version <- get_hash_version()
+ vs <- agent$validation_set
+
+ new_hash <- sapply(seq_len(nrow(vs)), function(i) {
+ step <- vs[i, ]
+ hash <- step$sha1
+ hash_version <- gsub("^.*(-|$)", "", hash)
+ if (hash_version != cur_hash_version) {
+ # Rehash from validation set, extracting from list-column where necessary
+ hash <- hash_validation_step(
+ assertion_type = step$assertion_type,
+ column = step$column[[1]],
+ values = step$values[[1]],
+ na_pass = step$na_pass,
+ preconditions = step$preconditions[[1]],
+ seg_col = step$seg_col,
+ seg_val = step$seg_val
+ )
+ }
+ hash
+ })
+
+ agent$validation_set$sha1 <- new_hash
+ agent
+
+}
diff --git a/R/datasets.R b/R/datasets.R
index 2770d07f6..665cbb1ff 100644
--- a/R/datasets.R
+++ b/R/datasets.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -73,18 +73,10 @@
small_table_sqlite <- function() {
# nocov start
-
- if (!requireNamespace("DBI", quietly = TRUE) &&
- !requireNamespace("RSQLite", quietly = TRUE)) {
-
- stop(
- "Creating the SQLite table object requires both the DBI and RSQLite ",
- "packages:\n",
- "* Install them with `install.packages(\"DBI\")` and ",
- "`install.packages(\"RSQLite\")`.",
- call. = FALSE
- )
- }
+ rlang::check_installed(
+ c("DBI", "RSQLite"),
+ "to create an SQLite table object."
+ )
con <-
DBI::dbConnect(
diff --git a/R/draft_validation.R b/R/draft_validation.R
index 7a50189c1..1c65e6f51 100644
--- a/R/draft_validation.R
+++ b/R/draft_validation.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -154,116 +154,116 @@
#' ) %>%
#' # Expect that column `name` is of type: character
#' col_is_character(
-#' columns = vars(name)
+#' columns = name
#' ) %>%
#' # Expect that column `year` is of type: numeric
#' col_is_numeric(
-#' columns = vars(year)
+#' columns = year
#' ) %>%
#' # Expect that values in `year` should be between `1975` and `2020`
#' col_vals_between(
-#' columns = vars(year),
+#' columns = year,
#' left = 1975,
#' right = 2020
#' ) %>%
#' # Expect that column `month` is of type: numeric
#' col_is_numeric(
-#' columns = vars(month)
+#' columns = month
#' ) %>%
#' # Expect that values in `month` should be between `1` and `12`
#' col_vals_between(
-#' columns = vars(month),
+#' columns = month,
#' left = 1,
#' right = 12
#' ) %>%
#' # Expect that column `day` is of type: integer
#' col_is_integer(
-#' columns = vars(day)
+#' columns = day
#' ) %>%
#' # Expect that values in `day` should be between `1` and `31`
#' col_vals_between(
-#' columns = vars(day),
+#' columns = day,
#' left = 1,
#' right = 31
#' ) %>%
#' # Expect that column `hour` is of type: numeric
#' col_is_numeric(
-#' columns = vars(hour)
+#' columns = hour
#' ) %>%
#' # Expect that values in `hour` should be between `0` and `23`
#' col_vals_between(
-#' columns = vars(hour),
+#' columns = hour,
#' left = 0,
#' right = 23
#' ) %>%
#' # Expect that column `lat` is of type: numeric
#' col_is_numeric(
-#' columns = vars(lat)
+#' columns = lat
#' ) %>%
#' # Expect that values in `lat` should be between `-90` and `90`
#' col_vals_between(
-#' columns = vars(lat),
+#' columns = lat,
#' left = -90,
#' right = 90
#' ) %>%
#' # Expect that column `long` is of type: numeric
#' col_is_numeric(
-#' columns = vars(long)
+#' columns = long
#' ) %>%
#' # Expect that values in `long` should be between `-180` and `180`
#' col_vals_between(
-#' columns = vars(long),
+#' columns = long,
#' left = -180,
#' right = 180
#' ) %>%
#' # Expect that column `status` is of type: character
#' col_is_character(
-#' columns = vars(status)
+#' columns = status
#' ) %>%
#' # Expect that column `category` is of type: factor
#' col_is_factor(
-#' columns = vars(category)
+#' columns = category
#' ) %>%
#' # Expect that column `wind` is of type: integer
#' col_is_integer(
-#' columns = vars(wind)
+#' columns = wind
#' ) %>%
#' # Expect that values in `wind` should be between `10` and `160`
#' col_vals_between(
-#' columns = vars(wind),
+#' columns = wind,
#' left = 10,
#' right = 160
#' ) %>%
#' # Expect that column `pressure` is of type: integer
#' col_is_integer(
-#' columns = vars(pressure)
+#' columns = pressure
#' ) %>%
#' # Expect that values in `pressure` should be between `882` and `1022`
#' col_vals_between(
-#' columns = vars(pressure),
+#' columns = pressure,
#' left = 882,
#' right = 1022
#' ) %>%
#' # Expect that column `tropicalstorm_force_diameter` is of type: integer
#' col_is_integer(
-#' columns = vars(tropicalstorm_force_diameter)
+#' columns = tropicalstorm_force_diameter
#' ) %>%
#' # Expect that values in `tropicalstorm_force_diameter` should be between
#' # `0` and `870`
#' col_vals_between(
-#' columns = vars(tropicalstorm_force_diameter),
+#' columns = tropicalstorm_force_diameter,
#' left = 0,
#' right = 870,
#' na_pass = TRUE
#' ) %>%
#' # Expect that column `hurricane_force_diameter` is of type: integer
#' col_is_integer(
-#' columns = vars(hurricane_force_diameter)
+#' columns = hurricane_force_diameter
#' ) %>%
#' # Expect that values in `hurricane_force_diameter` should be between
#' # `0` and `300`
#' col_vals_between(
-#' columns = vars(hurricane_force_diameter),
+#' columns = hurricane_force_diameter,
#' left = 0,
#' right = 300,
#' na_pass = TRUE
diff --git a/R/emailing.R b/R/emailing.R
index 0f9399a0e..182e4f910 100644
--- a/R/emailing.R
+++ b/R/emailing.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -93,8 +93,8 @@
#' )
#' )
#' ) %>%
-#' col_vals_gt(vars(a), 1) %>%
-#' col_vals_lt(vars(a), 7)
+#' col_vals_gt(a, 1) %>%
+#' col_vals_lt(a, 7)
#' ```
#'
#' YAML representation:
@@ -116,10 +116,10 @@
#' embed_report: true
#' steps:
#' - col_vals_gt:
-#' columns: vars(a)
+#' columns: c(a)
#' value: 1.0
#' - col_vals_lt:
-#' columns: vars(a)
+#' columns: c(a)
#' value: 7.0
#' ```
#'
@@ -176,8 +176,8 @@
#' )
#' )
#' ) %>%
-#' col_vals_gt(vars(a), value = 1) %>%
-#' col_vals_lt(vars(a), value = 7) %>%
+#' col_vals_gt(a, value = 1) %>%
+#' col_vals_lt(a, value = 7) %>%
#' interrogate()
#' ```
#'
@@ -294,8 +294,8 @@ email_blast <- function(
#' label = "An example.",
#' actions = al
#' ) %>%
-#' col_vals_gt(vars(a), value = 1) %>%
-#' col_vals_lt(vars(a), value = 7) %>%
+#' col_vals_gt(a, value = 1) %>%
+#' col_vals_lt(a, value = 7) %>%
#' interrogate() %>%
#' email_create()
#'
diff --git a/R/file_naming.R b/R/file_naming.R
index 4f5f07994..f27d57a1a 100644
--- a/R/file_naming.R
+++ b/R/file_naming.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/get_agent_report.R b/R/get_agent_report.R
index a4b247bfe..6af117258 100644
--- a/R/get_agent_report.R
+++ b/R/get_agent_report.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -210,7 +210,7 @@
#' tbl_name = "small_table",
#' label = "An example."
#' ) %>%
-#' col_vals_gt(columns = vars(a), value = 4) %>%
+#' col_vals_gt(columns = a, value = 4) %>%
#' interrogate()
#' ```
#'
@@ -333,11 +333,11 @@ get_agent_report <- function(
FUN.VALUE = character(1),
USE.NAMES = FALSE,
FUN = function(x) {
- ifelse(
- is.null(x),
- NA_character_,
- unlist(x)
- )
+ if (is.null(x)) {
+ NA_character_
+ } else {
+ toString(unique(x))
+ }
}
)
@@ -448,7 +448,8 @@ get_agent_report <- function(
# nocov start
- validation_set <- validation_set[report_tbl$i, ]
+ validation_set <- validation_set %>%
+ dplyr::filter(.data$i %in% report_tbl$i)
eval <- eval[report_tbl$i]
extracts <-
agent$extracts[
@@ -510,7 +511,8 @@ get_agent_report <- function(
htmltools::HTML(agent_label_styled),
htmltools::tags$div(
style = htmltools::css(
- height = "25px"
+ height = "25px",
+ `padding-top` = "10px"
),
htmltools::HTML(paste0(table_type, action_levels))
)
@@ -751,16 +753,42 @@ get_agent_report <- function(
}
}
- if (
- is.null(column_i) |
- (is.list(column_i) && is.na(unlist(column_i)))
- ) {
-
- NA_character_
-
- } else if (is.na(column_i)) {
-
- NA_character_
+ # If column missing
+ if (is.null(column_i) || identical(unlist(column_i), NA_character_)) {
+
+ columns_expr <- validation_set$columns_expr[[x]]
+ not_interrogated <- is.na(validation_set$eval_error[[x]])
+ eval_error <- isTRUE(validation_set$eval_error[[x]])
+
+ # If column selection attempted AND:
+ # - in validation planning, OR
+ # - the evaluation errors, OR
+ # - is a col_exists() step
+ columns_expr_exists <- !is.na(columns_expr) && columns_expr != "NULL"
+ show_column_expr <- columns_expr_exists &&
+ (not_interrogated || eval_error || assertion_str == "col_exists")
+ # Then display the original column selection expression for debugging
+ if (show_column_expr) {
+ as.character(
+ htmltools::tags$p(
+ title = columns_expr,
+ style = htmltools::css(
+ `margin-top` = "0",
+ `margin-bottom` = "0",
+ `font-family` = "monospace",
+ `font-size` = "10px",
+ `white-space` = "nowrap",
+ `text-overflow` = "ellipsis",
+ overflow = "hidden",
+ color = if (eval_error) "firebrick",
+ `font-face` = "maroon"
+ ),
+ columns_expr
+ )
+ )
+ } else {
+ NA_character_
+ }
} else {
@@ -1160,15 +1188,18 @@ get_agent_report <- function(
NA_character_
} else {
-
+
text <-
- values_i %>%
- tidy_gsub(
- "~",
- "▮"
- ) %>%
- unname()
-
+ unname(
+ tidy_gsub(
+ values_i,
+ "~",
+ "▮"
+ )
+ )
+
+ text <- gsub("$", "$", values_i, fixed = TRUE)
+
text <- paste(text, collapse = ", ")
if (size == "small") {
@@ -1302,6 +1333,16 @@ get_agent_report <- function(
FUN.VALUE = character(1),
USE.NAMES = FALSE,
FUN = function(x) {
+
+ # Reformat error/warning to string
+ msg_error <- pointblank_cnd_to_string(
+ cnd = agent$validation_set$capture_stack[[x]]$error,
+ pb_call = agent$validation_set$capture_stack[[x]]$pb_call
+ )
+ msg_warning <- pointblank_cnd_to_string(
+ cnd = agent$validation_set$capture_stack[[x]]$warning,
+ pb_call = agent$validation_set$capture_stack[[x]]$pb_call
+ )
if (is.na(eval[x])) {
@@ -1325,7 +1366,7 @@ get_agent_report <- function(
text <-
htmltools::htmlEscape(
- agent$validation_set$capture_stack[[x]]$error %>%
+ msg_error %>%
tidy_gsub("\"", "'")
)
@@ -1351,7 +1392,7 @@ get_agent_report <- function(
text <-
htmltools::htmlEscape(
- agent$validation_set$capture_stack[[x]]$warning %>%
+ msg_warning %>%
tidy_gsub("\"", "'")
)
@@ -1377,7 +1418,7 @@ get_agent_report <- function(
text <-
htmltools::htmlEscape(
- agent$validation_set$capture_stack[[x]]$error %>%
+ msg_error %>%
tidy_gsub("\"", "'")
)
@@ -1870,9 +1911,7 @@ get_agent_report <- function(
agent_report <-
agent_report %>%
gt::tab_header(
- title = get_lsv(text = c(
- "agent_report", "pointblank_validation_title_text"
- ))[[lang]],
+ title = title_text,
subtitle = gt::md(
paste0(agent_label_styled, " ", table_type, "
")
)
@@ -1926,6 +1965,7 @@ get_agent_report <- function(
}
#pb_agent code {
font-family: 'IBM Plex Mono', monospace, courier;
+ color: black;
background-color: transparent;
padding: 0;
}
@@ -1940,11 +1980,15 @@ get_agent_report <- function(
# nocov end
+ # Quarto rendering workaround
+ if (check_quarto()) {
+ agent_report <- gt::fmt(agent_report, fns = identity)
+ }
+
agent_report
}
-get_default_title_text <- function(report_type,
- lang) {
+get_default_title_text <- function(report_type, lang) {
if (report_type == "informant") {
title_text <-
@@ -2421,3 +2465,17 @@ store_footnote <- function(
)
)
}
+
+# Function for formatting error in `$capture_stack`
+pointblank_cnd_to_string <- function(cnd, pb_call) {
+ if (is.null(cnd)) return(character(0))
+ # Reformatting not yet implemented for warnings
+ if (rlang::is_warning(cnd)) return(cnd)
+ # Reconstruct trimmed down error and rethrow without cli
+ new <- rlang::error_cnd(
+ call = rlang::call2(":::", quote(pointblank), pb_call[1]),
+ message = cnd$parent$message %||% cnd$message,
+ use_cli_format = FALSE
+ )
+ as.character(try(rlang::cnd_signal(new), silent = TRUE))
+}
diff --git a/R/get_agent_x_list.R b/R/get_agent_x_list.R
index 5f4fe1a44..23edac9d2 100644
--- a/R/get_agent_x_list.R
+++ b/R/get_agent_x_list.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -145,8 +145,8 @@
#' tbl = tbl,
#' actions = al
#' ) %>%
-#' col_vals_gt(columns = vars(a), value = 7) %>%
-#' col_is_numeric(columns = vars(a)) %>%
+#' col_vals_gt(columns = a, value = 7) %>%
+#' col_is_numeric(columns = a) %>%
#' interrogate()
#' ```
#'
diff --git a/R/get_data_extracts.R b/R/get_data_extracts.R
index d1ce1bc39..745e6b4bc 100644
--- a/R/get_data_extracts.R
+++ b/R/get_data_extracts.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -77,9 +77,9 @@
#' dplyr::select(a:f),
#' label = "`get_data_extracts()`"
#' ) %>%
-#' col_vals_gt(vars(d), value = 1000) %>%
+#' col_vals_gt(d, value = 1000) %>%
#' col_vals_between(
-#' columns = vars(c),
+#' columns = c,
#' left = vars(a), right = vars(d),
#' na_pass = TRUE
#' ) %>%
diff --git a/R/get_informant_report.R b/R/get_informant_report.R
index 0fbd42675..675d5d238 100644
--- a/R/get_informant_report.R
+++ b/R/get_informant_report.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -139,6 +139,8 @@ get_informant_report <- function(
y <- informant$metadata_rev
} else {
y <- informant$metadata
+ # Hide private metadata from report
+ y[["_private"]] <- NULL
}
if ("info_label" %in% names(informant)) {
@@ -676,6 +678,11 @@ get_informant_report <- function(
# nocov end
+ # Quarto rendering workaround
+ if (check_quarto()) {
+ gt_informant_report <- gt::fmt(gt_informant_report, fns = identity)
+ }
+
gt_informant_report
}
diff --git a/R/get_multiagent_report.R b/R/get_multiagent_report.R
index eee09f8f9..8ed4d28c9 100644
--- a/R/get_multiagent_report.R
+++ b/R/get_multiagent_report.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -146,32 +146,32 @@
#' actions = al
#' ) %>%
#' col_vals_gt(
-#' columns = vars(date_time),
+#' columns = date_time,
#' value = vars(date),
#' na_pass = TRUE
#' ) %>%
#' col_vals_gt(
-#' columns = vars(b),
+#' columns = b,
#' value = vars(g),
#' na_pass = TRUE
#' ) %>%
#' rows_distinct() %>%
#' col_vals_equal(
-#' columns = vars(d),
+#' columns = d,
#' value = vars(d),
#' na_pass = TRUE
#' ) %>%
#' col_vals_between(
-#' columns = vars(c),
+#' columns = c,
#' left = vars(a), right = vars(d)
#' ) %>%
#' col_vals_not_between(
-#' columns = vars(c),
+#' columns = c,
#' left = 10, right = 20,
#' na_pass = TRUE
#' ) %>%
-#' rows_distinct(columns = vars(d, e, f)) %>%
-#' col_is_integer(columns = vars(a)) %>%
+#' rows_distinct(columns = d, e, f) %>%
+#' col_is_integer(columns = a) %>%
#' interrogate()
#' ```
#'
@@ -181,9 +181,9 @@
#' ```r
#' agent_2 <-
#' agent_1 %>%
-#' col_exists(columns = vars(date, date_time)) %>%
+#' col_exists(columns = date, date_time) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}",
#' active = FALSE
#' ) %>%
@@ -197,7 +197,7 @@
#' agent_3 <-
#' agent_2 %>%
#' col_vals_in_set(
-#' columns = vars(f),
+#' columns = f,
#' set = c("low", "mid", "high")
#' ) %>%
#' remove_steps(i = 5) %>%
@@ -889,6 +889,7 @@ get_multiagent_report <- function(
#report code {
font-family: 'IBM Plex Mono', monospace, courier;
font-size: 11px;
+ color: black;
background-color: transparent;
padding: 0;
}
@@ -914,6 +915,11 @@ get_multiagent_report <- function(
class(report_tbl) <- c("ptblank_multiagent_report.wide", class(report_tbl))
+ # Quarto rendering workaround
+ if (check_quarto()) {
+ report_tbl <- gt::fmt(report_tbl, fns = identity)
+ }
+
report_tbl
}
@@ -1504,6 +1510,6 @@ generate_cell_content <- function(
return(cell_content)
}
-
+ NULL
# nocov end
}
diff --git a/R/get_sundered_data.R b/R/get_sundered_data.R
index 8c5063abf..808b742b7 100644
--- a/R/get_sundered_data.R
+++ b/R/get_sundered_data.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -94,9 +94,9 @@
#' dplyr::select(a:f),
#' label = "`get_sundered_data()`"
#' ) %>%
-#' col_vals_gt(columns = vars(d), value = 1000) %>%
+#' col_vals_gt(columns = d, value = 1000) %>%
#' col_vals_between(
-#' columns = vars(c),
+#' columns = c,
#' left = vars(a), right = vars(d),
#' na_pass = TRUE
#' ) %>%
@@ -268,6 +268,14 @@ get_sundered_data <- function(
)
}
+ # Stop function if `tbl_checked` is not present
+ if (!"tbl_checked" %in% colnames(agent$validation_set)) {
+ stop(
+ "`agent` is missing `tbl_checked` information required for sundering. ",
+ "See `?interrogate`."
+ )
+ }
+
# Get the row count of the input table
row_count_input_tbl <-
input_tbl %>%
diff --git a/R/has_columns.R b/R/has_columns.R
index e4dafa1ee..0252c79da 100644
--- a/R/has_columns.R
+++ b/R/has_columns.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -27,10 +27,10 @@
#' specified name is present in a table object. This function works well enough
#' on a table object but it can also be used as part of a formula in any
#' validation function's `active` argument. Using `active = ~ . %>%
-#' has_columns("column_1")` means that the validation step will be inactive if
+#' has_columns(column_1)` means that the validation step will be inactive if
#' the target table doesn't contain a column named `column_1`. We can also use
-#' multiple columns in `vars()` so having `active = ~ . %>%
-#' has_columns(vars(column_1, column_2))` in a validation step will make it
+#' multiple columns in `c()`, so having `active = ~ . %>%
+#' has_columns(c(column_1, column_2))` in a validation step will make it
#' inactive at [interrogate()] time unless the columns `column_1` and `column_2`
#' are both present.
#'
@@ -43,10 +43,10 @@
#'
#' @param columns *The target columns*
#'
-#' `vector|vars()`` // **required**
+#' `` // *required*
#'
-#' One or more column names that are to be checked for existence in the table
-#' `x`.
+#' One or more columns or column-selecting expressions. Each element is
+#' checked for a match in the table `x`.
#'
#' @return A length-1 logical vector.
#'
@@ -60,11 +60,10 @@
#' ```
#'
#' With `has_columns()` we can check for column existence by using it directly
-#' on the table. A column name can be verified as present by using it in double
-#' quotes.
+#' on the table.
#'
#' ```r
-#' small_table %>% has_columns(columns = "date")
+#' small_table %>% has_columns(columns = date)
#' ```
#'
#' ```
@@ -75,17 +74,17 @@
#' columns are present in `small_table`.
#'
#' ```r
-#' small_table %>% has_columns(columns = c("a", "b"))
+#' small_table %>% has_columns(columns = c(a, b))
#' ```
#'
#' ```
#' ## [1] TRUE
#' ```
#'
-#' It's possible to supply column names in `vars()` as well:
+#' It's possible to use a tidyselect helper as well:
#'
#' ```r
-#' small_table %>% has_columns(columns = vars(a, b))
+#' small_table %>% has_columns(columns = c(a, starts_with("b")))
#' ```
#'
#' ```
@@ -96,13 +95,27 @@
#' need to be present to obtain `TRUE`).
#'
#' ```r
-#' small_table %>% has_columns(columns = vars(a, h))
+#' small_table %>% has_columns(columns = c(a, h))
#' ```
#'
#' ```
#' ## [1] FALSE
#' ```
#'
+#' The same holds in the case of tidyselect helpers. Because no columns start
+#' with `"h"`, including `starts_with("h")` returns `FALSE` for the entire
+#' check.
+#'
+#' ```r
+#' small_table %>% has_columns(columns = starts_with("h"))
+#' small_table %>% has_columns(columns = c(a, starts_with("h")))
+#' ```
+#'
+#' ```
+#' ## [1] FALSE
+#' ## [1] FALSE
+#' ```
+#'
#' The `has_columns()` function can be useful in expressions that involve the
#' target table, especially if it is uncertain that the table will contain a
#' column that's involved in a validation.
@@ -119,17 +132,17 @@
#' tbl_name = "small_table"
#' ) %>%
#' col_vals_gt(
-#' columns = vars(c), value = vars(a),
-#' active = ~ . %>% has_columns(vars(a, c))
+#' columns = c, value = vars(a),
+#' active = ~ . %>% has_columns(c(a, c))
#' ) %>%
#' col_vals_lt(
-#' columns = vars(h), value = vars(d),
+#' columns = h, value = vars(d),
#' preconditions = ~ . %>% dplyr::mutate(h = d - a),
-#' active = ~ . %>% has_columns(vars(a, d))
+#' active = ~ . %>% has_columns(c(a, d))
#' ) %>%
#' col_is_character(
-#' columns = vars(j),
-#' active = ~ . %>% has_columns("j")
+#' columns = j,
+#' active = ~ . %>% has_columns(j)
#' ) %>%
#' interrogate()
#' ```
@@ -170,17 +183,47 @@ has_columns <- function(
)
}
- # Normalize the `columns` expression
- if (inherits(columns, "quosures")) {
+ # Capture the `columns` expression
+ columns <- rlang::enquo(columns)
+ if (rlang::quo_is_missing(columns)) {
+ rlang::abort("Must supply a value for `columns`")
+ }
+
+ # Split into quos if multi-length c()/vars() expr
+ if (rlang::quo_is_call(columns, c("c", "vars"))) {
+ columns_env <- rlang::quo_get_env(columns)
+ column_quos <- lapply(rlang::call_args(columns), function(x) {
+ rlang::new_quosure(x, env = columns_env)
+ })
+ } else {
+ column_quos <- list(columns)
+ }
+
+ .call <- rlang::current_env()
+ has_column <- function(col_expr) {
+ columns <- tryCatch(
+ expr = resolve_columns(x = x, var_expr = col_expr,
+ allow_empty = FALSE, call = .call),
+ error = function(cnd) cnd
+ )
+ ## If error from {tidyselect}, counts as no selection
+ if (rlang::is_error(columns)) {
+ cnd <- columns
+ # Rethrow error if genuine evaluation error
+ if (inherits(cnd, "resolve_eval_err")) {
+ rlang::cnd_signal(cnd)
+ }
+ # Return length-0 vector if "column not found" or "0 columns" error
+ return(character(0L))
+ }
- columns <-
- vapply(
- columns,
- FUN.VALUE = character(1),
- USE.NAMES = FALSE,
- FUN = function(x) as.character(rlang::get_expr(x))
- )
+ ## If columns succesfully resolved to character, return only existing ones
+ intersect(columns, colnames(x))
}
- all(columns %in% rlang::names2(x))
+ # A list of columns (character vector) selected by elements of `columns`
+ # - Ex: `c(a, b:c)` becomes `list("a", c("b", "c"))` if data has those columns
+ columns_list <- lapply(column_quos, has_column)
+ all(lengths(columns_list) > 0L)
+
}
diff --git a/R/incorporate.R b/R/incorporate.R
index a14ec4325..c7346f49e 100644
--- a/R/incorporate.R
+++ b/R/incorporate.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -75,7 +75,7 @@
#' fn = ~ . %>% ncol()
#' ) %>%
#' info_columns(
-#' columns = vars(a),
+#' columns = a,
#' info = "In the range of 1 to 10. ((SIMPLE))"
#' ) %>%
#' info_columns(
@@ -83,7 +83,7 @@
#' info = "Time-based values (e.g., `Sys.time()`)."
#' ) %>%
#' info_columns(
-#' columns = "date",
+#' columns = date,
#' info = "The date part of `date_time`. ((CALC))"
#' ) %>%
#' info_section(
@@ -207,7 +207,7 @@ incorporate <- function(informant) {
# TODO: Improve the `stop()` message here
stop(
"The `read_fn` object must be a function or an R formula.\n",
- "* A function can be made with `function()` {}.\n",
+ "* A function can be made with `function()` {}.\n",
"* An R formula can also be used, with the expression on the RHS.",
call. = FALSE
)
@@ -371,7 +371,7 @@ incorporate <- function(informant) {
extra_sections <-
base::setdiff(
names(informant$metadata),
- c("info_label", "table", "columns")
+ c("info_label", "table", "columns", "_private")
)
metadata_extra <- informant$metadata[extra_sections]
diff --git a/R/info_add.R b/R/info_add.R
index ab574cd52..c0ed7af33 100644
--- a/R/info_add.R
+++ b/R/info_add.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -193,7 +193,7 @@ info_tabular <- function(
...
) {
- metadata_items <- list(...)
+ metadata_items <- rlang::list2(...)
metadata <- x
@@ -246,7 +246,7 @@ info_tabular <- function(
#'
#' @param columns *The target columns*
#'
-#' `vector|vars()`` // **required**
+#' `vector|vars()` // **required**
#'
#' The column or set of columns to focus on. Can be defined as a column name
#' in quotes (e.g., `""`), one or more column names in `vars()`
@@ -331,19 +331,19 @@ info_tabular <- function(
#' # R statement
#' informant %>%
#' info_columns(
-#' columns = "date_time",
+#' columns = date_time,
#' info = "*info text* 1."
#' ) %>%
#' info_columns(
-#' columns = "date",
+#' columns = date,
#' info = "*info text* 2."
#' ) %>%
#' info_columns(
-#' columns = "item_count",
+#' columns = item_count,
#' info = "*info text* 3. Statistics: {snippet_1}."
#' ) %>%
#' info_columns(
-#' columns = vars(date, date_time),
+#' columns = c(date, date_time),
#' info = "UTC time."
#' )
#'
@@ -401,7 +401,7 @@ info_tabular <- function(
#' informant <-
#' informant %>%
#' info_columns(
-#' columns = vars(a),
+#' columns = a,
#' info = "In the range of 1 to 10. ((SIMPLE))"
#' ) %>%
#' info_columns(
@@ -409,7 +409,7 @@ info_tabular <- function(
#' info = "Time-based values (e.g., `Sys.time()`)."
#' ) %>%
#' info_columns(
-#' columns = "date",
+#' columns = date,
#' info = "The date part of `date_time`. ((CALC))"
#' )
#' ```
@@ -442,17 +442,21 @@ info_columns <- function(
# Capture the `columns` expression
columns <- rlang::enquo(columns)
- metadata_items <- list(...)
+ metadata_items <- rlang::list2(...)
metadata <- x
metadata_list <- metadata$metadata
metadata_columns <- metadata_list$columns
- x <- dplyr::as_tibble(metadata_columns %>% lapply(function(x) 1))
+ if (is.null(x$tbl)) {
+ tbl <- metadata_list[["_private"]]$col_ptypes
+ } else {
+ tbl <- x$tbl
+ }
# Resolve the columns based on the expression
- columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
+ columns <- resolve_columns(x = tbl, var_expr = columns)
if (length(columns) == 1 && is.na(columns)) {
@@ -605,11 +609,11 @@ info_columns <- function(
#' informant <-
#' informant %>%
#' info_columns(
-#' columns = "item_revenue",
+#' columns = item_revenue,
#' info = "Revenue reported in USD."
#' ) %>%
#' info_columns(
-#' columns = "acquisition",
+#' columns = acquisition,
#' `top list` = "{top5_aq}"
#' ) %>%
#' info_snippet(
@@ -719,7 +723,7 @@ check_info_columns_tbl <- function(tbl) {
#'
#' @param section_name *The section name*
#'
-#' `scalar`` // **required**
+#' `scalar` // **required**
#'
#' The name of the section for which this information pertains.
#'
@@ -888,7 +892,7 @@ info_section <- function(
...
) {
- metadata_items <- list(...)
+ metadata_items <- rlang::list2(...)
metadata <- x
@@ -961,7 +965,7 @@ info_section <- function(
#'
#' @param snippet_name *The snippet name*
#'
-#' `scalar`` // **required**
+#' `scalar` // **required**
#'
#' The name for snippet, which is used for interpolating the result of the
#' snippet formula into *info text* defined by an `info_*()` function.
@@ -1009,7 +1013,7 @@ info_section <- function(
#' # R statement
#' informant %>%
#' info_columns(
-#' columns = "date_time",
+#' columns = date_time,
#' `Latest Date` = "The latest date is {latest_date}."
#' ) %>%
#' info_snippet(
@@ -1064,7 +1068,7 @@ info_section <- function(
#' fn = snip_highest(column = "a")
#' ) %>%
#' info_columns(
-#' columns = vars(a),
+#' columns = a,
#' info = "In the range of 1 to {max_a}. ((SIMPLE))"
#' ) %>%
#' info_columns(
@@ -1072,7 +1076,7 @@ info_section <- function(
#' info = "Time-based values (e.g., `Sys.time()`)."
#' ) %>%
#' info_columns(
-#' columns = "date",
+#' columns = date,
#' info = "The date part of `date_time`. ((CALC))"
#' ) %>%
#' info_section(
@@ -1158,7 +1162,7 @@ info_snippet <- function(
#'
#' @param column *The target column*
#'
-#' `scalar`` // **required**
+#' `scalar` // **required**
#'
#' The name of the column that contains the target values.
#'
@@ -1227,6 +1231,12 @@ info_snippet <- function(
#' derived from `character` or `factor` values; numbers, dates, and logical
#' values won't have quotation marks. We can explicitly use quotations (or
#' not) with either `TRUE` or `FALSE` here.
+#'
+#' @param na_rm *Remove NA values from list*
+#'
+#' `scalar` // *default:* `FALSE`
+#'
+#' An option for whether NA values should be counted as an item in the list.
#'
#' @param lang *Reporting language*
#'
@@ -1260,7 +1270,7 @@ info_snippet <- function(
#' label = "An example."
#' ) %>%
#' info_columns(
-#' columns = "f",
+#' columns = f,
#' `Items` = "This column contains {values_f}."
#' ) %>%
#' info_snippet(
@@ -1297,6 +1307,7 @@ snip_list <- function(
oxford = TRUE,
as_code = TRUE,
quot_str = NULL,
+ na_rm = FALSE,
lang = NULL
) {
@@ -1361,9 +1372,9 @@ snip_list <- function(
stats::as.formula(
as.character(
glue::glue(
- "~ . %>% dplyr::select(<>) %>%",
+ "~ . %>% dplyr::select(`<>`) %>%",
"dplyr::distinct() %>%",
- "dplyr::pull(<>) %>%",
+ "dplyr::pull(`<>`) %>%",
ifelse(reverse, "rev() %>%", ""),
"pb_str_catalog(
limit = <>,
@@ -1372,6 +1383,7 @@ snip_list <- function(
oxford = <>,
as_code = <>,
quot_str = <>,
+ na_rm = <>,
lang = <>
)",
.open = "<<", .close = ">>"
@@ -1385,16 +1397,16 @@ snip_list <- function(
stats::as.formula(
as.character(
glue::glue(
- "~ . %>% dplyr::select(<>) %>%",
- "dplyr::group_by(<>) %>%",
+ "~ . %>% dplyr::select(`<>`) %>%",
+ "dplyr::group_by(`<>`) %>%",
"dplyr::summarize(`_count_` = dplyr::n(), .groups = 'keep') %>%",
ifelse(
reverse,
"dplyr::arrange(`_count_`) %>%",
"dplyr::arrange(dplyr::desc(`_count_`)) %>%"
),
- "dplyr::select(<>) %>%",
- "dplyr::pull(<>) %>%",
+ "dplyr::select(`<>`) %>%",
+ "dplyr::pull(`<>`) %>%",
"pb_str_catalog(
limit = <>,
sep = <>,
@@ -1402,6 +1414,7 @@ snip_list <- function(
oxford = <>,
as_code = <>,
quot_str = <>,
+ na_rm = <>,
lang = <>
)",
.open = "<<", .close = ">>"
@@ -1416,9 +1429,9 @@ snip_list <- function(
stats::as.formula(
as.character(
glue::glue(
- "~ . %>% dplyr::select(<>) %>%",
+ "~ . %>% dplyr::select(`<>`) %>%",
"dplyr::distinct() %>%",
- "dplyr::pull(<>) %>%",
+ "dplyr::pull(`<>`) %>%",
ifelse(
reverse,
"sort(decreasing = TRUE) %>%",
@@ -1431,6 +1444,7 @@ snip_list <- function(
oxford = <>,
as_code = <>,
quot_str = <>,
+ na_rm = <>,
lang = <>
)",
.open = "<<", .close = ">>"
@@ -1461,7 +1475,7 @@ snip_list <- function(
#'
#' @param column *The target column*
#'
-#' `scalar`` // **required**
+#' `scalar` // **required**
#'
#' The name of the column that contains the target values.
#'
@@ -1491,7 +1505,7 @@ snip_list <- function(
#' label = "An example."
#' ) %>%
#' info_columns(
-#' columns = "d",
+#' columns = d,
#' `Stats` = "Stats (fivenum): {stats_d}."
#' ) %>%
#' info_snippet(
@@ -1529,7 +1543,7 @@ snip_stats <- function(
as.character(
glue::glue(
"~ . %>%
- dplyr::select(<>) %>%
+ dplyr::select(`<>`) %>%
pb_str_summary(type = '<>')",
.open = "<<", .close = ">>"
)
@@ -1548,7 +1562,7 @@ snip_stats <- function(
#'
#' @param column *The target column*
#'
-#' `scalar`` // **required**
+#' `scalar` // **required**
#'
#' The name of the column that contains the target values.
#'
@@ -1570,7 +1584,7 @@ snip_stats <- function(
#' label = "An example."
#' ) %>%
#' info_columns(
-#' columns = "a",
+#' columns = a,
#' `Lowest Value` = "Lowest value is {lowest_a}."
#' ) %>%
#' info_snippet(
@@ -1603,8 +1617,8 @@ snip_lowest <- function(column) {
as.character(
glue::glue(
"~ . %>%
- dplyr::select(<>) %>% dplyr::distinct() %>%
- dplyr::summarize(`pb_summary` = min(<>, na.rm = TRUE)) %>%
+ dplyr::select(`<>`) %>% dplyr::distinct() %>%
+ dplyr::summarize(`pb_summary` = min(`<>`, na.rm = TRUE)) %>%
dplyr::pull(`pb_summary`) %>% as.character()",
.open = "<<", .close = ">>"
)
@@ -1622,7 +1636,7 @@ snip_lowest <- function(column) {
#'
#' @param column *The target column*
#'
-#' `scalar`` // **required**
+#' `scalar` // **required**
#'
#' The name of the column that contains the target values.
#'
@@ -1644,7 +1658,7 @@ snip_lowest <- function(column) {
#' label = "An example."
#' ) %>%
#' info_columns(
-#' columns = "a",
+#' columns = a,
#' `Highest Value` = "Highest value is {highest_a}."
#' ) %>%
#' info_snippet(
@@ -1677,8 +1691,8 @@ snip_highest <- function(column) {
as.character(
glue::glue(
"~ . %>%
- dplyr::select(<>) %>% dplyr::distinct() %>%
- dplyr::summarize(`pb_summary` = max(<>, na.rm = TRUE)) %>%
+ dplyr::select(`<>`) %>% dplyr::distinct() %>%
+ dplyr::summarize(`pb_summary` = max(`<>`, na.rm = TRUE)) %>%
dplyr::pull(`pb_summary`) %>% as.character()",
.open = "<<", .close = ">>"
)
diff --git a/R/interrogate.R b/R/interrogate.R
index 8cb90dc6b..22606466c 100644
--- a/R/interrogate.R
+++ b/R/interrogate.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -44,6 +44,15 @@
#' The default is `TRUE` and further options allow for fine control of how
#' these rows are collected.
#'
+#' @param extract_tbl_checked *Collect validation results from each step*
+#'
+#' `scalar` // *default:* `TRUE`
+#'
+#' An option to collect processed data frames produced by executing the
+#' validation steps. This information is necessary for some functions
+#' (e.g., `get_sundered_data()`), but may grow to a large size. To opt out
+#' of attaching this data to the agent, set this argument to `FALSE`.
+#'
#' @param get_first_n *Get the first n values*
#'
#' `scalar` // *default:* `NULL` (`optional`)
@@ -79,6 +88,19 @@
#' A value that limits the possible number of rows returned when sampling
#' non-passing rows using the `sample_frac` option.
#'
+#' @param show_step_label *Show step labels in progress*
+#'
+#' `scalar` // *default:* `FALSE`
+#'
+#' Whether to show the `label` value of each validation step in the console.
+#'
+#' @param progress *Show interrogation progress*
+#'
+#' `scalar` // *default:* `interactive()`
+#'
+#' Whether to show the progress of an agent's interrogation in the console.
+#' Defaults to `TRUE` in interactive sessions.
+#'
#' @return A `ptblank_agent` object.
#'
#' @section Examples:
@@ -105,7 +127,7 @@
#' tbl = tbl,
#' label = "`interrogate()` example"
#' ) %>%
-#' col_vals_gt(columns = vars(a), value = 5) %>%
+#' col_vals_gt(columns = a, value = 5) %>%
#' interrogate()
#' ```
#'
@@ -130,10 +152,13 @@
interrogate <- function(
agent,
extract_failed = TRUE,
+ extract_tbl_checked = TRUE,
get_first_n = NULL,
sample_n = NULL,
sample_frac = NULL,
- sample_limit = 5000
+ sample_limit = 5000,
+ show_step_label = FALSE,
+ progress = interactive()
) {
#
@@ -177,7 +202,7 @@ interrogate <- function(
# TODO: create a better `stop()` message
stop(
"The `read_fn` object must be a function or an R formula.\n",
- "* A function can be made with `function()` {}.\n",
+ "* A function can be made with `function()` {}.\n",
"* An R formula can also be used, with the expression on the RHS.",
call. = FALSE
)
@@ -199,7 +224,7 @@ interrogate <- function(
# Quieting of an agent's remarks either when the agent has the
# special label `"::QUIET::"` or the session is non-interactive
- if (agent$label == "::QUIET::" || !interactive()) {
+ if (agent$label == "::QUIET::" || !progress) {
quiet <- TRUE
} else {
quiet <- FALSE
@@ -251,15 +276,6 @@ interrogate <- function(
agent$validation_set[[i, "eval_active"]] <- FALSE
}
- # Set the validation step as `active = FALSE` if there is a
- # no column available as a result of a select expression
- if (!is.null(agent$validation_set$column[[i]]) &&
- is.na(agent$validation_set$column[[i]]) &&
- agent$validation_set$assertion_type[[i]] %in%
- column_expansion_fns_vec()) {
- agent$validation_set[[i, "eval_active"]] <- FALSE
- }
-
# Skip the validation step if `active = FALSE`
if (!agent$validation_set[[i, "eval_active"]]) {
@@ -710,6 +726,7 @@ interrogate <- function(
agent = agent,
i = i,
time_diff_s = time_diff_s,
+ show_step_label = show_step_label,
quiet = quiet
)
}
@@ -722,6 +739,11 @@ interrogate <- function(
# all validation steps have been carried out
class(agent) <- c("has_intel", "ptblank_agent")
+ # Drop $tbl_checked if `extract_tbl_checked = FALSE`
+ if (!extract_tbl_checked) {
+ agent$validation_set$tbl_checked <- NULL
+ }
+
# Add the ending time to the `agent` object
agent$time_end <- Sys.time()
@@ -804,6 +826,7 @@ create_post_step_cli_output_a <- function(
agent,
i,
time_diff_s,
+ show_step_label,
quiet
) {
@@ -840,6 +863,13 @@ create_post_step_cli_output_a <- function(
)) %>%
dplyr::pull(condition)
+ label <- agent$validation_set[i, ]$label
+ if (show_step_label && !is.na(label)) {
+ step_label <- paste0(" - {label}")
+ } else {
+ step_label <- NULL
+ }
+
cli::cli_div(
theme = list(
span.green = list(color = "green"),
@@ -854,26 +884,33 @@ create_post_step_cli_output_a <- function(
c(
"Step {.field {i}}: an evaluation issue requires attention ",
"(", interrogation_evaluation, ").",
- print_time(time_diff_s)
+ print_time(time_diff_s),
+ step_label
)
)
} else if (validation_condition == "NONE" && notify_condition == "NONE") {
cli::cli_alert_success(
- c("Step {.field {i}}: {.green OK}.", print_time(time_diff_s))
+ c(
+ "Step {.field {i}}: {.green OK}.",
+ print_time(time_diff_s),
+ step_label
+ )
)
} else if (validation_condition != "NONE" && notify_condition == "NONE") {
if (validation_condition == "STOP") {
cli::cli_alert_danger(
c(
"Step {.field {i}}: {.red STOP} condition met.",
- print_time(time_diff_s)
+ print_time(time_diff_s),
+ step_label
)
)
} else {
cli::cli_alert_warning(
c(
"Step {.field {i}}: {.yellow WARNING} condition met.",
- print_time(time_diff_s)
+ print_time(time_diff_s),
+ step_label
)
)
}
@@ -883,7 +920,8 @@ create_post_step_cli_output_a <- function(
c(
"Step {.field {i}}: {.red STOP} and ",
"{.blue NOTIFY} conditions met.",
- print_time(time_diff_s)
+ print_time(time_diff_s),
+ step_label
)
)
} else {
@@ -891,7 +929,8 @@ create_post_step_cli_output_a <- function(
c(
"Step {.field {i}}: {.yellow WARNING} and ",
"{.blue NOTIFY} conditions met.",
- print_time(time_diff_s)
+ print_time(time_diff_s),
+ step_label
)
)
}
@@ -899,7 +938,8 @@ create_post_step_cli_output_a <- function(
cli::cli_alert_warning(
c(
"Step {.field {i}}: {.blue NOTIFY} condition met.",
- print_time(time_diff_s)
+ print_time(time_diff_s),
+ step_label
)
)
}
@@ -1059,18 +1099,15 @@ interrogate_comparison <- function(
value <- get_values_at_idx(agent = agent, idx = idx)
# Normalize a column in `vars()` to a `name` object
- if (inherits(value, "list")) {
- value <- value[1][[1]] %>% rlang::get_expr()
- } else {
- if (is.character(value)) {
- value <- paste0("'", value, "'")
- }
+ if (inherits(value, "list") && rlang::is_quosure(value[1][[1]])) {
+ # Both `vars(col)` and `vars("col")` become `col` for `dplyr::mutate()`
+ value <- rlang::sym(rlang::quo_get_expr(value[1][[1]]))
}
# Obtain the target column as a label
column <-
get_column_as_sym_at_idx(agent = agent, idx = idx) %>%
- rlang::as_label()
+ as.character()
# Determine whether NAs should be allowed
na_pass <- get_column_na_pass_at_idx(agent = agent, idx = idx)
@@ -1107,20 +1144,20 @@ tbl_val_comparison <- function(
)
# Construct a string-based expression for the validation
- expression <- paste(column, operator, value)
+ expression <- call(operator, as.symbol(column), value)
if (is_tbl_mssql(table)) {
table %>%
dplyr::mutate(pb_is_good_ = dplyr::case_when(
- !!rlang::parse_expr(expression) ~ 1,
+ !!expression ~ 1,
TRUE ~ 0
))
} else {
table %>%
- dplyr::mutate(pb_is_good_ = !!rlang::parse_expr(expression)) %>%
+ dplyr::mutate(pb_is_good_ = !!expression) %>%
dplyr::mutate(pb_is_good_ = dplyr::case_when(
is.na(pb_is_good_) ~ na_pass,
TRUE ~ pb_is_good_
@@ -1414,10 +1451,10 @@ interrogate_set <- function(
}
extra_variables <-
- base::setdiff(table_col_distinct_values, set)
+ table_col_distinct_values[!table_col_distinct_values %in% set]
table_col_distinct_set <-
- base::intersect(table_col_distinct_values, set)
+ table_col_distinct_values[table_col_distinct_values %in% set]
dplyr::bind_rows(
dplyr::tibble(set_element = as.character(set)) %>%
@@ -1489,7 +1526,7 @@ interrogate_set <- function(
}
table_col_distinct_set <-
- base::intersect(table_col_distinct_values, set)
+ table_col_distinct_values[table_col_distinct_values %in% set]
dplyr::tibble(set_element = as.character(set)) %>%
dplyr::left_join(
@@ -2226,13 +2263,21 @@ interrogate_col_exists <- function(
# Obtain the target column as a symbol
column <- get_column_as_sym_at_idx(agent = agent, idx = idx)
+ # Get `column_expr` to signal error if user didn't supply `columns`
+ column_input_missing <- agent$validation_set$columns_expr[idx] == "NULL"
+
# Create function for validating the `col_exists()` step function
tbl_col_exists <- function(
table,
column,
- column_names
+ column_names,
+ column_input_missing
) {
+ if (column_input_missing) {
+ stop("`columns` argument must be supplied.", call. = FALSE)
+ }
+
# Ensure that the input `table` is actually a table object
tbl_validity_check(table = table)
@@ -2244,7 +2289,8 @@ interrogate_col_exists <- function(
tbl_col_exists(
table = table,
column = {{ column }},
- column_names = column_names
+ column_names = column_names,
+ column_input_missing = column_input_missing
)
)
}
@@ -2313,31 +2359,22 @@ interrogate_distinct <- function(
table
) {
- # Determine if grouping columns are provided in the test
- # for distinct rows and parse the column names
- if (!is.na(agent$validation_set$column[idx] %>% unlist())) {
-
+ column_names <-
+ get_column_as_sym_at_idx(agent = agent, idx = idx) %>%
+ as.character()
+
+ if (grepl("(,|&)", column_names)) {
column_names <-
- get_column_as_sym_at_idx(agent = agent, idx = idx) %>%
- as.character()
-
- if (grepl("(,|&)", column_names)) {
- column_names <-
- strsplit(split = "(, |,|&)", column_names) %>%
- unlist()
- }
-
- if (length(column_names) == 1 && column_names == "NA") {
- if (uses_tidyselect(expr_text = agent$validation_set$columns_expr[idx])) {
- column_names <- character(0)
- }
- }
-
- } else if (is.na(agent$validation_set$column[idx] %>% unlist())) {
- column_names <- get_all_cols(agent = agent)
+ strsplit(split = "(, |,|&)", column_names) %>%
+ unlist()
}
- col_syms <- rlang::syms(column_names)
+ if (identical(column_names, NA_character_)) {
+ # If column is missing, let it get caught by `column_validity_has_columns`
+ col_syms <- NULL
+ } else {
+ col_syms <- rlang::syms(column_names)
+ }
# Create function for validating the `rows_distinct()` step function
tbl_rows_distinct <- function(
@@ -2413,31 +2450,22 @@ interrogate_complete <- function(
table
) {
- # Determine if grouping columns are provided in the test
- # for distinct rows and parse the column names
- if (!is.na(agent$validation_set$column[idx] %>% unlist())) {
-
+ column_names <-
+ get_column_as_sym_at_idx(agent = agent, idx = idx) %>%
+ as.character()
+
+ if (grepl("(,|&)", column_names)) {
column_names <-
- get_column_as_sym_at_idx(agent = agent, idx = idx) %>%
- as.character()
-
- if (grepl("(,|&)", column_names)) {
- column_names <-
- strsplit(split = "(, |,|&)", column_names) %>%
- unlist()
- }
-
- if (length(column_names) == 1 && column_names == "NA") {
- if (uses_tidyselect(expr_text = agent$validation_set$columns_expr[idx])) {
- column_names <- character(0)
- }
- }
-
- } else if (is.na(agent$validation_set$column[idx] %>% unlist())) {
- column_names <- get_all_cols(agent = agent)
+ strsplit(split = "(, |,|&)", column_names) %>%
+ unlist()
}
- col_syms <- rlang::syms(column_names)
+ if (identical(column_names, NA_character_)) {
+ # If column is missing, let it get caught by `column_validity_has_columns`
+ col_syms <- NULL
+ } else {
+ col_syms <- rlang::syms(column_names)
+ }
# Create function for validating the `rows_complete()` step function
tbl_rows_complete <- function(
@@ -2823,15 +2851,9 @@ column_validity_checks_column_value <- function(
value
) {
- table_colnames <- colnames(table)
+ column_validity_checks_column(table, column)
- if (!(as.character(column) %in% table_colnames)) {
-
- stop(
- "The value for `column` doesn't correspond to a column name.",
- call. = FALSE
- )
- }
+ table_colnames <- colnames(table)
if (inherits(value, "name")) {
@@ -2851,7 +2873,7 @@ column_validity_checks_column_value <- function(
# Validity check for presence of columns
column_validity_has_columns <- function(columns) {
- if (length(columns) < 1) {
+ if (length(columns) < 1 || identical(columns, NA_character_)) {
stop(
"The column selection statement that was used yielded no columns.",
call. = FALSE
@@ -2865,6 +2887,8 @@ column_validity_checks_column <- function(
column
) {
+ column_validity_has_columns(as.character(column))
+
table_colnames <- colnames(table)
if (!(as.character(column) %in% table_colnames)) {
@@ -2884,15 +2908,9 @@ column_validity_checks_ib_nb <- function(
right
) {
- table_colnames <- colnames(table)
+ column_validity_checks_column(table, column)
- if (!(as.character(column) %in% table_colnames)) {
-
- stop(
- "The value for `column` doesn't correspond to a column name.",
- call. = FALSE
- )
- }
+ table_colnames <- colnames(table)
if (inherits(left, "name")) {
@@ -2921,6 +2939,8 @@ column_validity_checks_ib_nb <- function(
pointblank_try_catch <- function(expr) {
+ call <- rlang::enexpr(expr)
+
warn <- err <- NULL
value <-
@@ -2933,7 +2953,7 @@ pointblank_try_catch <- function(expr) {
invokeRestart("muffleWarning")
})
- eval_list <- list(value = value, warning = warn, error = err)
+ eval_list <- list(value = value, warning = warn, error = err, pb_call = call)
class(eval_list) <- "table_eval"
eval_list
@@ -2953,7 +2973,7 @@ add_reporting_data <- function(
has_warnings <- !is.null(tbl_checked$warning)
has_error <- !is.null(tbl_checked$error)
- capture_stack <- tbl_checked[c("warning", "error")]
+ capture_stack <- tbl_checked[c("warning", "error", "pb_call")]
agent$validation_set$eval_warning[idx] <- has_warnings
agent$validation_set$eval_error[idx] <- has_error
@@ -3141,7 +3161,7 @@ perform_action <- function(
}
}
- return(NULL)
+ NULL
}
perform_end_action <- function(agent) {
@@ -3238,7 +3258,7 @@ perform_end_action <- function(agent) {
y %>% rlang::f_rhs() %>% rlang::eval_tidy()
})
- return(NULL)
+ NULL
}
add_table_extract <- function(
diff --git a/R/logging.R b/R/logging.R
index cf509b267..e52252051 100644
--- a/R/logging.R
+++ b/R/logging.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -144,8 +144,8 @@
#' label = "An example.",
#' actions = al
#' ) %>%
-#' col_vals_gt(columns = vars(d), 300) %>%
-#' col_vals_in_set(columns = vars(f), c("low", "high")) %>%
+#' col_vals_gt(columns = d, 300) %>%
+#' col_vals_in_set(columns = f, c("low", "high")) %>%
#' interrogate()
#'
#' agent
@@ -184,14 +184,7 @@ log4r_step <- function(
append_to = "pb_log_file"
) {
- if (!requireNamespace("log4r", quietly = TRUE)) {
-
- stop(
- "Using the `log4r_step()` function requires the log4r package:\n",
- "* It can be installed with `install.packages(\"log4r\")`.",
- call. = FALSE
- )
- }
+ rlang::check_installed("log4r", "to use the `log4r_step()` function.")
type <- x$this_type
warn_val <- x$warn
diff --git a/R/object_ops.R b/R/object_ops.R
index e8720b839..d3c0f0f39 100644
--- a/R/object_ops.R
+++ b/R/object_ops.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -133,14 +133,14 @@
#' ```r
#' agent <-
#' agent %>%
-#' col_exists(columns = vars(date, date_time)) %>%
+#' col_exists(columns = c(date, date_time)) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}"
#' ) %>%
#' rows_distinct() %>%
-#' col_vals_gt(columns = vars(d), value = 100) %>%
-#' col_vals_lte(columns = vars(c), value = 5) %>%
+#' col_vals_gt(columns = d, value = 100) %>%
+#' col_vals_lte(columns = c, value = 5) %>%
#' interrogate()
#' ```
#'
@@ -197,7 +197,7 @@
#' fn = snip_lowest(column = "a")
#' ) %>%
#' info_columns(
-#' columns = vars(a),
+#' columns = a,
#' info = "From {low_a} to {high_a}."
#' ) %>%
#' info_columns(
@@ -205,7 +205,7 @@
#' info = "Time-based values."
#' ) %>%
#' info_columns(
-#' columns = "date",
+#' columns = date,
#' info = "The date part of `date_time`."
#' ) %>%
#' incorporate()
@@ -240,13 +240,13 @@
#' actions = al
#' ) %>%
#' col_vals_gt(
-#' columns = vars(b),
-#' value = vars(g),
+#' columns = b,
+#' value = g,
#' na_pass = TRUE,
#' label = "b > g"
#' ) %>%
#' col_is_character(
-#' columns = vars(b, f),
+#' columns = c(b, f),
#' label = "Verifying character-type columns"
#' ) %>%
#' interrogate()
@@ -611,14 +611,14 @@ x_read_disk <- function(
#' ```r
#' agent <-
#' agent %>%
-#' col_exists(columns = vars(date, date_time)) %>%
+#' col_exists(columns = c(date, date_time)) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}"
#' ) %>%
#' rows_distinct() %>%
-#' col_vals_gt(columns = vars(d), value = 100) %>%
-#' col_vals_lte(columns = vars(c), value = 5) %>%
+#' col_vals_gt(columns = d, value = 100) %>%
+#' col_vals_lte(columns = c, value = 5) %>%
#' interrogate()
#' ```
#'
@@ -672,7 +672,7 @@ x_read_disk <- function(
#' fn = snip_lowest(column = "a")
#' ) %>%
#' info_columns(
-#' columns = vars(a),
+#' columns = a,
#' info = "From {low_a} to {high_a}."
#' ) %>%
#' info_columns(
@@ -680,7 +680,7 @@ x_read_disk <- function(
#' info = "Time-based values."
#' ) %>%
#' info_columns(
-#' columns = "date",
+#' columns = date,
#' info = "The date part of `date_time`."
#' ) %>%
#' incorporate()
@@ -844,7 +844,7 @@ export_report <- function(
#'
#' @param tbl *Table or expression for reading in one*
#'
-#' `obj:|` // **required**
+#' `obj:|` // **required**
#'
#' The input table for the *agent* or the *informant*. This can be a data
#' frame, a tibble, a `tbl_dbi` object, or a `tbl_spark` object.
@@ -852,8 +852,8 @@ export_report <- function(
#' how to retrieve the target table at interrogation- or incorporation-time.
#' There are two ways to specify an association to a target table: (1) as a
#' table-prep formula, which is a right-hand side (RHS) formula expression
-#' (e.g., `~ { }`), or (2) as a function (e.g.,
-#' `function() { }`).
+#' (e.g., `~ { }`), or (2) as a function (e.g.,
+#' `function() { }`).
#'
#' @param tbl_name *A table name*
#'
@@ -895,9 +895,9 @@ export_report <- function(
#' label = "An example.",
#' actions = al
#' ) %>%
-#' col_exists(columns = vars(date, date_time)) %>%
+#' col_exists(columns = c(date, date_time)) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}"
#' ) %>%
#' rows_distinct() %>%
diff --git a/R/pipe.R b/R/pipe.R
index b63e636d7..081383635 100644
--- a/R/pipe.R
+++ b/R/pipe.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/print.R b/R/print.R
index 4cec41fb8..4d6ba6b0e 100644
--- a/R/print.R
+++ b/R/print.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/read_disk_multiagent.R b/R/read_disk_multiagent.R
index 1c84a02a3..787c0d893 100644
--- a/R/read_disk_multiagent.R
+++ b/R/read_disk_multiagent.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/reexports.R b/R/reexports.R
index 81e99bd1f..713bdae8f 100644
--- a/R/reexports.R
+++ b/R/reexports.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -35,26 +35,6 @@ dplyr::between
#' @export
rlang::expr
-#' @importFrom tidyselect starts_with
-#' @export
-tidyselect::starts_with
-
-#' @importFrom tidyselect ends_with
-#' @export
-tidyselect::ends_with
-
-#' @importFrom tidyselect contains
-#' @export
-tidyselect::contains
-
-#' @importFrom tidyselect matches
-#' @export
-tidyselect::matches
-
-#' @importFrom tidyselect everything
-#' @export
-tidyselect::everything
-
#' @importFrom blastula creds
#' @export
blastula::creds
diff --git a/R/regex.R b/R/regex.R
index 3f8f25743..0e3e7a359 100644
--- a/R/regex.R
+++ b/R/regex.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/remove_deactivate.R b/R/remove_deactivate.R
index 9c3b96469..31c189cd0 100644
--- a/R/remove_deactivate.R
+++ b/R/remove_deactivate.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -60,11 +60,11 @@
#' label = "An example."
#' ) %>%
#' col_exists(
-#' columns = vars(date),
+#' columns = date,
#' active = FALSE
#' ) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}",
#' active = FALSE
#' ) %>%
@@ -146,9 +146,9 @@ activate_steps <- function(
#' tbl_name = "small_table",
#' label = "An example."
#' ) %>%
-#' col_exists(columns = vars(date)) %>%
+#' col_exists(columns = date) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]"
#' ) %>%
#' interrogate()
@@ -227,9 +227,9 @@ deactivate_steps <- function(
#' tbl_name = "small_table",
#' label = "An example."
#' ) %>%
-#' col_exists(columns = vars(date)) %>%
+#' col_exists(columns = date) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]"
#' ) %>%
#' interrogate()
diff --git a/R/row_count_match.R b/R/row_count_match.R
index ff234ae64..03c6a61a0 100644
--- a/R/row_count_match.R
+++ b/R/row_count_match.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -43,9 +43,9 @@
#' against the target table in terms of row count values. If supplying a
#' comparison table, it can either be a table object such as a data frame, a
#' tibble, a `tbl_dbi` object, or a `tbl_spark` object. Alternatively, a
-#' table-prep formula (`~ `) or a function (`function()
-#' `) can be used to lazily read in the comparison table
-#' at interrogation time.
+#' table-prep formula (`~ `) or a function
+#' (`function() `) can be used to lazily read in the
+#' comparison table at interrogation time.
#'
#' @param tbl_compare *[Deprecated] Comparison table*
#'
@@ -137,6 +137,19 @@
#' depending on the situation (the first produces a warning, the other
#' `stop()`s).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -371,6 +384,7 @@ row_count_match <- function(
# Add one or more validation steps based on the
# length of `segments`
+ label <- resolve_label(label, segments = segments_list)
for (i in seq_along(segments_list)) {
seg_col <- names(segments_list[i])
@@ -390,7 +404,7 @@ row_count_match <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id,
- label = label,
+ label = label[[i]],
brief = brief,
active = active
)
diff --git a/R/rows_complete.R b/R/rows_complete.R
index c7fd201c4..d497fd067 100644
--- a/R/rows_complete.R
+++ b/R/rows_complete.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -32,10 +32,14 @@
#' be used with a data table. As a validation step or as an expectation, this
#' will operate over the number of test units that is equal to the number of
#' rows in the table (after any `preconditions` have been applied).
-#'
-#' We can specify the constraining column names in quotes, in `vars()`, and with
-#' the following **tidyselect** helper functions: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#'
+#' @param columns *The target columns*
+#'
+#' `` // *default:* `everything()`
+#'
+#' A column-selecting expression, as one would use inside `dplyr::select()`.
+#' Specifies the set of column(s) for which the completeness of rows is
+#' checked.
#'
#' @inheritParams col_vals_gt
#'
@@ -126,6 +130,20 @@
#' warning when a quarter of the total test units fails, the other `stop()`s at
#' the same threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -150,7 +168,7 @@
#' ```r
#' agent %>%
#' rows_complete(
-#' columns = vars(a, b),
+#' columns = c(a, b),
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' segments = b ~ c("group_1", "group_2"),
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
@@ -164,7 +182,7 @@
#' ```yaml
#' steps:
#' - rows_complete:
-#' columns: vars(a, b)
+#' columns: c(a, b)
#' preconditions: ~. %>% dplyr::filter(a < 10)
#' segments: b ~ c("group_1", "group_2")
#' actions:
@@ -205,7 +223,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' rows_complete(columns = vars(a, b)) %>%
+#' rows_complete(columns = c(a, b)) %>%
#' interrogate()
#' ```
#'
@@ -227,7 +245,7 @@
#'
#' ```{r}
#' tbl %>%
-#' rows_complete(columns = vars(a, b)) %>%
+#' rows_complete(columns = c(a, b)) %>%
#' dplyr::pull(a)
#' ```
#'
@@ -237,7 +255,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_rows_complete(tbl, columns = vars(a, b))
+#' expect_rows_complete(tbl, columns = c(a, b))
#' ```
#'
#' ## D: Using the test function
@@ -246,7 +264,7 @@
#' us.
#'
#' ```{r}
-#' test_rows_complete(tbl, columns = vars(a, b))
+#' test_rows_complete(tbl, columns = c(a, b))
#' ```
#'
#' @family validation functions
@@ -261,7 +279,7 @@ NULL
#' @export
rows_complete <- function(
x,
- columns = NULL,
+ columns = tidyselect::everything(),
preconditions = NULL,
segments = NULL,
actions = NULL,
@@ -271,28 +289,17 @@ rows_complete <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
-
- if (uses_tidyselect(expr_text = columns_expr)) {
-
- # Resolve the columns based on the expression
- columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
-
- } else {
-
- # Resolve the columns based on the expression
- if (!is.null(rlang::eval_tidy(columns)) && !is.null(columns)) {
- columns <- resolve_columns(x = x, var_expr = columns, preconditions)
- } else {
- columns <- NULL
- }
+ # `rows_*()` functions treat `NULL` as `everything()`
+ if (rlang::quo_is_null(columns) || rlang::quo_is_missing(columns)) {
+ columns <- rlang::quo(tidyselect::everything())
}
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
+
+ # Resolve the columns based on the expression
+ columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
# Resolve segments into list
segments_list <-
@@ -307,7 +314,7 @@ rows_complete <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
rows_complete(
- columns = columns,
+ columns = tidyselect::all_of(columns),
preconditions = preconditions,
segments = segments,
label = label,
@@ -322,12 +329,8 @@ rows_complete <- function(
agent <- x
- if (length(columns) > 0) {
+ if (length(columns) > 1) {
columns <- paste(columns, collapse = ", ")
- } else if (length(columns) == 1) {
- columns <- columns
- } else {
- columns <- NULL
}
if (is.null(brief)) {
@@ -352,6 +355,7 @@ rows_complete <- function(
# Add one or more validation steps based on the
# length of `segments`
+ label <- resolve_label(label, segments = segments_list)
for (i in seq_along(segments_list)) {
seg_col <- names(segments_list[i])
@@ -371,7 +375,7 @@ rows_complete <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id,
- label = label,
+ label = label[[i]],
brief = brief,
active = active
)
@@ -385,7 +389,7 @@ rows_complete <- function(
#' @export
expect_rows_complete <- function(
object,
- columns = NULL,
+ columns = tidyselect::everything(),
preconditions = NULL,
threshold = 1
) {
@@ -440,7 +444,7 @@ expect_rows_complete <- function(
#' @export
test_rows_complete <- function(
object,
- columns = NULL,
+ columns = tidyselect::everything(),
preconditions = NULL,
threshold = 1
) {
diff --git a/R/rows_distinct.R b/R/rows_distinct.R
index 6c822a8b3..d23afe8b9 100644
--- a/R/rows_distinct.R
+++ b/R/rows_distinct.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -34,9 +34,13 @@
#' test units that is equal to the number of rows in the table (after any
#' `preconditions` have been applied).
#'
-#' We can specify the constraining column names in quotes, in `vars()`, and with
-#' the following **tidyselect** helper functions: `starts_with()`,
-#' `ends_with()`, `contains()`, `matches()`, and `everything()`.
+#' @param columns *The target columns*
+#'
+#' `` // *default:* `everything()`
+#'
+#' A column-selecting expression, as one would use inside `dplyr::select()`.
+#' Specifies the set of column(s) for which the distinctness of rows is
+#' checked.
#'
#' @inheritParams col_vals_gt
#'
@@ -127,6 +131,20 @@
#' warning when a quarter of the total test units fails, the other `stop()`s at
#' the same threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.col}"`: The current column name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -151,7 +169,7 @@
#' ```r
#' agent %>%
#' rows_distinct(
-#' columns = vars(a, b),
+#' columns = c(a, b),
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' segments = b ~ c("group_1", "group_2"),
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
@@ -165,7 +183,7 @@
#' ```
#' steps:
#' - rows_distinct:
-#' columns: vars(a, b)
+#' columns: c(a, b)
#' preconditions: ~. %>% dplyr::filter(a < 10)
#' segments: b ~ c("group_1", "group_2")
#' actions:
@@ -206,7 +224,7 @@
#' ```r
#' agent <-
#' create_agent(tbl = tbl) %>%
-#' rows_distinct(columns = vars(a, b)) %>%
+#' rows_distinct(columns = c(a, b)) %>%
#' interrogate()
#' ```
#'
@@ -228,7 +246,7 @@
#'
#' ```{r}
#' tbl %>%
-#' rows_distinct(columns = vars(a, b)) %>%
+#' rows_distinct(columns = c(a, b)) %>%
#' dplyr::pull(a)
#' ```
#'
@@ -238,7 +256,7 @@
#' time. This is primarily used in **testthat** tests.
#'
#' ```r
-#' expect_rows_distinct(tbl, columns = vars(a, b))
+#' expect_rows_distinct(tbl, columns = c(a, b))
#' ```
#'
#' ## D: Using the test function
@@ -247,7 +265,7 @@
#' us.
#'
#' ```{r}
-#' test_rows_distinct(tbl, columns = vars(a, b))
+#' test_rows_distinct(tbl, columns = c(a, b))
#' ```
#'
#' @family validation functions
@@ -262,7 +280,7 @@ NULL
#' @export
rows_distinct <- function(
x,
- columns = NULL,
+ columns = tidyselect::everything(),
preconditions = NULL,
segments = NULL,
actions = NULL,
@@ -272,28 +290,17 @@ rows_distinct <- function(
active = TRUE
) {
- # Get `columns` as a label
- columns_expr <-
- rlang::as_label(rlang::quo(!!enquo(columns))) %>%
- gsub("^\"|\"$", "", .)
-
# Capture the `columns` expression
columns <- rlang::enquo(columns)
-
- if (uses_tidyselect(expr_text = columns_expr)) {
-
- # Resolve the columns based on the expression
- columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
-
- } else {
-
- # Resolve the columns based on the expression
- if (!is.null(rlang::eval_tidy(columns)) && !is.null(columns)) {
- columns <- resolve_columns(x = x, var_expr = columns, preconditions)
- } else {
- columns <- NULL
- }
+ # `rows_*()` functions treat `NULL` as `everything()`
+ if (rlang::quo_is_null(columns) || rlang::quo_is_missing(columns)) {
+ columns <- rlang::quo(tidyselect::everything())
}
+ # Get `columns` as a label
+ columns_expr <- as_columns_expr(columns)
+
+ # Resolve the columns based on the expression
+ columns <- resolve_columns(x = x, var_expr = columns, preconditions = NULL)
# Resolve segments into list
segments_list <-
@@ -308,7 +315,7 @@ rows_distinct <- function(
secret_agent <-
create_agent(x, label = "::QUIET::") %>%
rows_distinct(
- columns = columns,
+ columns = tidyselect::all_of(columns),
preconditions = preconditions,
segments = segments,
label = label,
@@ -323,12 +330,8 @@ rows_distinct <- function(
agent <- x
- if (length(columns) > 0) {
+ if (length(columns) > 1) {
columns <- paste(columns, collapse = ", ")
- } else if (length(columns) == 1) {
- columns <- columns
- } else {
- columns <- NULL
}
if (is.null(brief)) {
@@ -353,6 +356,7 @@ rows_distinct <- function(
# Add one or more validation steps based on the
# length of `segments`
+ label <- resolve_label(label, segments = segments_list)
for (i in seq_along(segments_list)) {
seg_col <- names(segments_list[i])
@@ -372,7 +376,7 @@ rows_distinct <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id,
- label = label,
+ label = label[[i]],
brief = brief,
active = active
)
@@ -386,7 +390,7 @@ rows_distinct <- function(
#' @export
expect_rows_distinct <- function(
object,
- columns = NULL,
+ columns = tidyselect::everything(),
preconditions = NULL,
threshold = 1
) {
@@ -441,7 +445,7 @@ expect_rows_distinct <- function(
#' @export
test_rows_distinct <- function(
object,
- columns = NULL,
+ columns = tidyselect::everything(),
preconditions = NULL,
threshold = 1
) {
diff --git a/R/scan_data.R b/R/scan_data.R
index db2cb3a32..b13c6545e 100644
--- a/R/scan_data.R
+++ b/R/scan_data.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -221,26 +221,10 @@ scan_data <- function(
}
if (any(c("interactions", "correlations") %in% sections)) {
-
- if (!requireNamespace("ggplot2", quietly = TRUE)) {
-
- stop(
- "The `interactions` and `correlations` sections require ",
- "the ggplot2 package:\n",
- "* It can be installed with `install.packages(\"ggplot2\")`.",
- call. = FALSE
- )
- }
-
- if (!requireNamespace("ggforce", quietly = TRUE)) {
-
- stop(
- "The `interactions` and `correlations` sections require ",
- "the ggforce package:\n",
- "* It can be installed with `install.packages(\"ggforce\")`.",
- call. = FALSE
- )
- }
+ rlang::check_installed(
+ c("ggforce", "ggplot2"),
+ "to use the `interactions` and `correlations` sections."
+ )
}
# Normalize the reporting language identifier and stop if necessary
@@ -1041,7 +1025,7 @@ probe_columns_numeric <- function(
locale
) {
- data_column <- dplyr::select(data, {{ column }})
+ data_column <- dplyr::select(data, tidyselect::any_of(column))
column_description_gt <-
get_column_description_gt(
@@ -1133,7 +1117,7 @@ probe_columns_character <- function(
locale
) {
- data_column <- data %>% dplyr::select({{ column }})
+ data_column <- data %>% dplyr::select(tidyselect::any_of(column))
column_description_gt <-
get_column_description_gt(
@@ -1184,7 +1168,7 @@ probe_columns_logical <- function(
locale
) {
- data_column <- data %>% dplyr::select({{ column }})
+ data_column <- data %>% dplyr::select(tidyselect::any_of(column))
column_description_gt <-
get_column_description_gt(
@@ -1211,7 +1195,7 @@ probe_columns_factor <- function(
locale
) {
- data_column <- data %>% dplyr::select({{ column }})
+ data_column <- data %>% dplyr::select(tidyselect::any_of(column))
column_description_gt <-
get_column_description_gt(
@@ -1238,7 +1222,7 @@ probe_columns_date <- function(
locale
) {
- data_column <- data %>% dplyr::select({{ column }})
+ data_column <- data %>% dplyr::select(tidyselect::any_of(column))
column_description_gt <-
get_column_description_gt(
@@ -1265,7 +1249,7 @@ probe_columns_posix <- function(
locale
) {
- data_column <- data %>% dplyr::select({{ column }})
+ data_column <- data %>% dplyr::select(tidyselect::any_of(column))
column_description_gt <-
get_column_description_gt(
@@ -1290,7 +1274,7 @@ probe_columns_other <- function(
n_rows
) {
- data_column <- data %>% dplyr::select({{ column }})
+ data_column <- data %>% dplyr::select(tidyselect::any_of(column))
column_classes <- paste(class(data_column), collapse = ", ")
diff --git a/R/serially.R b/R/serially.R
index 02e4d80b4..698772d2d 100644
--- a/R/serially.R
+++ b/R/serially.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -52,9 +52,9 @@
#' Here's an example of how to arrange expressions:
#'
#' ```
-#' ~ test_col_exists(., columns = vars(count)),
-#' ~ test_col_is_numeric(., columns = vars(count)),
-#' ~ col_vals_gt(., columns = vars(count), value = 2)
+#' ~ test_col_exists(., columns = count),
+#' ~ test_col_is_numeric(., columns = count),
+#' ~ col_vals_gt(., columns = count, value = 2)
#' ```
#'
#' This series concentrates on the column called `count` and first checks
@@ -83,7 +83,7 @@
#' [col_vals_increasing()], etc.) can optionally be inserted at the end of the
#' series, serving as a validation step that only undergoes interrogation if
#' the prior tests adequately pass. An example of this is
-#' `~ test_column_exists(., vars(a)), ~ col_vals_not_null(., vars(a))`).
+#' `~ test_column_exists(., a), ~ col_vals_not_null(., a)`).
#'
#' @param .list *Alternative to `...`*
#'
@@ -118,12 +118,17 @@
#'
#' @section Column Names:
#'
-#' If providing multiple column names in any of the supplied validation steps,
-#' the result will be an expansion of sub-validation steps to that number of
-#' column names. Aside from column names in quotes and in `vars()`,
-#' **tidyselect** helper functions are available for specifying columns. They
-#' are: `starts_with()`, `ends_with()`, `contains()`, `matches()`, and
-#' `everything()`.
+#' `columns` may be a single column (as symbol `a` or string `"a"`) or a vector
+#' of columns (`c(a, b, c)` or `c("a", "b", "c")`). `{tidyselect}` helpers
+#' are also supported, such as `contains("date")` and `where(is.double)`. If
+#' passing an *external vector* of columns, it should be wrapped in `all_of()`.
+#'
+#' When multiple columns are selected by `columns`, the result will be an
+#' expansion of validation steps to that number of columns (e.g.,
+#' `c(col_a, col_b)` will result in the entry of two validation steps).
+#'
+#' Previously, columns could be specified in `vars()`. This continues to work,
+#' but `c()` offers the same capability and supersedes `vars()` in `columns`.
#'
#' @section Preconditions:
#'
@@ -160,6 +165,17 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -184,9 +200,9 @@
#' ```r
#' agent %>%
#' serially(
-#' ~ col_vals_lt(., columns = vars(a), value = 8),
-#' ~ col_vals_gt(., columns = vars(c), value = vars(a)),
-#' ~ col_vals_not_null(., columns = vars(b)),
+#' ~ test_col_vals_lt(., columns = a, value = 8),
+#' ~ test_col_vals_gt(., columns = c, value = vars(a)),
+#' ~ col_vals_not_null(., columns = b),
#' preconditions = ~ . %>% dplyr::filter(a < 10),
#' actions = action_levels(warn_at = 0.1, stop_at = 0.2),
#' label = "The `serially()` step.",
@@ -200,9 +216,9 @@
#' steps:
#' - serially:
#' fns:
-#' - ~col_vals_lt(., columns = vars(a), value = 8)
-#' - ~col_vals_gt(., columns = vars(c), value = vars(a))
-#' - ~col_vals_not_null(., vars(b))
+#' - ~test_col_vals_lt(., columns = a, value = 8)
+#' - ~test_col_vals_gt(., columns = c, value = vars(a))
+#' - ~col_vals_not_null(., columns = b)
#' preconditions: ~. %>% dplyr::filter(a < 10)
#' actions:
#' warn_fraction: 0.1
@@ -249,9 +265,9 @@
#' agent_1 <-
#' create_agent(tbl = tbl) %>%
#' serially(
-#' ~ test_col_is_numeric(., columns = vars(a, b)),
-#' ~ test_col_vals_not_null(., columns = vars(a, b)),
-#' ~ col_vals_gt(., columns = vars(b), value = vars(a))
+#' ~ test_col_is_numeric(., columns = c(a, b)),
+#' ~ test_col_vals_not_null(., columns = c(a, b)),
+#' ~ col_vals_gt(., columns = b, value = vars(a))
#' ) %>%
#' interrogate()
#' ```
@@ -276,8 +292,8 @@
#' agent_2 <-
#' create_agent(tbl = tbl) %>%
#' serially(
-#' ~ test_col_is_numeric(., columns = vars(a, b)),
-#' ~ test_col_vals_not_null(., columns = vars(a, b))
+#' ~ test_col_is_numeric(., columns = c(a, b)),
+#' ~ test_col_vals_not_null(., columns = c(a, b))
#' ) %>%
#' interrogate()
#' ```
@@ -299,9 +315,9 @@
#' ```{r}
#' tbl %>%
#' serially(
-#' ~ test_col_is_numeric(., columns = vars(a, b)),
-#' ~ test_col_vals_not_null(., columns = vars(a, b)),
-#' ~ col_vals_gt(., columns = vars(b), value = vars(a))
+#' ~ test_col_is_numeric(., columns = c(a, b)),
+#' ~ test_col_vals_not_null(., columns = c(a, b)),
+#' ~ col_vals_gt(., columns = b, value = vars(a))
#' )
#' ```
#'
@@ -313,9 +329,9 @@
#' ```r
#' expect_serially(
#' tbl,
-#' ~ test_col_is_numeric(., columns = vars(a, b)),
-#' ~ test_col_vals_not_null(., columns = vars(a, b)),
-#' ~ col_vals_gt(., columns = vars(b), value = vars(a))
+#' ~ test_col_is_numeric(., columns = c(a, b)),
+#' ~ test_col_vals_not_null(., columns = c(a, b)),
+#' ~ col_vals_gt(., columns = b, value = vars(a))
#' )
#' ```
#'
@@ -327,9 +343,9 @@
#' ```{r}
#' tbl %>%
#' test_serially(
-#' ~ test_col_is_numeric(., columns = vars(a, b)),
-#' ~ test_col_vals_not_null(., columns = vars(a, b)),
-#' ~ col_vals_gt(., columns = vars(b), value = vars(a))
+#' ~ test_col_is_numeric(., columns = c(a, b)),
+#' ~ test_col_vals_not_null(., columns = c(a, b)),
+#' ~ col_vals_gt(., columns = b, value = vars(a))
#' )
#' ```
#'
@@ -644,6 +660,7 @@ serially <- function(
# Add one or more validation steps based on the
# length of `segments_list`
+ label <- resolve_label(label, segments = segments_list)
for (i in seq_along(segments_list)) {
seg_col <- names(segments_list[i])
@@ -664,7 +681,7 @@ serially <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id,
- label = label,
+ label = label[[i]],
brief = brief,
active = active
)
diff --git a/R/specially.R b/R/specially.R
index 15f3c5a28..8e27ff486 100644
--- a/R/specially.R
+++ b/R/specially.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -104,6 +104,17 @@
#' quarter of the total test units fails, the other `stop()`s at the same
#' threshold level).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
@@ -366,6 +377,7 @@ specially <- function(
# Add one or more validation steps based on the
# length of `segments_list`
+ label <- resolve_label(label, segments = segments_list)
for (i in seq_along(segments_list)) {
seg_col <- names(segments_list[i])
@@ -386,7 +398,7 @@ specially <- function(
seg_val = seg_val,
actions = covert_actions(actions, agent),
step_id = step_id,
- label = label,
+ label = label[[i]],
brief = brief,
active = active
)
diff --git a/R/steps_and_briefs.R b/R/steps_and_briefs.R
index 936906a74..ccb2a63c1 100644
--- a/R/steps_and_briefs.R
+++ b/R/steps_and_briefs.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -35,34 +35,23 @@ create_validation_step <- function(
step_id = NULL,
label = NULL,
brief = NULL,
- active = NULL
+ active = NULL,
+ .call = rlang::caller_env(n = 2L)
) {
# Get the next step number (i)
i <- get_next_validation_set_row(agent)
# Calculate the SHA1 hash for the validation step
- sha1 <-
- digest::sha1(
- list(
- assertion_type = assertion_type,
- column = ifelse(is.null(column), list(NULL), list(column)),
- values = ifelse(
- is.null(values) || is_a_table_object(values),
- list(NULL), list(values)
- ),
- na_pass = ifelse(is.null(na_pass), NA, as.logical(na_pass)),
- preconditions = ifelse(
- is.null(preconditions), list(NULL), list(preconditions)
- ),
- seg_col = ifelse(
- is.null(seg_col), NA_character_, as.character(seg_col)
- ),
- seg_val = ifelse(
- is.null(seg_val), NA_character_, as.character(seg_val)
- )
- )
- )
+ sha1 <- hash_validation_step(
+ assertion_type = assertion_type,
+ column = column,
+ values = values,
+ na_pass = na_pass,
+ preconditions = preconditions,
+ seg_col = seg_col,
+ seg_val = seg_val
+ )
# Create a validation step as a single-row `tbl_df` object
validation_step_df <-
@@ -106,6 +95,21 @@ create_validation_step <- function(
f_failed = NA_real_
)
+ # glue-powered labels
+ if (!is.na(validation_step_df$label)) {
+ glue_mask <- rlang::new_environment(
+ data = list(
+ .step = assertion_type,
+ .col = column,
+ .seg_col = seg_col,
+ .seg_val = seg_val
+ ),
+ parent = .call
+ )
+ label <- glue::glue_data(glue_mask, validation_step_df$label, .envir = NULL)
+ validation_step_df$label <- as.character(label)
+ }
+
# Append `validation_step` to `validation_set`
agent$validation_set <-
dplyr::bind_rows(agent$validation_set, validation_step_df)
@@ -113,6 +117,54 @@ create_validation_step <- function(
agent
}
+get_hash_version <- function() {
+ "v0.12"
+}
+
+hash_validation_step <- function(assertion_type,
+ column = NULL,
+ values = NULL,
+ na_pass = NULL,
+ preconditions = NULL,
+ seg_col = NULL,
+ seg_val = NULL) {
+
+ # pkg version that introduced the current hash implementation
+ hash_version <- get_hash_version()
+
+ values <- if (is.null(values) || is_a_table_object(values)) {
+ NA_character_
+ } else if (is.list(values)) {
+ # Resolve `vars()` to scalar string
+ toString(vapply(values, deparse_expr, character(1)))
+ } else {
+ deparse_expr(values)
+ }
+
+ preconditions <- if (inherits(preconditions, "fseq")) {
+ # Spell out components of magrittr anonymous function
+ magrittr_fn_seq <- environment(preconditions)[["_function_list"]]
+ deparse_expr(magrittr_fn_seq)
+ } else {
+ deparse_expr(preconditions)
+ }
+
+ step_chr <- c(
+ assertion_type = assertion_type,
+ column = as.character(column %||% NA_character_),
+ values = values,
+ na_pass = as.character(na_pass %||% NA_character_),
+ preconditions = preconditions,
+ seg_col = as.character(seg_col %||% NA_character_),
+ seg_val = as.character(seg_val %||% NA_character_)
+ )
+
+ step_hash <- digest::sha1(step_chr)
+
+ paste(step_hash, hash_version, sep = "-")
+
+}
+
apply_preconditions_to_tbl <- function(agent, idx, tbl) {
preconditions <- agent$validation_set$preconditions[[idx]]
@@ -135,9 +187,10 @@ apply_segments_to_tbl <- function(agent, idx, tbl) {
}
# Generate a second set of 'preconditions' to filter the table
+ seg_val <- gsub("'", "\\\\'", seg_val)
preconditions <-
stats::as.formula(
- glue::glue("~ . %>% dplyr::filter({seg_col} == '{seg_val}')")
+ glue::glue("~ . %>% dplyr::filter(`{seg_col}` == '{seg_val}')")
)
tbl <- apply_preconditions(tbl = tbl, preconditions = preconditions)
diff --git a/R/table_transformers.R b/R/table_transformers.R
index 66cd2dce7..0c47d898d 100644
--- a/R/table_transformers.R
+++ b/R/table_transformers.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -67,7 +67,7 @@
#' ```{r}
#' tt_summary_stats(tbl = game_revenue) %>%
#' col_vals_lt(
-#' columns = vars(item_revenue),
+#' columns = item_revenue,
#' value = 150,
#' segments = .param. ~ "max"
#' )
@@ -83,7 +83,7 @@
#' dplyr::filter(item_type == "iap") %>%
#' tt_summary_stats() %>%
#' col_vals_between(
-#' columns = vars(item_revenue),
+#' columns = item_revenue,
#' left = 8, right = 12,
#' segments = .param. ~ "med"
#' )
@@ -112,7 +112,7 @@
#' rows_complete() %>%
#' rows_distinct() %>%
#' col_vals_between(
-#' columns = vars(item_revenue),
+#' columns = item_revenue,
#' left = 8, right = 12,
#' preconditions = ~ . %>%
#' dplyr::filter(item_type == "iap") %>%
@@ -161,7 +161,7 @@ tt_summary_stats <- function(tbl) {
if (r_col_types[i] %in% c("integer", "numeric")) {
- data_col <- dplyr::select(tbl, col_names[i])
+ data_col <- dplyr::select(tbl, tidyselect::all_of(col_names[i]))
# nocov start
@@ -238,11 +238,11 @@ tt_summary_stats <- function(tbl) {
#' ```{r}
#' tt_string_info(tbl = game_revenue) %>%
#' col_vals_equal(
-#' columns = vars(player_id),
+#' columns = player_id,
#' value = 15
#' ) %>%
#' col_vals_equal(
-#' columns = vars(session_id),
+#' columns = session_id,
#' value = 24
#' )
#' ```
@@ -256,7 +256,7 @@ tt_summary_stats <- function(tbl) {
#' ```{r}
#' tt_string_info(tbl = small_table) %>%
#' test_col_vals_lte(
-#' columns = vars(f),
+#' columns = f,
#' value = 4
#' )
#' ```
@@ -286,7 +286,7 @@ tt_string_info <- function(tbl) {
if (r_col_types[i] == "character") {
- data_col <- dplyr::select(tbl, col_names[i])
+ data_col <- dplyr::select(tbl, tidyselect::all_of(col_names[i]))
suppressWarnings({
info_list <- get_table_column_nchar_stats(data_column = data_col)
@@ -343,7 +343,7 @@ tt_string_info <- function(tbl) {
#' tt_tbl_dims(tbl = game_revenue) %>%
#' dplyr::filter(.param. == "rows") %>%
#' test_col_vals_gt(
-#' columns = vars(value),
+#' columns = value,
#' value = 1500
#' )
#' ```
@@ -355,7 +355,7 @@ tt_string_info <- function(tbl) {
#' tt_tbl_dims(tbl = small_table) %>%
#' dplyr::filter(.param. == "columns") %>%
#' test_col_vals_lt(
-#' columns = vars(value),
+#' columns = value,
#' value = 10
#' )
#' ```
@@ -421,7 +421,7 @@ tt_tbl_dims <- function(tbl) {
#' ```{r}
#' tt_tbl_colnames(tbl = game_revenue) %>%
#' test_col_vals_make_subset(
-#' columns = vars(value),
+#' columns = value,
#' set = c("acquisition", "country")
#' )
#' ```
@@ -436,7 +436,7 @@ tt_tbl_dims <- function(tbl) {
#' tt_tbl_colnames() %>%
#' tt_string_info() %>%
#' test_col_vals_lt(
-#' columns = vars(value),
+#' columns = value,
#' value = 15
#' )
#' ```
@@ -546,18 +546,7 @@ tt_time_shift <- function(
time_shift = "0y 0m 0d 0H 0M 0S"
) {
- # nocov start
-
- if (!requireNamespace("lubridate", quietly = TRUE)) {
-
- stop(
- "The `tt_time_shift()` function requires the lubridate package:\n",
- "* It can be installed with `install.packages(\"lubridate\")`.",
- call. = FALSE
- )
- }
-
- # nocov end
+ rlang::check_installed("lubridate", "to use the `tt_time_shift()` function.")
# Determine whether the `tbl` object is acceptable here
check_is_a_table_object(tbl = tbl)
@@ -585,7 +574,7 @@ tt_time_shift <- function(
tbl %>%
dplyr::mutate(
dplyr::across(
- .cols = time_columns,
+ .cols = tidyselect::all_of(time_columns),
.fns = ~ lubridate::days(n_days) + .
)
)
@@ -596,7 +585,7 @@ tt_time_shift <- function(
tbl %>%
dplyr::mutate(
dplyr::across(
- .cols = time_columns,
+ .cols = tidyselect::all_of(time_columns),
.fns = ~ time_shift + .
)
)
@@ -645,7 +634,7 @@ tt_time_shift <- function(
tbl %>%
dplyr::mutate(
dplyr::across(
- .cols = time_columns,
+ .cols = tidyselect::all_of(time_columns),
.fns = ~ fn_time(time_value * direction_val) + .)
)
}
@@ -760,18 +749,7 @@ tt_time_slice <- function(
arrange = FALSE
) {
- # nocov start
-
- if (!requireNamespace("lubridate", quietly = TRUE)) {
-
- stop(
- "The `tt_time_shift()` function requires the lubridate package:\n",
- "* It can be installed with `install.packages(\"lubridate\")`.",
- call. = FALSE
- )
- }
-
- # nocov end
+ rlang::check_installed("lubridate", "to use the `tt_time_slice()` function.")
keep <- match.arg(keep)
@@ -953,7 +931,7 @@ tt_time_slice <- function(
#' keep = "right"
#' ) %>%
#' test_col_vals_lte(
-#' columns = vars(session_duration),
+#' columns = session_duration,
#' value = get_tt_param(
#' tbl = stats_tbl,
#' param = "max",
@@ -1058,9 +1036,9 @@ get_tt_param <- function(
# Obtain the value from the `tbl` through a `select()`, `filter()`, `pull()`
param_value <-
tbl %>%
- dplyr::select(.param., .env$column) %>%
+ dplyr::select(.param., tidyselect::all_of(column)) %>%
dplyr::filter(.param. == .env$param) %>%
- dplyr::pull(.env$column)
+ dplyr::pull(tidyselect::all_of(column))
} else if (tt_type == "tbl_dims") {
diff --git a/R/tbl_from_db.R b/R/tbl_from_db.R
index f6d1c6779..12e836074 100644
--- a/R/tbl_from_db.R
+++ b/R/tbl_from_db.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -368,14 +368,7 @@ db_tbl <- function(
dbname <- bq_project
}
- if (!requireNamespace("DBI", quietly = TRUE)) {
-
- stop(
- "Accessing a database table requires the DBI package:\n",
- "* It can be installed with `install.packages(\"DBI\")`.",
- call. = FALSE
- )
- }
+ rlang::check_installed("DBI", "to access a database table.")
if (is.character(dbtype)) {
@@ -523,72 +516,27 @@ db_tbl <- function(
# nolint start
RPostgres_driver <- function() {
-
- if (!requireNamespace("RPostgres", quietly = TRUE)) {
-
- stop(
- "Accessing a PostgreSQL table requires the RPostgres package:\n",
- "* It can be installed with `install.packages(\"RPostgres\")`.",
- call. = FALSE
- )
- }
-
+ rlang::check_installed("RPostgres", "to access a PostgreSQL table.")
RPostgres::Postgres()
}
RMySQL_driver <- function() {
-
- if (!requireNamespace("RMySQL", quietly = TRUE)) {
-
- stop(
- "Accessing a MariaDB or MySQL table requires the RMySQL package:\n",
- "* It can be installed with `install.packages(\"RMySQL\")`.",
- call. = FALSE
- )
- }
-
+ rlang::check_installed("RMySQL", "to access a MariaDB or MySQL table.")
RMySQL::MySQL()
}
bigrquery_driver <- function() {
-
- if (!requireNamespace("bigrquery", quietly = TRUE)) {
-
- stop(
- "Accessing a BigQuery table requires the bigrquery package:\n",
- "* It can be installed with `install.packages(\"bigrquery\")`.",
- call. = FALSE
- )
- }
-
+ rlang::check_installed("bigquery", "to access a BigQuery table.")
bigrquery::bigquery()
}
DuckDB_driver <- function() {
-
- if (!requireNamespace("duckdb", quietly = TRUE)) {
-
- stop(
- "Accessing a DuckDB table requires the duckdb package:\n",
- "* It can be installed with `install.packages(\"duckdb\")`.",
- call. = FALSE
- )
- }
-
+ rlang::check_installed("duckdb", "to access a DuckDB table.")
duckdb::duckdb()
}
RSQLite_driver <- function() {
-
- if (!requireNamespace("RSQLite", quietly = TRUE)) {
-
- stop(
- "Accessing a SQLite table requires the RSQLite package:\n",
- "* It can be installed with `install.packages(\"RSQLite\")`.",
- call. = FALSE
- )
- }
-
+ rlang::check_installed("RSQLite", "to access a SQLite table.")
RSQLite::SQLite()
}
diff --git a/R/tbl_from_file.R b/R/tbl_from_file.R
index 7e96bae10..4829d8222 100644
--- a/R/tbl_from_file.R
+++ b/R/tbl_from_file.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -135,7 +135,7 @@
#' col_types = "TDdcddlc"
#' )
#' ) %>%
-#' col_vals_gt(columns = vars(a), value = 0)
+#' col_vals_gt(columns = a, value = 0)
#' ```
#'
#' All of the file-reading instructions are encapsulated in the `tbl` expression
@@ -162,7 +162,7 @@
#' tbl_name = "small_table",
#' label = "`file_tbl()` example.",
#' ) %>%
-#' col_vals_gt(columns = vars(a), value = 0) %>%
+#' col_vals_gt(columns = a, value = 0) %>%
#' interrogate()
#' ```
#'
@@ -285,13 +285,7 @@ file_tbl <- function(
verify = TRUE
) {
- if (!requireNamespace("readr", quietly = TRUE)) {
- stop(
- "Reading a table from a file requires the readr package:\n",
- " * It can be installed with `install.packages(\"readr\")`.",
- call. = FALSE
- )
- }
+ rlang::check_installed("readr", "to read a table from a file.")
file_extension <- tolower(tools::file_ext(file))
file_name <- basename(file)
@@ -463,7 +457,7 @@ file_tbl <- function(
#' # col_types = "TDdcddlc"
#' # )
#' # ) %>%
-#' # col_vals_gt(vars(a), 0) %>%
+#' # col_vals_gt(a, 0) %>%
#' # interrogate()
#'
#' # The `from_github()` helper function is
@@ -529,13 +523,7 @@ from_github <- function(
} else if (grepl("#", repo, fixed = TRUE)) {
- if (!requireNamespace("jsonlite", quietly = TRUE)) {
- stop(
- "Getting a table from a file in a PR requires the jsonlite package:\n",
- " * It can be installed with `install.packages(\"jsonlite\")`.",
- call. = FALSE
- )
- }
+ rlang::check_installed("jsonlite", "to get a table from a file in a PR.")
pr_number <- unlist(strsplit(repo, "#"))[2]
pulls_doc_tempfile <- tempfile(pattern = "pulls", fileext = ".json")
diff --git a/R/tbl_match.R b/R/tbl_match.R
index d9029772b..261453f73 100644
--- a/R/tbl_match.R
+++ b/R/tbl_match.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -43,8 +43,8 @@
#' A table to compare against the target table. This can either be a table
#' object, a table-prep formula. This can be a table object such as a data
#' frame, a tibble, a `tbl_dbi` object, or a `tbl_spark` object.
-#' Alternatively, a table-prep formula (`~ `) or a
-#' function (`function() `) can be used to lazily read in
+#' Alternatively, a table-prep formula (`~ `) or a
+#' function (`function() `) can be used to lazily read in
#' the table at interrogation time.
#'
#' @return For the validation function, the return value is either a
@@ -126,6 +126,19 @@
#' depending on the situation (the first produces a warning, the other
#' `stop()`s).
#'
+#' @section Labels:
+#'
+#' `label` may be a single string or a character vector that matches the number
+#' of expanded steps. `label` also supports `{glue}` syntax and exposes the
+#' following dynamic variables contextualized to the current step:
+#'
+#' - `"{.step}"`: The validation step name
+#' - `"{.seg_col}"`: The current segment's column name
+#' - `"{.seg_val}"`: The current segment's value/group
+#'
+#' The glue context also supports ordinary expressions for further flexibility
+#' (e.g., `"{toupper(.step)}"`) as long as they return a length-1 string.
+#'
#' @section Briefs:
#'
#' Want to describe this validation step in some detail? Keep in mind that this
diff --git a/R/tbl_store.R b/R/tbl_store.R
index ed772da17..21707cedc 100644
--- a/R/tbl_store.R
+++ b/R/tbl_store.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -107,7 +107,7 @@
#' label = "An example that uses a table store.",
#' actions = action_levels(warn_at = 0.10)
#' ) %>%
-#' col_exists(vars(date, date_time)) %>%
+#' col_exists(c(date, date_time)) %>%
#' write_yaml()
#' ```
#'
@@ -122,7 +122,7 @@
#' locale: en
#' steps:
#' - col_exists:
-#' columns: vars(date, date_time)
+#' columns: c(date, date_time)
#' ```
#'
#' Now, whenever the `sml_table_high` table needs to be validated, it can be
@@ -620,7 +620,7 @@ add_to_name_list <- function(
#' label = "`tbl_source()` example",
#' actions = action_levels(warn_at = 0.10)
#' ) %>%
-#' col_exists(columns = vars(date, date_time)) %>%
+#' col_exists(columns = c(date, date_time)) %>%
#' interrogate()
#' ```
#'
diff --git a/R/utils-output.R b/R/utils-output.R
index 83d38943d..6240ff211 100644
--- a/R/utils-output.R
+++ b/R/utils-output.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -165,4 +165,8 @@ get_rds_tbl_info_files_tbl <- function(rds_tbl, tbl_name) {
rds_tbl[rds_tbl$tbl_name == tbl_name, "information_files"][[1]][[1]]
}
+check_quarto <- function() {
+ Sys.getenv("QUARTO_BIN_PATH") != ""
+}
+
# nocov end
diff --git a/R/utils-profiling.R b/R/utils-profiling.R
index 8ee3b72ad..fdb6dbb1a 100644
--- a/R/utils-profiling.R
+++ b/R/utils-profiling.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/utils-specifications.R b/R/utils-specifications.R
index 87975e590..be20e8578 100644
--- a/R/utils-specifications.R
+++ b/R/utils-specifications.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/utils-tidyselect.R b/R/utils-tidyselect.R
new file mode 100644
index 000000000..ae61a36d0
--- /dev/null
+++ b/R/utils-tidyselect.R
@@ -0,0 +1,142 @@
+resolve_columns <- function(x, var_expr, preconditions = NULL, ...,
+ call = rlang::caller_env()) {
+
+ # If columns is just character vector, pass it through
+ if (rlang::is_character(rlang::quo_get_expr(var_expr))) {
+ return(rlang::eval_tidy(var_expr))
+ }
+
+ # Materialize table and apply preconditions for tidyselect
+ tbl <- apply_preconditions_for_cols(x, preconditions)
+
+ # If tbl cannot (yet) materialize, don't attempt tidyselect and return early
+ if (rlang::is_error(tbl)) {
+ return(resolve_columns_notidyselect(var_expr, tbl, call = call))
+ }
+
+ # Attempt tidyselect
+ out <- tryCatch(
+ expr = resolve_columns_internal(tbl, var_expr, ..., call = call),
+ error = function(cnd) cnd
+ )
+
+ if (rlang::is_error(out)) {
+ # If error is a genuine evaluation error, throw that error
+ if (!is_subscript_error(out)) {
+ rlang::cnd_signal(rlang::error_cnd("resolve_eval_err", parent = out))
+ }
+ # If not in validation-planning context (assert/expect/test), rethrow
+ if (is_a_table_object(x) || is_secret_agent(x)) {
+ rlang::cnd_signal(out)
+ } else {
+ # Else (mid-planning): grab columns attempted to subset
+ fail <- out$i %||% out$parent$i
+ # If failure is due to scoping a bad object in the env, re-throw error
+ if (!is.character(fail) && !rlang::is_integerish(fail)) {
+ rlang::cnd_signal(out)
+ }
+ success <- resolve_columns_possible(tbl, var_expr)
+ out <- c(success, fail) %||% NA_character_
+ }
+ }
+
+ out
+
+}
+
+resolve_columns_notidyselect <- function(var_expr, parent, call) {
+ # Error if attempting to tidyselect on a lazy tbl that cannot materialize
+ var_str <- rlang::expr_deparse(rlang::quo_get_expr(var_expr))
+ if (any(sapply(names(tidyselect::vars_select_helpers), grepl, var_str))) {
+ rlang::abort(
+ "Cannot use tidyselect helpers for an undefined lazy tbl.",
+ parent = parent,
+ call = call
+ )
+ }
+
+ # Force column selection to character vector
+ if (rlang::quo_is_symbol(var_expr)) {
+ var_expr <- rlang::as_name(var_expr)
+ } else if (rlang::quo_is_call(var_expr, c("vars", "c"))) {
+ var_expr <- rlang::quo_set_expr(var_expr, vars_to_c(var_expr))
+ }
+ rlang::eval_tidy(var_expr)
+}
+
+# Apply the preconditions function and resolve to data frame for tidyselect
+apply_preconditions_for_cols <- function(x, preconditions) {
+ # Extract tbl
+ tbl <- if (is_ptblank_agent(x)) {
+ tryCatch(get_tbl_object(x), error = function(cnd) cnd)
+ } else if (is_a_table_object(x)) {
+ x
+ }
+ # Apply preconditions
+ if (!rlang::is_error(tbl) && !is.null(preconditions)) {
+ tbl <- apply_preconditions(tbl = tbl, preconditions = preconditions)
+ }
+ tbl
+}
+
+# Determines whether the error from a tidyselect expression is from attempting
+# to select a non-existing column (i.e., a "subscript error")
+is_subscript_error <- function(cnd) {
+ is.null(cnd$parent) || inherits(cnd$parent, "vctrs_error_subscript")
+}
+
+# If selection gets short-circuited by error, re-run with `strict = FALSE`
+# to safely get the possible column selections
+resolve_columns_possible <- function(tbl, var_expr) {
+ success <- tryCatch(
+ names(tidyselect::eval_select(var_expr, tbl,
+ strict = FALSE, allow_empty = FALSE)),
+ error = function(cnd) NULL
+ )
+ success
+}
+
+# Resolve column selections to integer
+resolve_columns_internal <- function(tbl, var_expr, ..., call) {
+
+ # Return NA if the expr is NULL
+ if (rlang::quo_is_null(var_expr)) {
+ return(NA_character_)
+ }
+
+ # Special case `serially()`: just deparse elements and bypass tidyselect
+ if (rlang::is_empty(tbl)) {
+ var_expr <- rlang::quo_get_expr(var_expr)
+ if (rlang::is_symbol(var_expr) || rlang::is_scalar_character(var_expr)) {
+ column <- rlang::as_name(var_expr)
+ } else {
+ cols <- rlang::call_args(var_expr)
+ column <- vapply(cols, rlang::as_name, character(1), USE.NAMES = FALSE)
+ }
+ return(column)
+ }
+ # Special case `vars()`-expression for backwards compatibility
+ if (rlang::quo_is_call(var_expr, "vars")) {
+ var_expr <- rlang::quo_set_expr(var_expr, vars_to_c(var_expr))
+ }
+
+ # Proceed with tidyselect
+ column <- tidyselect::eval_select(var_expr, tbl, error_call = call, ...)
+ column <- names(column)
+
+ if (length(column) < 1) {
+ column <- NA_character_
+ }
+
+ column
+}
+
+# Convert to the idiomatic `c()`-expr before passing off to tidyselect
+# + ensure that vars() always scopes symbols to data (vars(a) -> c("a"))
+vars_to_c <- function(var_expr) {
+ var_args <- lapply(rlang::call_args(var_expr), function(var_arg) {
+ if (rlang::is_symbol(var_arg)) rlang::as_name(var_arg) else var_arg
+ })
+ c_expr <- rlang::call2("c", !!!var_args)
+ c_expr
+}
diff --git a/R/utils-translations.R b/R/utils-translations.R
index b960f2c76..51fa07a50 100644
--- a/R/utils-translations.R
+++ b/R/utils-translations.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/utils.R b/R/utils.R
index 68fa851ee..a7e1f9dc4 100644
--- a/R/utils.R
+++ b/R/utils.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -148,15 +148,8 @@ get_next_validation_set_row <- function(agent) {
step
}
-exported_tidyselect_fns <- function() {
- c("starts_with", "ends_with", "contains", "matches", "everything")
-}
-
-uses_tidyselect <- function(expr_text) {
- grepl(
- "^starts_with\\(|^ends_with\\(|^contains\\(|^matches\\(|^everything\\(",
- expr_text
- )
+tidyselect_helpers <- function() {
+ names(tidyselect::vars_select_helpers)
}
get_assertion_type_at_idx <- function(agent, idx) {
@@ -164,15 +157,29 @@ get_assertion_type_at_idx <- function(agent, idx) {
}
get_column_as_sym_at_idx <- function(agent, idx) {
- rlang::sym(
- agent$validation_set[[idx, "column"]] %>%
- unlist() %>%
- gsub("'", "", .)
- )
+ column <- unlist(agent$validation_set[[idx, "column"]])
+ if (!is.na(column)) {
+ column <- rlang::sym(gsub("'", "", column))
+ }
+ column
}
get_values_at_idx <- function(agent, idx) {
- agent$validation_set[[idx, "values"]] %>% unlist(recursive = FALSE)
+
+ # Get list-column element (`values` is always a length-1 list)
+ values <- agent$validation_set[[idx, "values"]]
+
+ # Expressions (via `col_vals_expr()`) and functions (via `specially()`)
+ # can get the old `unlist()` treatment
+ if (rlang::is_expression(values[[1]]) || rlang::is_function(values[[1]])) {
+ values <- unlist(values, recursive = FALSE)
+ } else {
+ # In other cases (e.g., `values`, `left`, `right`), flatten with subsetting
+ # to preserve class
+ values <- values[[1]]
+ }
+
+ values
}
get_column_na_pass_at_idx <- function(agent, idx) {
@@ -206,7 +213,7 @@ materialize_table <- function(tbl, check = TRUE) {
stop(
"The `tbl` object must either be a table, a function, or a formula.\n",
"* A table-prep formula can be used (with the expression on the RHS).\n",
- "* A function can be made with `function()` {}.",
+ "* A function can be made with `function()` {}.",
call. = FALSE
)
}
@@ -218,75 +225,45 @@ materialize_table <- function(tbl, check = TRUE) {
tbl
}
-resolve_expr_to_cols <- function(tbl, var_expr) {
-
- var_expr <- enquo(var_expr)
-
- if ((var_expr %>% rlang::get_expr() %>% as.character())[1] == "vars") {
-
- cols <- (var_expr %>% rlang::get_expr() %>% as.character())[-1]
- return(cols)
+as_columns_expr <- function(columns) {
+ columns_expr <- gsub("^\"|\"$", "", rlang::as_label(columns))
+ # Treat NULL and missing `columns` as the same
+ if (columns_expr == "") {
+ columns_expr <- "NULL"
}
-
- tidyselect::vars_select(.vars = colnames(tbl), {{ var_expr }}) %>% unname()
+ columns_expr
}
-resolve_columns <- function(x, var_expr, preconditions) {
-
- # If getting a character vector as `var_expr`, simply return the vector
- # since this should already be a vector of column names and it's not necessary
- # to resolve this against the target table
- if (is.character(var_expr)) {
- return(var_expr)
+is_secret_agent <- function(x) {
+ is_ptblank_agent(x) && (x$label == "::QUIET::")
+}
+
+resolve_label <- function(label, columns = "", segments = "") {
+ n_columns <- length(columns)
+ n_segments <- length(segments)
+ n_combinations <- n_columns * n_segments
+ # If label is NULL, turn into NA for vector storage
+ if (is.null(label)) {
+ label <- NA_character_
}
-
- # nocov start
-
- # Return an empty character vector if the expr is NULL
- if (inherits(var_expr, "quosure") &&
- var_expr %>% rlang::as_label() == "NULL") {
-
- return(character(NA_character_))
+ # If length-1, match length of col-x-seg combination
+ if (length(label) == 1) {
+ label <- rep_len(label, n_combinations)
}
-
- # nocov end
-
- # Get the column names from a non-NULL, non-character expression
- if (is.null(preconditions)) {
-
- if (inherits(x, c("data.frame", "tbl_df", "tbl_dbi"))) {
-
- column <- resolve_expr_to_cols(tbl = x, var_expr = !!var_expr)
-
- } else if (inherits(x, ("ptblank_agent"))) {
-
- tbl <- get_tbl_object(agent = x)
- column <- resolve_expr_to_cols(tbl = tbl, var_expr = !!var_expr)
- }
-
- } else {
-
- if (inherits(x, c("data.frame", "tbl_df", "tbl_dbi"))) {
-
- tbl <- apply_preconditions(tbl = x, preconditions = preconditions)
-
- column <- resolve_expr_to_cols(tbl = tbl, var_expr = !!var_expr)
-
- } else if (inherits(x, ("ptblank_agent"))) {
-
- tbl <- get_tbl_object(agent = x)
-
- tbl <- apply_preconditions(tbl = tbl, preconditions = preconditions)
-
- column <- resolve_expr_to_cols(tbl = tbl, var_expr = !!var_expr)
- }
+ # Check for length match
+ if (length(label) != n_combinations) {
+ rlang::abort(paste0("`label` must be length 1 or ", n_combinations,
+ ", not ", length(label)))
}
-
- if (length(column) < 1) {
- column <- NA_character_
+ # Create a columns * segments matrix of the (recycled) label vector
+ # - Fill by row to preserve order (for loops iterate the j before the i)
+ out <- matrix(label, nrow = n_columns, ncol = n_segments, byrow = TRUE)
+ # If missing columns and/or segments, collapse to vector/scalar
+ if (missing(columns) || missing(segments)) {
+ out <- as.vector(out)
}
-
- column
+ # A matrix/vector subsettable via `out[col]`, `out[seg]`, or `out[col,seg]`
+ out
}
#' The `resolve_segments()` function works with input from the `segments`
@@ -322,7 +299,7 @@ resolve_segments <- function(x, seg_expr, preconditions) {
}
segments_list <- list()
-
+
# Process each `seg_expr` element
for (i in seq_along(seg_expr)) {
@@ -344,7 +321,7 @@ resolve_segments <- function(x, seg_expr, preconditions) {
col_seg_vals <-
tbl %>%
- dplyr::select(.env$column_name) %>%
+ dplyr::select(tidyselect::all_of(column_name)) %>%
dplyr::distinct() %>%
dplyr::pull()
@@ -578,6 +555,64 @@ get_threshold_type <- function(threshold) {
}
}
+# nocov start
+
+all_data_vars <- function(x, data_cols) {
+ deparsed <- paste(deparse(x, width.cutoff = 500L), collapse = " ")
+ reparsed <- parse(text = deparsed, keep.source = TRUE)
+ x <- utils::getParseData(reparsed)
+ if (is.null(x)) return(NA_character_)
+
+ .data_vars <- pronoun_vars(x, ".data")
+ .env_vars <- pronoun_vars(x, ".env")
+
+ bare_syms <- x[
+ x$token == "SYMBOL" &
+ !x$text %in% c(".data", ".env") &
+ !x$id %in% c(names(.data_vars), names(.env_vars)),
+ c("id", "text")
+ ]
+ if (nrow(bare_syms) == 0) {
+ all_cols <- unique(.data_vars)
+ } else {
+ unscoped_vars <- bare_syms$text
+ names(unscoped_vars) <- bare_syms$id
+ all_cols <- c(unscoped_vars, .data_vars)
+ all_cols <- all_cols[order(as.integer(names(all_cols)))]
+ all_cols <- unique(all_cols)
+ }
+
+ all_cols <- all_cols[all_cols %in% data_cols]
+
+ if (length(all_cols) == 0) {
+ NA_character_
+ } else {
+ sort(all_cols)
+ }
+
+}
+
+pronoun_vars <- function(x, pronoun = c(".data", ".env")) {
+ pronoun <- match.arg(pronoun)
+ if (!any(x$text == pronoun)) return(character(0))
+ conseq_pronoun <- rle(x$text == pronoun)
+ x$dotdata <- rep(seq_along(conseq_pronoun$values), conseq_pronoun$lengths)
+ x$dotdata <- ifelse(x$text == pronoun, x$dotdata + 1, x$dotdata)
+ dotdata <- lapply(split(x, x$dotdata), function(g) {
+ if (g$text[1] == pronoun && g$token[3] %in% c("'$'", "LBB")) {
+ var <- g$text[4]
+ names(var) <- g$id[4]
+ if (g$token[4] == "STR_CONST") gsub('"', "", var) else var
+ } else {
+ character(0)
+ }
+ })
+ allvars <- unlist(unname(dotdata))
+ allvars
+}
+
+# nocov end
+
all_validations_fns_vec <- function() {
c(
@@ -692,19 +727,18 @@ get_tbl_dbi_src_details <- function(tbl) {
get_r_column_names_types <- function(tbl) {
suppressWarnings(
- column_names_types <-
+ column_header <-
tbl %>%
utils::head(1) %>%
- dplyr::collect() %>%
- vapply(
- FUN.VALUE = character(1),
- FUN = function(x) class(x)[1]
- )
+ dplyr::collect()
)
+ column_names_types <-
+ vapply(column_header, function(x) class(x)[1], character(1))
list(
col_names = names(column_names_types),
- r_col_types = unname(unlist(column_names_types))
+ r_col_types = unname(unlist(column_names_types)),
+ col_ptypes = utils::head(column_header, 0)
)
}
@@ -759,7 +793,8 @@ get_tbl_information_df <- function(tbl) {
db_tbl_name = NA_character_,
col_names = r_column_names_types$col_names,
r_col_types = r_column_names_types$r_col_types,
- db_col_types = NA_character_
+ db_col_types = NA_character_,
+ col_ptypes = r_column_names_types$col_ptypes
)
}
@@ -783,7 +818,8 @@ get_tbl_information_spark <- function(tbl) {
db_tbl_name = NA_character_,
col_names = r_column_names_types$col_names,
r_col_types = r_column_names_types$r_col_types,
- db_col_types = db_col_types
+ db_col_types = db_col_types,
+ col_ptypes = r_column_names_types$col_ptypes
)
}
@@ -927,7 +963,7 @@ get_tbl_information_dbi <- function(tbl) {
DBI::dbDataType(
tbl_connection,
tbl %>%
- dplyr::select(x) %>%
+ dplyr::select(tidyselect::all_of(x)) %>%
utils::head(1) %>%
dplyr::collect() %>%
dplyr::pull(x)
@@ -964,7 +1000,8 @@ get_tbl_information_dbi <- function(tbl) {
db_tbl_name = db_tbl_name,
col_names = r_column_names_types$col_names,
r_col_types = r_column_names_types$r_col_types,
- db_col_types = db_col_types
+ db_col_types = db_col_types,
+ col_ptypes = r_column_names_types$col_ptypes
)
}
@@ -1008,7 +1045,8 @@ get_tbl_information_arrow <- function(tbl) {
db_tbl_name = NA_character_,
col_names = col_names,
r_col_types = r_col_types,
- db_col_types = db_col_types
+ db_col_types = db_col_types,
+ col_ptypes = dplyr::collect(utils::head(tbl, 0))
)
}
@@ -1183,11 +1221,16 @@ pb_str_catalog <- function(
oxford = TRUE,
as_code = TRUE,
quot_str = NULL,
+ na_rm = FALSE,
lang = NULL
) {
if (is.null(lang)) lang <- "en"
+ if (na_rm) {
+ item_vector <- item_vector[!is.na(item_vector)]
+ }
+
item_count <- length(item_vector)
# If there is nothing in the `item_vector`, return
@@ -1568,8 +1611,8 @@ cli_bullet_msg <- function(
msg <- glue::glue_collapse(msg, "\n")
msg <- glue::glue(msg, .envir = .envir)
- if (!is.null(color) && requireNamespace("crayon", quietly = TRUE)) {
- color_style <- crayon::make_style(color)
+ if (!is.null(color)) {
+ color_style <- cli::make_ansi_style(color)
bullet <- color_style(bullet)
}
@@ -1590,16 +1633,14 @@ print_time <- function(time_diff_s) {
if (time_diff_s < 1) {
return("")
- } else {
- return(
- paste0(
- " {.time_taken (",
- round(time_diff_s, 1) %>%
- formatC(format = "f", drop0trailing = FALSE, digits = 1),
- " s)}"
- )
- )
}
+
+ paste0(
+ " {.time_taken (",
+ round(time_diff_s, 1) %>%
+ formatC(format = "f", drop0trailing = FALSE, digits = 1),
+ " s)}"
+ )
}
gt_missing <-
@@ -1646,3 +1687,12 @@ pb_get_image_tag <- function(file, dir = "images") {
"style=\"width:100\\%;\">"
)
}
+
+deparse_expr <- function(expr, collapse = " ", ...) {
+ if (rlang::is_scalar_atomic(expr)) {
+ as.character(expr)
+ } else {
+ deparsed <- paste(deparse(expr, ...), collapse = collapse)
+ paste("", deparsed)
+ }
+}
diff --git a/R/validate_rmd.R b/R/validate_rmd.R
index acd409ed9..62addb9ea 100644
--- a/R/validate_rmd.R
+++ b/R/validate_rmd.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -116,14 +116,7 @@ validate_rmd <- function(
if (test_options$perform_logging) {
- if (!requireNamespace("log4r", quietly = TRUE)) {
-
- stop(
- "Using the `log4r_step()` function requires the log4r package:\n",
- "* It can be installed with `install.packages(\"log4r\")`.",
- call. = FALSE
- )
- }
+ rlang::check_installed("log4r", "to use the `log4r_step()` function.")
# Create a log4r `logger` object and store it in `test_options`
test_options$logger <-
@@ -641,7 +634,7 @@ knitr_chunk_hook <- function(x, options) {
#' @export
stop_if_not <- function(...) {
- res <- list(...)
+ res <- rlang::list2(...)
n <- length(res)
@@ -681,8 +674,7 @@ stop_if_not <- function(...) {
return(TRUE)
- } else {
-
- return()
}
+
+ NULL
}
diff --git a/R/write_testthat_file.R b/R/write_testthat_file.R
index dec9e6fb7..eae53a986 100644
--- a/R/write_testthat_file.R
+++ b/R/write_testthat_file.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -79,7 +79,7 @@
#'
#' expect_col_exists(
#' tbl,
-#' columns = vars(date_time),
+#' columns = date_time,
#' threshold = 1
#' )
#' })
@@ -88,7 +88,7 @@
#'
#' expect_col_vals_lte(
#' tbl,
-#' columns = vars(c),
+#' columns = c,
#' value = 5,
#' threshold = 0.25
#' )
@@ -106,8 +106,8 @@
#' tbl = ~ small_table,
#' actions = action_levels(stop_at = 0.25)
#' ) %>%
-#' col_exists(vars(date_time)) %>%
-#' col_vals_lte(vars(c), value = 5)
+#' col_exists(date_time) %>%
+#' col_vals_lte(c, value = 5)
#'
#' write_testthat_file(
#' agent = agent,
@@ -206,13 +206,13 @@
#' label = "An example.",
#' actions = al
#' ) %>%
-#' col_exists(vars(date, date_time)) %>%
+#' col_exists(c(date, date_time)) %>%
#' col_vals_regex(
-#' vars(b),
+#' b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}"
#' ) %>%
-#' col_vals_gt(vars(d), value = 100) %>%
-#' col_vals_lte(vars(c), value = 5) %>%
+#' col_vals_gt(d, value = 100) %>%
+#' col_vals_lte(c, value = 5) %>%
#' interrogate()
#' ```
#'
@@ -245,7 +245,7 @@
#'
#' expect_col_exists(
#' tbl,
-#' columns = vars(date),
+#' columns = date,
#' threshold = 1
#' )
#' })
@@ -254,7 +254,7 @@
#'
#' expect_col_exists(
#' tbl,
-#' columns = vars(date_time),
+#' columns = date_time,
#' threshold = 1
#' )
#' })
@@ -264,7 +264,7 @@
#'
#' expect_col_vals_regex(
#' tbl,
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}",
#' threshold = 0.25
#' )
@@ -274,7 +274,7 @@
#'
#' expect_col_vals_gt(
#' tbl,
-#' columns = vars(d),
+#' columns = d,
#' value = 100,
#' threshold = 0.25
#' )
@@ -284,7 +284,7 @@
#'
#' expect_col_vals_lte(
#' tbl,
-#' columns = vars(c),
+#' columns = c,
#' value = 5,
#' threshold = 0.25
#' )
diff --git a/R/yaml_exec.R b/R/yaml_exec.R
index 2222d6aba..777d61970 100644
--- a/R/yaml_exec.R
+++ b/R/yaml_exec.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/yaml_read_agent.R b/R/yaml_read_agent.R
index 8718ff36f..22042952e 100644
--- a/R/yaml_read_agent.R
+++ b/R/yaml_read_agent.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -304,14 +304,14 @@ yaml_agent_interrogate <- function(
#' notify_at = 0.35
#' )
#' ) %>%
-#' col_exists(columns = vars(date, date_time)) %>%
+#' col_exists(columns = c(date, date_time)) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}"
#' ) %>%
#' rows_distinct() %>%
-#' col_vals_gt(columns = vars(d), value = 100) %>%
-#' col_vals_lte(columns = vars(c), value = 5)
+#' col_vals_gt(columns = d, value = 100) %>%
+#' col_vals_lte(columns = c, value = 5)
#' ```
#'
#' The agent can be written to a **pointblank** YAML file with [yaml_write()].
@@ -357,19 +357,19 @@ yaml_agent_interrogate <- function(
#' label = "A simple example with the `small_table`."
#' ) %>%
#' col_exists(
-#' columns = vars(date, date_time)
+#' columns = c(date, date_time)
#' ) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}"
#' ) %>%
#' rows_distinct() %>%
#' col_vals_gt(
-#' columns = vars(d),
+#' columns = d,
#' value = 100
#' ) %>%
#' col_vals_lte(
-#' columns = vars(c),
+#' columns = c,
#' value = 5
#' )
#' ```
@@ -539,7 +539,7 @@ make_validation_steps <- function(steps) {
tidyselect_regex <-
paste0(
"^(",
- paste(c("vars", exported_tidyselect_fns()), collapse = "|"),
+ paste(c("vars", "c", tidyselect_helpers()), collapse = "|"),
")\\(.*?\\)$"
)
diff --git a/R/yaml_read_informant.R b/R/yaml_read_informant.R
index 3f40ad3b9..ac72714c2 100644
--- a/R/yaml_read_informant.R
+++ b/R/yaml_read_informant.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/R/yaml_write.R b/R/yaml_write.R
index f5668d1e3..e8479979e 100644
--- a/R/yaml_write.R
+++ b/R/yaml_write.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
@@ -81,9 +81,9 @@
#' `scalar` // *default:* `FALSE`
#'
#' Should the written validation expressions for an *agent* be expanded such
-#' that **tidyselect** and [vars()] expressions for columns are evaluated,
-#' yielding a validation function per column? By default, this is `FALSE` so
-#' expressions as written will be retained in the YAML representation.
+#' that **tidyselect** expressions for columns are evaluated, yielding a
+#' validation function per column? By default, this is `FALSE` so expressions
+#' as written will be retained in the YAML representation.
#'
#' @param quiet *Inform (or not) upon file writing*
#'
@@ -139,14 +139,14 @@
#' ```r
#' agent <-
#' agent %>%
-#' col_exists(columns = vars(date, date_time)) %>%
+#' col_exists(columns = c(date, date_time)) %>%
#' col_vals_regex(
-#' columns = vars(b),
+#' columns = b,
#' regex = "[0-9]-[a-z]{3}-[0-9]{3}"
#' ) %>%
#' rows_distinct() %>%
-#' col_vals_gt(columns = vars(d), value = 100) %>%
-#' col_vals_lte(columns = vars(c), value = 5)
+#' col_vals_gt(columns = d, value = 100) %>%
+#' col_vals_lte(columns = c, value = 5)
#' ```
#'
#' The agent can be written to a **pointblank**-readable YAML file with the
@@ -178,17 +178,17 @@
#' notify_fraction: 0.35
#' steps:
#' - col_exists:
-#' columns: vars(date, date_time)
+#' columns: c(date, date_time)
#' - col_vals_regex:
-#' columns: vars(b)
+#' columns: c(b)
#' regex: '[0-9]-[a-z]{3}-[0-9]{3}'
#' - rows_distinct:
#' columns: ~
#' - col_vals_gt:
-#' columns: vars(d)
+#' columns: c(d)
#' value: 100.0
#' - col_vals_lte:
-#' columns: vars(c)
+#' columns: c(c)
#' value: 5.0
#' ```
#'
@@ -282,7 +282,7 @@
#' informant <-
#' informant %>%
#' info_columns(
-#' columns = vars(a),
+#' columns = a,
#' info = "In the range of 1 to 10. (SIMPLE)"
#' ) %>%
#' info_columns(
@@ -290,7 +290,7 @@
#' info = "Time-based values (e.g., `Sys.time()`)."
#' ) %>%
#' info_columns(
-#' columns = "date",
+#' columns = date,
#' info = "The date part of `date_time`. (CALC)"
#' )
#' ```
@@ -576,10 +576,9 @@ yaml_write <- function(
#' @param path An optional path to the YAML file (combined with `filename`).
#'
#' @param expanded Should the written validation expressions for an *agent* be
-#' expanded such that **tidyselect** and [vars()] expressions for columns are
-#' evaluated, yielding a validation function per column? By default, this is
-#' `FALSE` so expressions as written will be retained in the YAML
-#' representation.
+#' expanded such that **tidyselect** expressions for columns are evaluated,
+#' yielding a validation function per column? By default, this is `FALSE`
+#' so expressions as written will be retained in the YAML representation.
#'
#' @return Nothing is returned. Instead, text is printed to the console.
#'
@@ -649,56 +648,47 @@ yaml_agent_string <- function(
expanded = FALSE
) {
- if (is.null(agent) && is.null(filename)) {
- stop(
- "An `agent` object or a `filename` for a YAML file must be specified.",
- call. = FALSE
- )
- }
-
- if (!is.null(agent) && !is.null(filename)) {
- stop(
- "Only `agent` or `filename` should be specified (not both).",
- call. = FALSE
- )
- }
-
- if (!is.null(agent)) {
-
- # Display the agent's YAML as a nicely formatted string by
- # generating the YAML (`as_agent_yaml_list() %>% as.yaml()`) and
- # then emitting it to the console via `message()`
- message(
- as_agent_yaml_list(
- agent = agent,
- expanded = expanded
- ) %>%
- yaml::as.yaml(
- handlers = list(
- logical = function(x) {
- result <- ifelse(x, "true", "false")
- class(result) <- "verbatim"
- result
- }
+ switch(
+ rlang::check_exclusive(agent, filename),
+ agent = {
+ # Display the agent's YAML as a nicely formatted string by
+ # generating the YAML (`as_agent_yaml_list() %>% as.yaml()`) and
+ # then emitting it to the console via `message()`
+ message(
+ as_agent_yaml_list(
+ agent = agent,
+ expanded = expanded
+ ) %>%
+ yaml::as.yaml(
+ handlers = list(
+ logical = function(x) {
+ result <- ifelse(x, "true", "false")
+ class(result) <- "verbatim"
+ result
+ }
+ )
)
- )
- )
-
- } else {
-
- if (!is.null(path)) {
- filename <- file.path(path, filename)
+ )
+ },
+ filename = {
+ # Display the agent's YAML as a nicely formatted string by
+ # reading the YAML file specified by `file` (and perhaps `path`)
+ # and then emitting it to the console via `message()`
+ if (!is.null(path)) {
+ filename <- file.path(path, filename)
+ }
+ message(
+ readLines(filename) %>%
+ paste(collapse = "\n")
+ )
}
-
- # Display the agent's YAML as a nicely formatted string by
- # reading the YAML file specified by `file` (and perhaps `path`)
- # and then emitting it to the console via `message()`
- message(readLines(filename) %>% paste(collapse = "\n"))
- }
+ )
+
}
-as_vars_fn <- function(columns) {
- paste0("vars(", columns, ")")
+as_c_fn <- function(columns) {
+ columns <- strsplit(unlist(columns), ", ")[[1]]
+ paste0("c(", paste0('"', columns, '"', collapse = ", "), ")")
}
as_list_preconditions <- function(preconditions) {
@@ -714,9 +704,9 @@ as_list_preconditions <- function(preconditions) {
gsub("function (x) \n{", "function(x) {", ., fixed = TRUE)
)
- } else {
- return(as.character(preconditions))
}
+
+ as.character(preconditions)
}
as_list_segments <- function(segments) {
@@ -751,9 +741,9 @@ as_list_active <- function(active) {
if (is.logical(active[[1]])) {
return(active[[1]])
- } else {
- return(as.character(active))
}
+
+ as.character(active)
}
to_list_action_levels <- function(actions) {
@@ -1038,6 +1028,14 @@ as_agent_yaml_list <- function(agent, expanded) {
dplyr::filter(dplyr::row_number() == 1) %>%
dplyr::ungroup() %>%
dplyr::rename(i = i_o)
+
+ # Temporary conversion of `$label` to list-column
+ step_labels <- split(agent$validation_set$label, agent$validation_set$i_o)
+ step_labels_collapsed <- lapply(step_labels, function(label) {
+ # Collapse `label` when possible
+ if (all(is.na(label)) || all(label == label[1])) label[1] else label
+ })
+ agent_validation_set$label <- unname(step_labels_collapsed)
} else {
@@ -1329,16 +1327,16 @@ as_agent_yaml_list <- function(agent, expanded) {
} else if (validation_fn %in% c("rows_distinct", "rows_complete")) {
- if (is.na(step_list$column[[1]][[1]])) {
- vars_cols <- NULL
- } else {
- vars_cols <- as_vars_fn(step_list$column[[1]])
- }
+ column_text <-
+ get_column_text(
+ step_list = step_list,
+ expanded = expanded
+ )
lst_step <-
list(
validation_fn = list(
- columns = vars_cols,
+ columns = column_text,
preconditions = as_list_preconditions(step_list$preconditions),
segments = as_list_segments(step_list$seg_expr),
actions = as_action_levels(
@@ -1526,6 +1524,9 @@ as_agent_yaml_list <- function(agent, expanded) {
# Remove list elements that are representative of defaults
lst_step <- prune_lst_step(lst_step)
+
+ # Unlist labels as character vector/scalar
+ lst_step$validation_fn$label <- lst_step$validation_fn$label[[1]]
# Set the top level list-element name to that of
# the validation function
@@ -1554,15 +1555,18 @@ get_column_text <- function(step_list, expanded) {
if (!is.na(step_list$column[[1]]) &&
step_list$column[[1]] == step_list$columns_expr) {
- column_text <- as_vars_fn(step_list$column[[1]])
+ column_text <- as_c_fn(step_list$column[[1]])
} else {
column_text <- step_list$columns_expr
}
+ # Strip tidyselect namespacing for leaner yaml writing
+ column_text <- gsub("\\btidyselect::", "", column_text)
+
} else {
- column_text <- as_vars_fn(columns = step_list$column[[1]])
+ column_text <- as_c_fn(columns = step_list$column[[1]])
}
column_text
@@ -1609,6 +1613,9 @@ as_informant_yaml_list <- function(informant) {
lst_locale <- list(locale = informant$locale)
}
+ # Hide private field
+ metadata <- informant$metadata[names(informant$metadata) != "_private"]
+
c(
type = "informant", # YAML type: `informant`
lst_read_fn, # table-prep formula (stored in key `tbl`)
@@ -1617,7 +1624,7 @@ as_informant_yaml_list <- function(informant) {
lst_lang, # informant language
lst_locale, # informant locale
lst_meta_snippets, # informant metadata snippet statements
- informant$metadata # informant metadata entries
+ metadata # informant metadata entries
)
}
diff --git a/R/zzz.R b/R/zzz.R
index 4859d1363..4ff9393e4 100644
--- a/R/zzz.R
+++ b/R/zzz.R
@@ -11,7 +11,7 @@
#
# This file is part of the 'rstudio/pointblank' project.
#
-# Copyright (c) 2017-2023 pointblank authors
+# Copyright (c) 2017-2024 pointblank authors
#
# For full copyright and license information, please look at
# https://rstudio.github.io/pointblank/LICENSE.html
diff --git a/README.md b/README.md
index 081f63d69..79020cd95 100644
--- a/README.md
+++ b/README.md
@@ -4,21 +4,19 @@
-
-
-
-
-
-
-
-
-
-
-
+[![CRAN status](https://www.r-pkg.org/badges/version/pointblank)](https://CRAN.R-project.org/package=pointblank)
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/license/mit/)
+[![R-CMD-check](https://github.com/rstudio/pointblank/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/rstudio/pointblank/actions/workflows/R-CMD-check.yaml)
+[![Linting](https://github.com/rstudio/pointblank/actions/workflows/lint.yaml/badge.svg)](https://github.com/rstudio/pointblank/actions/workflows/lint.yaml)
+[![Codecov test coverage](https://codecov.io/gh/rstudio/pointblank/graph/badge.svg)](https://app.codecov.io/gh/rstudio/pointblank)
+[![Best Practices](https://bestpractices.coreinfrastructure.org/projects/4310/badge)](https://bestpractices.coreinfrastructure.org/projects/4310)
+[![The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
+[![Monthly Downloads](https://cranlogs.r-pkg.org/badges/pointblank)](https://CRAN.R-project.org/package=pointblank)
+[![Total Downloads](https://cranlogs.r-pkg.org/badges/grand-total/pointblank)](https://CRAN.R-project.org/package=pointblank)
[![Posit Cloud](https://img.shields.io/badge/Posit%20Cloud-pointblank%20Test%20Drive-blue?style=social&logo=rstudio&logoColor=75AADB)](https://rstudio.cloud/project/3411822)
-
-
+[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.1%20adopted-ff69b4.svg)](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html)
+
@@ -48,7 +46,7 @@ metadata updated so that this important documentation doesn't become stale.
## TABLE VALIDATIONS WITH AN AGENT AND DATA QUALITY REPORTING
Data validation can be carried out in *Data Quality Reporting* workflow,
-ultimately resulting in the production of of a data quality analysis report.
+ultimately resulting in the production of a data quality analysis report.
This is most useful in a non-interactive mode where data quality for database
tables and on-disk data files must be periodically checked. The **pointblank**
*agent* is given a collection of validation functions to define validation
@@ -141,14 +139,14 @@ dplyr::tibble(
b = c(6, 1, 0, 6, 0, 7)
) %>%
col_vals_between(
- vars(a), 1, 9,
+ a, 1, 9,
na_pass = TRUE
) %>%
col_vals_lt(
- vars(c), 12,
+ c, 12,
preconditions = ~ . %>% dplyr::mutate(c = a + b)
) %>%
- col_is_numeric(vars(a, b))
+ col_is_numeric(c(a, b))
```
Error: Exceedance of failed test units where values in `c` should have been < `12`.
@@ -169,17 +167,17 @@ dplyr::tibble(
b = c(6, 1, 0, 6, 0, 7)
) %>%
col_vals_between(
- vars(a), 1, 9,
+ a, 1, 9,
na_pass = TRUE,
actions = warn_on_fail()
) %>%
col_vals_lt(
- vars(c), 12,
+ c, 12,
preconditions = ~ . %>% dplyr::mutate(c = a + b),
actions = warn_on_fail()
) %>%
col_is_numeric(
- vars(a, b),
+ c(a, b),
actions = warn_on_fail()
)
```
@@ -267,19 +265,19 @@ informant <-
`README` pages. Column names are `a` and `b`. ((Cool stuff))"
) %>%
info_columns(
- columns = "a",
+ columns = a,
info = "This column has an `NA` value. [[Watch out!]]<>"
) %>%
info_columns(
- columns = "a",
+ columns = a,
info = "Mean value is `{a_mean}`."
) %>%
info_columns(
- columns = "b",
+ columns = b,
info = "Like column `a`. The lowest value is `{b_lowest}`."
) %>%
info_columns(
- columns = "b",
+ columns = b,
info = "The highest value is `{b_highest}`."
) %>%
info_snippet(
diff --git a/data-raw/translations_source.yml b/data-raw/translations_source.yml
index 263d135ce..c1baa01ab 100644
--- a/data-raw/translations_source.yml
+++ b/data-raw/translations_source.yml
@@ -1782,19 +1782,19 @@ table_scan:
sv: "Andra värden"
nl: "Andere waarden"
footer_text_fragment:
- en: "Table scan generated with pointblank."
- fr: "Scan de tableau généré avec pointblank."
- de: "Mit pointblank generierter Scan der Tabelle."
- it: "Scansione della tabella generata con pointblank."
- es: "Escaneo de Tabla generado con pointblank."
- pt: "Examen da tabela gerada com pointblank."
- tr: "pointblank ile oluşturulan tablo taraması."
- zh: "通过 pointblank建立表扫描。"
- ru: "Сканирование таблиц, сгенерированное с помощью pointblank."
- pl: "Skan tabeli wygenerowany za pomoca pointblank."
- da: "Scan af tabel genereret med pointblank."
- sv: "Genomsökning av tabellen genereras med pointblank."
- nl: "Scan van tabel gegenereerd met pointblank."
+ en: "Table scan generated with pointblank."
+ fr: "Scan de tableau généré avec pointblank."
+ de: "Mit pointblank generierter Scan der Tabelle."
+ it: "Scansione della tabella generata con pointblank."
+ es: "Escaneo de Tabla generado con pointblank."
+ pt: "Examen da tabela gerada com pointblank."
+ tr: "pointblank ile oluşturulan tablo taraması."
+ zh: "通过 pointblank建立表扫描。"
+ ru: "Сканирование таблиц, сгенерированное с помощью pointblank."
+ pl: "Skan tabeli wygenerowany za pomoca pointblank."
+ da: "Scan af tabel genereret med pointblank."
+ sv: "Genomsökning av tabellen genereras med pointblank."
+ nl: "Scan van tabel gegenereerd met pointblank."
multiagent_report:
pointblank_multiagent_title_text:
en: "Pointblank Validation Series"
diff --git a/images/pointblank_hex_logo.png b/images/pointblank_hex_logo.png
new file mode 100644
index 000000000..dbc5fa81e
Binary files /dev/null and b/images/pointblank_hex_logo.png differ
diff --git a/man/action_levels.Rd b/man/action_levels.Rd
index 680175b3d..e33cbbda9 100644
--- a/man/action_levels.Rd
+++ b/man/action_levels.Rd
@@ -161,10 +161,10 @@ validation steps and interrogate the \code{small_table}.
actions = al
) \%>\%
col_vals_gt(
- columns = vars(a), value = 2
+ columns = a, value = 2
) \%>\%
col_vals_lt(
- columns = vars(d), value = 20000
+ columns = d, value = 20000
) \%>\%
interrogate()
}\if{html}{\out{}}
@@ -192,11 +192,11 @@ another such object to the validation step instead (this time using the
actions = al
) \%>\%
col_vals_gt(
- columns = vars(a), value = 2,
+ columns = a, value = 2,
actions = warn_on_fail(warn_at = 0.5)
) \%>\%
col_vals_lt(
- columns = vars(d), value = 20000
+ columns = d, value = 20000
) \%>\%
interrogate()
}\if{html}{\out{}}
@@ -221,7 +221,7 @@ data).
\if{html}{\out{}}\preformatted{small_table \%>\%
col_vals_gt(
- columns = vars(a), value = 2,
+ columns = a, value = 2,
actions = warn_on_fail(warn_at = 2)
)
}\if{html}{\out{
}}
@@ -256,7 +256,7 @@ With the same pipeline, not supplying anything for \code{actions} (it's \code{NU
default) will have the same effect as using \code{stop_on_fail(stop_at = 1)}.
\if{html}{\out{}}\preformatted{small_table \%>\%
- col_vals_gt(columns = vars(a), value = 2)
+ col_vals_gt(columns = a, value = 2)
}\if{html}{\out{
}}
\if{html}{\out{}}\preformatted{## Error: Exceedance of failed test units where values in `a` should have
@@ -270,7 +270,7 @@ Here's the equivalent set of statements:
\if{html}{\out{
}}\preformatted{small_table \%>\%
col_vals_gt(
- columns = vars(a), value = 2,
+ columns = a, value = 2,
actions = stop_on_fail(stop_at = 1)
)
}\if{html}{\out{
}}
diff --git a/man/activate_steps.Rd b/man/activate_steps.Rd
index ca41ab711..31db1cd35 100644
--- a/man/activate_steps.Rd
+++ b/man/activate_steps.Rd
@@ -51,11 +51,11 @@ agent_1 <-
label = "An example."
) \%>\%
col_exists(
- columns = vars(date),
+ columns = date,
active = FALSE
) \%>\%
col_vals_regex(
- columns = vars(b),
+ columns = b,
regex = "[0-9]-[a-z]{3}-[0-9]{3}",
active = FALSE
) \%>\%
diff --git a/man/all_passed.Rd b/man/all_passed.Rd
index 601e2c263..3db914035 100644
--- a/man/all_passed.Rd
+++ b/man/all_passed.Rd
@@ -68,9 +68,9 @@ Validate that values in column \code{a} are always greater than 4.
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = tbl) \%>\%
- col_vals_gt(columns = vars(a), value = 3) \%>\%
- col_vals_lte(columns = vars(a), value = 10) \%>\%
- col_vals_increasing(columns = vars(a)) \%>\%
+ col_vals_gt(columns = a, value = 3) \%>\%
+ col_vals_lte(columns = a, value = 10) \%>\%
+ col_vals_increasing(columns = a) \%>\%
interrogate()
}\if{html}{\out{
}}
diff --git a/man/col_count_match.Rd b/man/col_count_match.Rd
index 4c06835f6..88c8c6581 100644
--- a/man/col_count_match.Rd
+++ b/man/col_count_match.Rd
@@ -38,10 +38,9 @@ Either a literal value for the number of columns, or, a table to compare
against the target table in terms of column count values. If supplying a
comparison table, it can either be a table object such as a data frame, a
tibble, a \code{tbl_dbi} object, or a \code{tbl_spark} object. Alternatively, a
-table-prep formula (\verb{~
}) or a function (`function()\if{html}{\out{
- `) can be used to lazily read in the comparison table
- at interrogation time.
-}}}
+table-prep formula (\verb{~ }) or a function (
+\verb{function() }) can be used to lazily read in the
+comparison table at interrogation time.}
\item{preconditions}{\emph{Input table modification prior to validation}
@@ -77,12 +76,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -109,7 +109,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -210,6 +210,20 @@ depending on the situation (the first produces a warning, the other
\code{stop()}s).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -397,12 +411,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_exists.Rd b/man/col_exists.Rd
index eabadc70c..20c3ca6de 100644
--- a/man/col_exists.Rd
+++ b/man/col_exists.Rd
@@ -8,7 +8,7 @@
\usage{
col_exists(
x,
- columns,
+ columns = NULL,
actions = NULL,
step_id = NULL,
label = NULL,
@@ -31,11 +31,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-`vector\if{html}{\out{}}|vars(\if{html}{\out{}})`` // \strong{required}
+\verb{} // \strong{required}
-One or more columns from the table in focus. This can be
-provided as a vector of column names using \code{c()} or bare column names
-enclosed in \code{\link[=vars]{vars()}}.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{actions}{\emph{Thresholds and actions for different states}
@@ -61,12 +61,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -93,7 +94,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -161,12 +162,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names, the result will be an expansion of
-validation steps to that number of column names (e.g., \code{vars(col_a, col_b)}
-will result in the entry of two validation steps). Aside from column names in
-quotes and in \code{vars()}, \strong{tidyselect} helper functions are available for
-specifying columns. They are: \code{starts_with()}, \code{ends_with()}, \code{contains()},
-\code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Actions}{
@@ -184,6 +190,21 @@ depending on the situation (the first produces a warning, the other
\code{stop()}s).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -210,7 +231,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_exists(
- columns = vars(a),
+ columns = a,
actions = action_levels(warn_at = 0.1, stop_at = 0.2),
label = "The `col_exists()` step.",
active = FALSE
@@ -221,7 +242,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_exists:
- columns: vars(a)
+ columns: c(a)
actions:
warn_fraction: 0.1
stop_fraction: 0.2
@@ -268,7 +289,7 @@ Validate that column \code{a} exists in the \code{tbl} table with \code{col_exis
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = tbl) \%>\%
- col_exists(columns = vars(a)) \%>\%
+ col_exists(columns = a) \%>\%
interrogate()
}\if{html}{\out{
}}
@@ -289,7 +310,7 @@ This way of using validation functions acts as a data filter. Data is
passed through but should \code{stop()} if there is a single test unit failing.
The behavior of side effects can be customized with the \code{actions} option.
-\if{html}{\out{
}}\preformatted{tbl \%>\% col_exists(columns = vars(a))
+\if{html}{\out{
}}\preformatted{tbl \%>\% col_exists(columns = a)
#> # A tibble: 6 x 2
#> a b
#>
@@ -307,7 +328,7 @@ The behavior of side effects can be customized with the \code{actions} option.
With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
-\if{html}{\out{}}\preformatted{expect_col_exists(tbl, columns = vars(a))
+\if{html}{\out{
}}\preformatted{expect_col_exists(tbl, columns = a)
}\if{html}{\out{
}}
}
@@ -316,7 +337,7 @@ time. This is primarily used in \strong{testthat} tests.
With the \verb{test_*()} form, we should get a single logical value returned to
us.
-\if{html}{\out{
}}\preformatted{tbl \%>\% test_col_exists(columns = vars(a))
+\if{html}{\out{
}}\preformatted{tbl \%>\% test_col_exists(columns = a)
#> [1] TRUE
}\if{html}{\out{
}}
}
@@ -342,12 +363,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_is_character.Rd b/man/col_is_character.Rd
index a933bf632..f16cec65e 100644
--- a/man/col_is_character.Rd
+++ b/man/col_is_character.Rd
@@ -31,10 +31,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{
} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{actions}{\emph{Thresholds and actions for different states}
@@ -60,12 +61,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -92,7 +94,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -162,12 +164,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names, the result will be an expansion of
-validation steps to that number of column names (e.g., \code{vars(col_a, col_b)}
-will result in the entry of two validation steps). Aside from column names in
-quotes and in \code{vars()}, \strong{tidyselect} helper functions are available for
-specifying columns. They are: \code{starts_with()}, \code{ends_with()}, \code{contains()},
-\code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Actions}{
@@ -185,6 +192,21 @@ happens. For the \verb{col_is_*()}-type functions, using \code{action_levels(war
situation (the first produces a warning, the other will \code{stop()}).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -211,7 +233,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_is_character(
- columns = vars(a),
+ columns = a,
actions = action_levels(warn_at = 0.1, stop_at = 0.2),
label = "The `col_is_character()` step.",
active = FALSE
@@ -222,7 +244,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_is_character:
- columns: vars(a)
+ columns: c(a)
actions:
warn_fraction: 0.1
stop_fraction: 0.2
@@ -269,7 +291,7 @@ Validate that column \code{b} has the \code{character} class.
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = tbl) \%>\%
- col_is_character(columns = vars(b)) \%>\%
+ col_is_character(columns = b) \%>\%
interrogate()
}\if{html}{\out{
}}
@@ -291,7 +313,7 @@ through but should \code{stop()} if there is a single test unit failing. The
behavior of side effects can be customized with the \code{actions} option.
\if{html}{\out{
}}\preformatted{tbl \%>\%
- col_is_character(columns = vars(b)) \%>\%
+ col_is_character(columns = b) \%>\%
dplyr::slice(1:5)
#> # A tibble: 5 x 2
#> a b
@@ -309,7 +331,7 @@ behavior of side effects can be customized with the \code{actions} option.
With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
-\if{html}{\out{
}}\preformatted{expect_col_is_character(tbl, columns = vars(b))
+\if{html}{\out{
}}\preformatted{expect_col_is_character(tbl, columns = b)
}\if{html}{\out{
}}
}
@@ -318,7 +340,7 @@ time. This is primarily used in \strong{testthat} tests.
With the \verb{test_*()} form, we should get a single logical value returned to
us.
-\if{html}{\out{
}}\preformatted{tbl \%>\% test_col_is_character(columns = vars(b))
+\if{html}{\out{
}}\preformatted{tbl \%>\% test_col_is_character(columns = b)
#> [1] TRUE
}\if{html}{\out{
}}
}
@@ -344,12 +366,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_is_date.Rd b/man/col_is_date.Rd
index a9dd83989..568b0516c 100644
--- a/man/col_is_date.Rd
+++ b/man/col_is_date.Rd
@@ -31,10 +31,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{
} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{actions}{\emph{Thresholds and actions for different states}
@@ -60,12 +61,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -92,7 +94,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -162,12 +164,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names, the result will be an expansion of
-validation steps to that number of column names (e.g., \code{vars(col_a, col_b)}
-will result in the entry of two validation steps). Aside from column names in
-quotes and in \code{vars()}, \strong{tidyselect} helper functions are available for
-specifying columns. They are: \code{starts_with()}, \code{ends_with()}, \code{contains()},
-\code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Actions}{
@@ -185,6 +192,21 @@ happens. For the \verb{col_is_*()}-type functions, using \code{action_levels(war
situation (the first produces a warning, the other will \code{stop()}).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -211,7 +233,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_is_date(
- columns = vars(a),
+ columns = a,
actions = action_levels(warn_at = 0.1, stop_at = 0.2),
label = "The `col_is_date()` step.",
active = FALSE
@@ -222,7 +244,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_is_date:
- columns: vars(a)
+ columns: c(a)
actions:
warn_fraction: 0.1
stop_fraction: 0.2
@@ -268,7 +290,7 @@ Validate that the column \code{date} has the \code{Date} class.
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = small_table) \%>\%
- col_is_date(columns = vars(date)) \%>\%
+ col_is_date(columns = date) \%>\%
interrogate()
}\if{html}{\out{
}}
@@ -290,7 +312,7 @@ through but should \code{stop()} if there is a single test unit failing. The
behavior of side effects can be customized with the \code{actions} option.
\if{html}{\out{
}}\preformatted{small_table \%>\%
- col_is_date(columns = vars(date)) \%>\%
+ col_is_date(columns = date) \%>\%
dplyr::slice(1:5)
#> # A tibble: 5 x 8
#> date_time date a b c d e f
@@ -308,7 +330,7 @@ behavior of side effects can be customized with the \code{actions} option.
With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
-\if{html}{\out{
}}\preformatted{expect_col_is_date(small_table, columns = vars(date))
+\if{html}{\out{
}}\preformatted{expect_col_is_date(small_table, columns = date)
}\if{html}{\out{
}}
}
@@ -317,7 +339,7 @@ time. This is primarily used in \strong{testthat} tests.
With the \verb{test_*()} form, we should get a single logical value returned to
us.
-\if{html}{\out{
}}\preformatted{small_table \%>\% test_col_is_date(columns = vars(date))
+\if{html}{\out{
}}\preformatted{small_table \%>\% test_col_is_date(columns = date)
#> [1] TRUE
}\if{html}{\out{
}}
}
@@ -343,12 +365,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_is_factor.Rd b/man/col_is_factor.Rd
index 8393c8e66..3bc0219e3 100644
--- a/man/col_is_factor.Rd
+++ b/man/col_is_factor.Rd
@@ -31,10 +31,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{
} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{actions}{\emph{Thresholds and actions for different states}
@@ -60,12 +61,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -92,7 +94,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -162,12 +164,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names, the result will be an expansion of
-validation steps to that number of column names (e.g., \code{vars(col_a, col_b)}
-will result in the entry of two validation steps). Aside from column names in
-quotes and in \code{vars()}, \strong{tidyselect} helper functions are available for
-specifying columns. They are: \code{starts_with()}, \code{ends_with()}, \code{contains()},
-\code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Actions}{
@@ -185,6 +192,21 @@ happens. For the \verb{col_is_*()}-type functions, using \code{action_levels(war
situation (the first produces a warning, the other will \code{stop()}).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -211,7 +233,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_is_factor(
- columns = vars(a),
+ columns = a,
actions = action_levels(warn_at = 0.1, stop_at = 0.2),
label = "The `col_is_factor()` step.",
active = FALSE
@@ -222,7 +244,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_is_factor:
- columns: vars(a)
+ columns: c(a)
actions:
warn_fraction: 0.1
stop_fraction: 0.2
@@ -274,7 +296,7 @@ Validate that the column \code{f} in the \code{tbl} object is of the \code{facto
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = tbl) \%>\%
- col_is_factor(columns = vars(f)) \%>\%
+ col_is_factor(columns = f) \%>\%
interrogate()
}\if{html}{\out{
}}
@@ -296,7 +318,7 @@ through but should \code{stop()} if there is a single test unit failing. The
behavior of side effects can be customized with the \code{actions} option.
\if{html}{\out{
}}\preformatted{tbl \%>\%
- col_is_factor(columns = vars(f)) \%>\%
+ col_is_factor(columns = f) \%>\%
dplyr::slice(1:5)
#> # A tibble: 5 x 8
#> date_time date a b c d e f
@@ -314,7 +336,7 @@ behavior of side effects can be customized with the \code{actions} option.
With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
-\if{html}{\out{
}}\preformatted{expect_col_is_factor(tbl, vars(f))
+\if{html}{\out{
}}\preformatted{expect_col_is_factor(tbl, f)
}\if{html}{\out{
}}
}
@@ -323,7 +345,7 @@ time. This is primarily used in \strong{testthat} tests.
With the \verb{test_*()} form, we should get a single logical value returned to
us.
-\if{html}{\out{
}}\preformatted{tbl \%>\% test_col_is_factor(columns = vars(f))
+\if{html}{\out{
}}\preformatted{tbl \%>\% test_col_is_factor(columns = f)
#> [1] TRUE
}\if{html}{\out{
}}
}
@@ -349,12 +371,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_is_integer.Rd b/man/col_is_integer.Rd
index 884e125aa..09eb320aa 100644
--- a/man/col_is_integer.Rd
+++ b/man/col_is_integer.Rd
@@ -31,10 +31,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{
} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{actions}{\emph{Thresholds and actions for different states}
@@ -60,12 +61,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -92,7 +94,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -162,12 +164,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names, the result will be an expansion of
-validation steps to that number of column names (e.g., \code{vars(col_a, col_b)}
-will result in the entry of two validation steps). Aside from column names in
-quotes and in \code{vars()}, \strong{tidyselect} helper functions are available for
-specifying columns. They are: \code{starts_with()}, \code{ends_with()}, \code{contains()},
-\code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Actions}{
@@ -185,6 +192,21 @@ happens. For the \verb{col_is_*()}-type functions, using \code{action_levels(war
situation (the first produces a warning, the other will \code{stop()}).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -211,7 +233,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_is_integer(
- columns = vars(a),
+ columns = a,
actions = action_levels(warn_at = 0.1, stop_at = 0.2),
label = "The `col_is_integer()` step.",
active = FALSE
@@ -222,7 +244,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_is_integer:
- columns: vars(a)
+ columns: c(a)
actions:
warn_fraction: 0.1
stop_fraction: 0.2
@@ -267,7 +289,7 @@ Validate that column \code{b} has the \code{integer} class.
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = tbl) \%>\%
- col_is_integer(columns = vars(b)) \%>\%
+ col_is_integer(columns = b) \%>\%
interrogate()
}\if{html}{\out{
}}
@@ -288,7 +310,7 @@ This way of using validation functions acts as a data filter. Data is passed
through but should \code{stop()} if there is a single test unit failing. The
behavior of side effects can be customized with the \code{actions} option.
-\if{html}{\out{
}}\preformatted{tbl \%>\% col_is_integer(columns = vars(b))
+\if{html}{\out{
}}\preformatted{tbl \%>\% col_is_integer(columns = b)
#> # A tibble: 6 x 2
#> a b
#>
@@ -306,7 +328,7 @@ behavior of side effects can be customized with the \code{actions} option.
With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
-\if{html}{\out{}}\preformatted{expect_col_is_integer(tbl, columns = vars(b))
+\if{html}{\out{
}}\preformatted{expect_col_is_integer(tbl, columns = b)
}\if{html}{\out{
}}
}
@@ -315,7 +337,7 @@ time. This is primarily used in \strong{testthat} tests.
With the \verb{test_*()} form, we should get a single logical value returned to
us.
-\if{html}{\out{
}}\preformatted{tbl \%>\% test_col_is_integer(columns = vars(b))
+\if{html}{\out{
}}\preformatted{tbl \%>\% test_col_is_integer(columns = b)
#> [1] TRUE
}\if{html}{\out{
}}
}
@@ -341,12 +363,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_is_logical.Rd b/man/col_is_logical.Rd
index d3bef5639..2003c7192 100644
--- a/man/col_is_logical.Rd
+++ b/man/col_is_logical.Rd
@@ -31,10 +31,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{
} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{actions}{\emph{Thresholds and actions for different states}
@@ -60,12 +61,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -92,7 +94,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -162,12 +164,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names, the result will be an expansion of
-validation steps to that number of column names (e.g., \code{vars(col_a, col_b)}
-will result in the entry of two validation steps). Aside from column names in
-quotes and in \code{vars()}, \strong{tidyselect} helper functions are available for
-specifying columns. They are: \code{starts_with()}, \code{ends_with()}, \code{contains()},
-\code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Actions}{
@@ -185,6 +192,21 @@ happens. For the \verb{col_is_*()}-type functions, using \code{action_levels(war
situation (the first produces a warning, the other will \code{stop()}).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -211,7 +233,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_is_logical(
- columns = vars(a),
+ columns = a,
actions = action_levels(warn_at = 0.1, stop_at = 0.2),
label = "The `col_is_logical()` step.",
active = FALSE
@@ -222,7 +244,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_is_logical:
- columns: vars(a)
+ columns: c(a)
actions:
warn_fraction: 0.1
stop_fraction: 0.2
@@ -269,7 +291,7 @@ Validate that the column \code{e} has the \code{logical} class.
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = small_table) \%>\%
- col_is_logical(columns = vars(e)) \%>\%
+ col_is_logical(columns = e) \%>\%
interrogate()
}\if{html}{\out{
}}
@@ -291,7 +313,7 @@ through but should \code{stop()} if there is a single test unit failing. The
behavior of side effects can be customized with the \code{actions} option.
\if{html}{\out{
}}\preformatted{small_table \%>\%
- col_is_logical(columns = vars(e)) \%>\%
+ col_is_logical(columns = e) \%>\%
dplyr::slice(1:5)
#> # A tibble: 5 x 8
#> date_time date a b c d e f
@@ -309,7 +331,7 @@ behavior of side effects can be customized with the \code{actions} option.
With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
-\if{html}{\out{
}}\preformatted{expect_col_is_logical(small_table, columns = vars(e))
+\if{html}{\out{
}}\preformatted{expect_col_is_logical(small_table, columns = e)
}\if{html}{\out{
}}
}
@@ -318,7 +340,7 @@ time. This is primarily used in \strong{testthat} tests.
With the \verb{test_*()} form, we should get a single logical value returned to
us.
-\if{html}{\out{
}}\preformatted{small_table \%>\% test_col_is_logical(columns = vars(e))
+\if{html}{\out{
}}\preformatted{small_table \%>\% test_col_is_logical(columns = e)
#> [1] TRUE
}\if{html}{\out{
}}
}
@@ -344,12 +366,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_is_numeric.Rd b/man/col_is_numeric.Rd
index 3b9096cad..61332bc9c 100644
--- a/man/col_is_numeric.Rd
+++ b/man/col_is_numeric.Rd
@@ -31,10 +31,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{
} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{actions}{\emph{Thresholds and actions for different states}
@@ -60,12 +61,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -92,7 +94,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -162,12 +164,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names, the result will be an expansion of
-validation steps to that number of column names (e.g., \code{vars(col_a, col_b)}
-will result in the entry of two validation steps). Aside from column names in
-quotes and in \code{vars()}, \strong{tidyselect} helper functions are available for
-specifying columns. They are: \code{starts_with()}, \code{ends_with()}, \code{contains()},
-\code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Actions}{
@@ -185,6 +192,21 @@ happens. For the \verb{col_is_*()}-type functions, using \code{action_levels(war
situation (the first produces a warning, the other will \code{stop()}).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -211,7 +233,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_is_numeric(
- columns = vars(a),
+ columns = a,
actions = action_levels(warn_at = 0.1, stop_at = 0.2),
label = "The `col_is_numeric()` step.",
active = FALSE
@@ -222,7 +244,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_is_numeric:
- columns: vars(a)
+ columns: c(a)
actions:
warn_fraction: 0.1
stop_fraction: 0.2
@@ -269,7 +291,7 @@ Validate that the column \code{d} has the \code{numeric} class.
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = small_table) \%>\%
- col_is_numeric(columns = vars(d)) \%>\%
+ col_is_numeric(columns = d) \%>\%
interrogate()
}\if{html}{\out{
}}
@@ -291,7 +313,7 @@ through but should \code{stop()} if there is a single test unit failing. The
behavior of side effects can be customized with the \code{actions} option.
\if{html}{\out{
}}\preformatted{small_table \%>\%
- col_is_numeric(columns = vars(d)) \%>\%
+ col_is_numeric(columns = d) \%>\%
dplyr::slice(1:5)
#> # A tibble: 5 x 8
#> date_time date a b c d e f
@@ -309,7 +331,7 @@ behavior of side effects can be customized with the \code{actions} option.
With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
-\if{html}{\out{
}}\preformatted{expect_col_is_numeric(small_table, columns = vars(d))
+\if{html}{\out{
}}\preformatted{expect_col_is_numeric(small_table, columns = d)
}\if{html}{\out{
}}
}
@@ -318,7 +340,7 @@ time. This is primarily used in \strong{testthat} tests.
With the \verb{test_*()} form, we should get a single logical value returned to
us.
-\if{html}{\out{
}}\preformatted{small_table \%>\% test_col_is_numeric(columns = vars(d))
+\if{html}{\out{
}}\preformatted{small_table \%>\% test_col_is_numeric(columns = d)
#> [1] TRUE
}\if{html}{\out{
}}
}
@@ -344,12 +366,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_is_posix.Rd b/man/col_is_posix.Rd
index da2efde82..64c6566c2 100644
--- a/man/col_is_posix.Rd
+++ b/man/col_is_posix.Rd
@@ -31,10 +31,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{
} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{actions}{\emph{Thresholds and actions for different states}
@@ -60,12 +61,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -92,7 +94,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -162,12 +164,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names, the result will be an expansion of
-validation steps to that number of column names (e.g., \code{vars(col_a, col_b)}
-will result in the entry of two validation steps). Aside from column names in
-quotes and in \code{vars()}, \strong{tidyselect} helper functions are available for
-specifying columns. They are: \code{starts_with()}, \code{ends_with()}, \code{contains()},
-\code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Actions}{
@@ -185,6 +192,21 @@ happens. For the \verb{col_is_*()}-type functions, using \code{action_levels(war
situation (the first produces a warning, the other will \code{stop()}).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -211,7 +233,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_is_posix(
- columns = vars(a),
+ columns = a,
actions = action_levels(warn_at = 0.1, stop_at = 0.2),
label = "The `col_is_posix()` step.",
active = FALSE
@@ -222,7 +244,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_is_posix:
- columns: vars(a)
+ columns: c(a)
actions:
warn_fraction: 0.1
stop_fraction: 0.2
@@ -269,7 +291,7 @@ Validate that the column \code{date_time} is indeed a date-time column.
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = small_table) \%>\%
- col_is_posix(columns = vars(date_time)) \%>\%
+ col_is_posix(columns = date_time) \%>\%
interrogate()
}\if{html}{\out{
}}
@@ -291,7 +313,7 @@ through but should \code{stop()} if there is a single test unit failing. The
behavior of side effects can be customized with the \code{actions} option.
\if{html}{\out{
}}\preformatted{small_table \%>\%
- col_is_posix(columns = vars(date_time)) \%>\%
+ col_is_posix(columns = date_time) \%>\%
dplyr::slice(1:5)
#> # A tibble: 5 x 8
#> date_time date a b c d e f
@@ -309,7 +331,7 @@ behavior of side effects can be customized with the \code{actions} option.
With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
-\if{html}{\out{
}}\preformatted{expect_col_is_posix(small_table, columns = vars(date_time))
+\if{html}{\out{
}}\preformatted{expect_col_is_posix(small_table, columns = date_time)
}\if{html}{\out{
}}
}
@@ -318,7 +340,7 @@ time. This is primarily used in \strong{testthat} tests.
With the \verb{test_*()} form, we should get a single logical value returned to
us.
-\if{html}{\out{
}}\preformatted{small_table \%>\% test_col_is_posix(columns = vars(date_time))
+\if{html}{\out{
}}\preformatted{small_table \%>\% test_col_is_posix(columns = date_time)
#> [1] TRUE
}\if{html}{\out{
}}
}
@@ -344,12 +366,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_schema.Rd b/man/col_schema.Rd
index 905673486..00daf5e7b 100644
--- a/man/col_schema.Rd
+++ b/man/col_schema.Rd
@@ -22,8 +22,8 @@ An option to use a table object to define the schema. If this is provided
then any values provided to \code{...} will be ignored. This can either be a
table object, a table-prep formula.This can be a table object such as a
data frame, a tibble, a \code{tbl_dbi} object, or a \code{tbl_spark} object.
-Alternatively, a table-prep formula (\verb{~
}) or a
-function (\verb{function() }) can be used to lazily read in
+Alternatively, a table-prep formula (\verb{~ }) or a
+function (\verb{function() }) can be used to lazily read in
the table at interrogation time.}
\item{.db_col_types}{\emph{Use R column types or database column types?}
@@ -139,8 +139,8 @@ example.
\seealso{
Other Utility and Helper Functions:
-\code{\link{affix_datetime}()},
\code{\link{affix_date}()},
+\code{\link{affix_datetime}()},
\code{\link{from_github}()},
\code{\link{has_columns}()},
\code{\link{stop_if_not}()}
diff --git a/man/col_schema_match.Rd b/man/col_schema_match.Rd
index aea64c3d8..05683362f 100644
--- a/man/col_schema_match.Rd
+++ b/man/col_schema_match.Rd
@@ -110,12 +110,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -142,7 +143,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -241,6 +242,20 @@ depending on the situation (the first produces a warning, the other
\code{stop()}s).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -429,12 +444,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_vals_between.Rd b/man/col_vals_between.Rd
index 0b8544b5b..603926f7f 100644
--- a/man/col_vals_between.Rd
+++ b/man/col_vals_between.Rd
@@ -55,10 +55,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{left}{\emph{Definition of left bound}
@@ -136,12 +137,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -168,7 +170,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -245,12 +247,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names to \code{columns}, the result will be an
-expansion of validation steps to that number of column names (e.g.,
-\code{vars(col_a, col_b)} will result in the entry of two validation steps). Aside
-from column names in quotes and in \code{vars()}, \strong{tidyselect} helper functions
-are available for specifying columns. They are: \code{starts_with()},
-\code{ends_with()}, \code{contains()}, \code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Missing Values}{
@@ -332,6 +339,23 @@ quarter of the total test units fails, the other \code{stop()}s at the same
threshold level).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+\item \code{"{.seg_col}"}: The current segment's column name
+\item \code{"{.seg_val}"}: The current segment's value/group
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -358,7 +382,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_vals_between(
- columns = vars(a),
+ columns = a,
left = 1,
right = 2,
inclusive = c(TRUE, FALSE),
@@ -375,7 +399,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_vals_between:
- columns: vars(a)
+ columns: c(a)
left: 1.0
right: 2.0
inclusive:
@@ -433,7 +457,7 @@ are \code{NA} values, we'll choose to let those pass validation by setting
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = small_table) \%>\%
col_vals_between(
- columns = vars(c),
+ columns = c,
left = 1, right = 9,
na_pass = TRUE
) \%>\%
@@ -459,7 +483,7 @@ behavior of side effects can be customized with the \code{actions} option.
\if{html}{\out{
}}\preformatted{small_table \%>\%
col_vals_between(
- columns = vars(c),
+ columns = c,
left = 1, right = 9,
na_pass = TRUE
) \%>\%
@@ -474,7 +498,7 @@ With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
\if{html}{\out{
}}\preformatted{expect_col_vals_between(
- small_table, columns = vars(c),
+ small_table, columns = c,
left = 1, right = 9,
na_pass = TRUE
)
@@ -488,7 +512,7 @@ us.
\if{html}{\out{
}}\preformatted{small_table \%>\%
test_col_vals_between(
- columns = vars(c),
+ columns = c,
left = 1, right = 9,
na_pass = TRUE
)
@@ -505,7 +529,7 @@ values are \code{9} and they now fall outside of the upper (or right) bound.
\if{html}{\out{
}}\preformatted{small_table \%>\%
test_col_vals_between(
- columns = vars(c), left = 1, right = 9,
+ columns = c, left = 1, right = 9,
inclusive = c(TRUE, FALSE),
na_pass = TRUE
)
@@ -536,12 +560,12 @@ Other validation functions:
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_vals_decreasing.Rd b/man/col_vals_decreasing.Rd
index fc02d3a42..1bcededc5 100644
--- a/man/col_vals_decreasing.Rd
+++ b/man/col_vals_decreasing.Rd
@@ -52,10 +52,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{
} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{allow_stationary}{\emph{Allowance for stationary pauses in values}
@@ -128,12 +129,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -160,7 +162,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -232,12 +234,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names to \code{columns}, the result will be an
-expansion of validation steps to that number of column names (e.g.,
-\code{vars(col_a, col_b)} will result in the entry of two validation steps). Aside
-from column names in quotes and in \code{vars()}, \strong{tidyselect} helper functions
-are available for specifying columns. They are: \code{starts_with()},
-\code{ends_with()}, \code{contains()}, \code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Missing Values}{
@@ -319,6 +326,23 @@ quarter of the total test units fails, the other \code{stop()}s at the same
threshold level).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+\item \code{"{.seg_col}"}: The current segment's column name
+\item \code{"{.seg_val}"}: The current segment's value/group
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -345,7 +369,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_vals_decreasing(
- columns = vars(a),
+ columns = a,
allow_stationary = TRUE,
increasing_tol = 0.5,
na_pass = TRUE,
@@ -361,7 +385,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_vals_decreasing:
- columns: vars(a)
+ columns: c(a)
allow_stationary: true
increasing_tol: 0.5
na_pass: true
@@ -430,7 +454,7 @@ to \code{TRUE}).
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = game_revenue_2) \%>\%
col_vals_decreasing(
- columns = vars(time_left),
+ columns = time_left,
allow_stationary = TRUE
) \%>\%
interrogate()
@@ -455,7 +479,7 @@ behavior of side effects can be customized with the \code{actions} option.
\if{html}{\out{
}}\preformatted{game_revenue_2 \%>\%
col_vals_decreasing(
- columns = vars(time_left),
+ columns = time_left,
allow_stationary = TRUE
) \%>\%
dplyr::select(time_left) \%>\%
@@ -475,7 +499,7 @@ time. This is primarily used in \strong{testthat} tests.
\if{html}{\out{
}}\preformatted{expect_col_vals_decreasing(
game_revenue_2,
- columns = vars(time_left),
+ columns = time_left,
allow_stationary = TRUE
)
}\if{html}{\out{
}}
@@ -488,7 +512,7 @@ us.
\if{html}{\out{
}}\preformatted{game_revenue_2 \%>\%
test_col_vals_decreasing(
- columns = vars(time_left),
+ columns = time_left,
allow_stationary = TRUE
)
#> [1] TRUE
@@ -519,12 +543,12 @@ Other validation functions:
\code{\link{col_vals_between}()},
\code{\link{col_vals_equal}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_vals_equal.Rd b/man/col_vals_equal.Rd
index 237e3e164..d812e6ef8 100644
--- a/man/col_vals_equal.Rd
+++ b/man/col_vals_equal.Rd
@@ -49,10 +49,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{
} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{value}{\emph{Value for comparison}
@@ -113,12 +114,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -145,7 +147,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -215,12 +217,17 @@ formally tested (so be mindful of this when using unsupported backends with
\section{Column Names}{
-If providing multiple column names to \code{columns}, the result will be an
-expansion of validation steps to that number of column names (e.g.,
-\code{vars(col_a, col_b)} will result in the entry of two validation steps). Aside
-from column names in quotes and in \code{vars()}, \strong{tidyselect} helper functions
-are available for specifying columns. They are: \code{starts_with()},
-\code{ends_with()}, \code{contains()}, \code{matches()}, and \code{everything()}.
+\code{columns} may be a single column (as symbol \code{a} or string \code{"a"}) or a vector
+of columns (\code{c(a, b, c)} or \code{c("a", "b", "c")}). \code{{tidyselect}} helpers
+are also supported, such as \code{contains("date")} and \code{where(is.double)}. If
+passing an \emph{external vector} of columns, it should be wrapped in \code{all_of()}.
+
+When multiple columns are selected by \code{columns}, the result will be an
+expansion of validation steps to that number of columns (e.g.,
+\code{c(col_a, col_b)} will result in the entry of two validation steps).
+
+Previously, columns could be specified in \code{vars()}. This continues to work,
+but \code{c()} offers the same capability and supersedes \code{vars()} in \code{columns}.
}
\section{Missing Values}{
@@ -302,6 +309,23 @@ quarter of the total test units fails, the other \code{stop()}s at the same
threshold level).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+\item \code{"{.seg_col}"}: The current segment's column name
+\item \code{"{.seg_val}"}: The current segment's value/group
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -328,7 +352,7 @@ R statement:
\if{html}{\out{}}\preformatted{agent \%>\%
col_vals_equal(
- columns = vars(a),
+ columns = a,
value = 1,
na_pass = TRUE,
preconditions = ~ . \%>\% dplyr::filter(a < 10),
@@ -343,7 +367,7 @@ YAML representation:
\if{html}{\out{
}}\preformatted{steps:
- col_vals_equal:
- columns: vars(a)
+ columns: c(a)
value: 1.0
na_pass: true
preconditions: ~. \%>\% dplyr::filter(a < 10)
@@ -398,7 +422,7 @@ units, one for each row).
\if{html}{\out{
}}\preformatted{agent <-
create_agent(tbl = tbl) \%>\%
- col_vals_equal(columns = vars(a), value = 5) \%>\%
+ col_vals_equal(columns = a, value = 5) \%>\%
interrogate()
}\if{html}{\out{
}}
@@ -420,7 +444,7 @@ through but should \code{stop()} if there is a single test unit failing. The
behavior of side effects can be customized with the \code{actions} option.
\if{html}{\out{
}}\preformatted{tbl \%>\%
- col_vals_equal(columns = vars(a), value = 5) \%>\%
+ col_vals_equal(columns = a, value = 5) \%>\%
dplyr::pull(a)
#> [1] 5 5 5 5 5 5
}\if{html}{\out{
}}
@@ -431,7 +455,7 @@ behavior of side effects can be customized with the \code{actions} option.
With the \verb{expect_*()} form, we would typically perform one validation at a
time. This is primarily used in \strong{testthat} tests.
-\if{html}{\out{
}}\preformatted{expect_col_vals_equal(tbl, columns = vars(a), value = 5)
+\if{html}{\out{
}}\preformatted{expect_col_vals_equal(tbl, columns = a, value = 5)
}\if{html}{\out{
}}
}
@@ -440,7 +464,7 @@ time. This is primarily used in \strong{testthat} tests.
With the \verb{test_*()} form, we should get a single logical value returned to
us.
-\if{html}{\out{
}}\preformatted{test_col_vals_equal(tbl, columns = vars(a), value = 5)
+\if{html}{\out{
}}\preformatted{test_col_vals_equal(tbl, columns = a, value = 5)
#> [1] TRUE
}\if{html}{\out{
}}
}
@@ -468,12 +492,12 @@ Other validation functions:
\code{\link{col_vals_between}()},
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_expr}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_vals_expr.Rd b/man/col_vals_expr.Rd
index f065d303c..ad2afea65 100644
--- a/man/col_vals_expr.Rd
+++ b/man/col_vals_expr.Rd
@@ -83,12 +83,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar
} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector} // \emph{default:} \code{NULL} (\code{optional})
-An optional label for the validation step. This label appears in the
-\emph{agent} report and, for the best appearance, it should be kept quite short.}
+Optional label for the validation step. This label appears in the \emph{agent}
+report and, for the best appearance, it should be kept quite short. See
+the \emph{Labels} section for more information.}
\item{brief}{\emph{Brief description for the validation step}
@@ -115,7 +116,7 @@ be used with \code{.} (serving as the input data table) to evaluate to a single
logical value. With this approach, the \strong{pointblank} function
\code{\link[=has_columns]{has_columns()}} can be used to determine whether to make a validation step
active on the basis of one or more columns existing in the table
-(e.g., \code{~ . \%>\% has_columns(vars(d, e))}).}
+(e.g., \code{~ . \%>\% has_columns(c(d, e))}).}
\item{object}{\emph{A data table for expectations or tests}
@@ -252,6 +253,23 @@ quarter of the total test units fails, the other \code{stop()}s at the same
threshold level).
}
+\section{Labels}{
+
+
+\code{label} may be a single string or a character vector that matches the number
+of expanded steps. \code{label} also supports \code{{glue}} syntax and exposes the
+following dynamic variables contextualized to the current step:
+\itemize{
+\item \code{"{.step}"}: The validation step name
+\item \code{"{.col}"}: The current column name
+\item \code{"{.seg_col}"}: The current segment's column name
+\item \code{"{.seg_val}"}: The current segment's value/group
+}
+
+The glue context also supports ordinary expressions for further flexibility
+(e.g., \code{"{toupper(.step)}"}) as long as they return a length-1 string.
+}
+
\section{Briefs}{
@@ -438,12 +456,12 @@ Other validation functions:
\code{\link{col_vals_between}()},
\code{\link{col_vals_decreasing}()},
\code{\link{col_vals_equal}()},
-\code{\link{col_vals_gte}()},
\code{\link{col_vals_gt}()},
+\code{\link{col_vals_gte}()},
\code{\link{col_vals_in_set}()},
\code{\link{col_vals_increasing}()},
-\code{\link{col_vals_lte}()},
\code{\link{col_vals_lt}()},
+\code{\link{col_vals_lte}()},
\code{\link{col_vals_make_set}()},
\code{\link{col_vals_make_subset}()},
\code{\link{col_vals_not_between}()},
diff --git a/man/col_vals_gt.Rd b/man/col_vals_gt.Rd
index ed4d4bb34..37fc5c40e 100644
--- a/man/col_vals_gt.Rd
+++ b/man/col_vals_gt.Rd
@@ -49,10 +49,11 @@ commonly created with \code{\link[=create_agent]{create_agent()}}.}
\item{columns}{\emph{The target columns}
-\verb{} // \strong{required}
+\verb{} // \strong{required}
-The column (or a set of columns, provided as a character vector) to which
-this validation should be applied.}
+A column-selecting expression, as one would use inside \code{dplyr::select()}.
+Specifies the column (or a set of columns) to which this validation should
+be applied. See the \emph{Column Names} section for more information.}
\item{value}{\emph{Value for comparison}
@@ -113,12 +114,13 @@ produce (influenced by the number of \code{columns} provided), (2) be an ID
string not used in any previous validation step, and (3) be a vector with
unique values.}
-\item{label}{\emph{An optional label for the validation step}
+\item{label}{\emph{Optional label for the validation step}
-\verb{scalar} // \emph{default:} \code{NULL} (\code{optional})
+\verb{vector