Releases: wranglezone/stbl
Releases · wranglezone/stbl
Release list
stbl 0.4.0
Breaking changes
to_df()andto_lst()now error if extra arguments are passed in.... Previously, these extra arguments were silently discarded (#200).to_chr()now converts named functions to a string representing their name instead of erroring. Package functions are returned as"pkg::fn"(e.g.,to_chr(mean)returns"base::mean"). Anonymous functions still produce an informative error. This behavior extends toto_chr_scalar(),stabilize_chr(), andstabilize_chr_scalar()(#251).
New functions
- New
pkg_inform()andpkg_warn()signal classed messages and warnings, respectively, with an opinionated class hierarchy, mirroringpkg_abort(). Newexpect_pkg_message_classes()andexpect_pkg_warning_classes()test that the expected classes are thrown, andexpect_pkg_message_snapshot()andexpect_pkg_warning_snapshot()snapshot-test the full output in one step (#213). - New function
to()coercesxto the type of its.toargument.stbl_to()is also registered as a C callable in a new public C API (#182). - New
to_fn(),are_fn_ish(), andis_fn_ish()add thefntype family to stbl.to_fn()coerces strings and symbols to functions.is_fn_ish()checks whether a single object can be safely coerced to a function.are_fn_ish()checks each element of a character vector for syntactic fn-ishness (bare name or"pkg::fn"form) (#250).
Bug fixes
expect_pkg_error_snapshot(),expect_pkg_message_snapshot(), andexpect_pkg_warning_snapshot()now produce stable snapshots when run underdevtools::test_coverage_active_file().specify_cls()and relatedspecify_*()functions now also produce stable function-body snapshots under coverage (#253).expect_pkg_message_classes()andexpect_pkg_warning_classes()now support assignments insideobject(e.g.result <- fn_that_warns()).expect_pkg_message_snapshot()andexpect_pkg_warning_snapshot()inherit the same fix (#234).
Other changes
are_*_ish(),to_*(),stabilize_dbl(), andstabilize_int()are all significantly faster for large vectors, with benchmarks showing roughly 3–20× throughput improvements (#217, #218, #219, #220, #221, #226, #239).- The
are_*_ish(),to_*(), and range-check functions are now registered as C callables, as are the*_to_chrand*_to_fctfamilies (stbl_chr_to_fct(),stbl_dbl_to_chr(),stbl_dbl_are_chrish(),stbl_fct_to_chr(),stbl_fct_are_chrish(),stbl_int_to_chr(),stbl_int_are_chrish(),stbl_int_to_fct(),stbl_lgl_to_chr(), andstbl_lgl_are_chrish()) (#235, #237, #241). is_fct_ish()now accepts amax_levelsargument to limit the number of unique non-NAlevels (#231).
{qcthat} Reports
Milestone
✅ A qcthat issue test matrix with 1 milestone, 18 issues, and 262 tests
└─█─Milestone: v0.4.0 (18 issues, 262 tests)
├─☑️─Bug 253: `expect_pkg_error_snapshot()` vs coverage
│ ├─✅─.is_covr_count_call() identifies covr counter calls (#253)
│ └─✅─.strip_covr_from_expr() removes covr counter wrappers (#253)
├─☑️─Task 226: chore: complete C optimization for are_*_ish() and to_*() methods
│ ├─✅─.dbl_to_lgl() converts 0 to FALSE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() converts non-zero to TRUE with valid TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() passes NA and NaN through; valid always TRUE (#226, #237)
│ ├─✅─.dbl_to_lgl() handles integer input; valid always TRUE (#226, #237)
│ ├─✅─.int_to_dbl() converts integers to doubles; valid always TRUE (#226, #237)
│ ├─✅─.int_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.int_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts TRUE to 1.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() converts FALSE to 0.0; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lgl_are_dblish() returns all TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts TRUE to 1L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() converts FALSE to 0L; valid TRUE (#226, #237)
│ ├─✅─.lgl_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.cpx_to_dbl() extracts real part when Im is zero (#226, #237)
│ ├─✅─.cpx_to_dbl() passes NA complex through as NA_real; valid TRUE (#226, #237)
│ ├─✅─.cpx_to_dbl() returns real part and valid FALSE for non-zero Im (#226, #237)
│ ├─✅─.cpx_to_int() converts whole-number complex with Im 0 (#226, #237)
│ ├─✅─.cpx_to_int() passes NA complex through; flags FALSE (#226, #237)
│ ├─✅─.cpx_to_int() marks non-zero Im as non_number (#226, #237)
│ ├─✅─.cpx_to_int() marks fractional real part as bad_precision (#226, #237)
│ ├─✅─.fct_to_dbl() converts numeric factor levels to doubles (#226, #237)
│ ├─✅─.fct_to_dbl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_dbl() marks non-numeric levels as not valid (#226, #237)
│ ├─✅─.fct_to_int() converts whole-number factor levels to integers (#226, #237)
│ ├─✅─.fct_to_int() passes NA factor element through; flags FALSE (#226, #237)
│ ├─✅─.fct_to_int() marks non-integer levels correctly (#226, #237)
│ ├─✅─.fct_to_lgl() converts TRUE/FALSE levels (#226, #237)
│ ├─✅─.fct_to_lgl() passes NA factor element through; valid TRUE (#226, #237)
│ ├─✅─.fct_to_lgl() marks non-logical levels as not valid (#226, #237)
│ ├─✅─.chr_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.chr_are_fctish() checks membership in levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.chr_are_fctish() treats to_na values as fctish (#226, #237)
│ ├─✅─.fct_are_fctish() returns all TRUE when levels is NULL (#226, #237)
│ ├─✅─.fct_are_fctish() checks factor level membership in target levels (#226, #237)
│ ├─✅─.fct_are_fctish() treats NA as fctish regardless of levels (#226, #237)
│ ├─✅─.lst_to_dbl() converts a flat list of numeric/lgl/int scalars (#226, #237)
│ ├─✅─.lst_to_dbl() converts numeric character strings (#226, #237)
│ ├─✅─.lst_to_dbl() marks non-parseable character strings as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts complex with Im == 0 (#226, #237)
│ ├─✅─.lst_to_dbl() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_dbl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_dbl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts a flat list of integer/logical scalars (#226, #237)
│ ├─✅─.lst_to_int() converts whole-number doubles (#226, #237)
│ ├─✅─.lst_to_int() converts integer-valued character strings (#226, #237)
│ ├─✅─.lst_to_int() marks fractional character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-number character strings as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts complex with Im == 0 and whole Re (#226, #237)
│ ├─✅─.lst_to_int() marks complex with Im != 0 as not valid (#226, #237)
│ ├─✅─.lst_to_int() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_int() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_int() marks fractional doubles as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_int() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts a flat list of lgl/int/dbl scalars (#226, #237)
│ ├─✅─.lst_to_lgl() converts lgl-ish character strings (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-lgl character strings as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() converts factor elements via their level strings (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-coercible single-element as not valid (#226, #237)
│ ├─✅─.lst_to_lgl() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_chr() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_chr() converts non-character atomic scalars to strings (#226, #237, #239)
│ ├─✅─.lst_to_chr() converts factor elements via their level labels (#226, #237, #239)
│ ├─✅─.lst_to_chr() marks non-character single-element vectors as not valid (#226, #237)
│ ├─✅─.lst_to_chr() marks non-scalar elements in multi-element lists as not valid (#226, #237)
│ ├─✅─.lst_to_fct() passes character scalars through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() passes NA_character_ through; valid TRUE (#226, #237)
│ ├─✅─.lst_to_fct() marks non-character scalars as not valid (#226, #237)
│ ├─✅─.lst_to_fct() marks factor elements as valid (#226, #237)
│ ├─✅─.lst_to_fct() marks non-character/factor single-element vectors as not valid (#226, #237)
│ └─✅─.lst_to_fct() marks non-scalar elements in multi-element lists as not valid (#226, #237)
├─☑️─Issue 221: C optimization: .are_not_dbl_ish_chr() — single-pass character-to-double failure detector
│ ├─✅─.chr_to_dbl() converts numeric strings (#221, #237)
│ ├─✅─.chr_to_dbl() converts Inf strings (#221, #237)
│ ├─✅─.chr_to_dbl() passes NA through as valid (#221, #237)
│ └─✅─.chr_to_dbl() marks invalid strings as not valid (#221, #237)
├─☑️─Task 220: C optimization: .find_failures() / %&&% — inline min/max range checks
│ ├─✅─.check_min_dbl() returns NULL when all values pass (#220)
│ ├─✅─.check_min_dbl() returns failure indices for values below min (#220)
│ ├─✅─.check_min_dbl() treats NA as passing (#220)
│ ├─✅─.check_min_dbl() handles integer input (#22...
stbl 0.3.0
Breaking changes
to_chr_scalar(),to_dbl_scalar(),to_fct_scalar(),to_int_scalar(),to_lgl_scalar(),stabilize_chr_scalar(),stabilize_dbl_scalar(),stabilize_fct_scalar(),stabilize_int_scalar(),stabilize_lgl_scalar(),specify_chr_scalar(),specify_dbl_scalar(),specify_fct_scalar(),specify_int_scalar(), andspecify_lgl_scalar()(and their synonyms) now default toallow_null = FALSEandallow_zero_length = FALSE. Passallow_null = TRUEorallow_zero_length = TRUEto restore the previous behavior (#189, #197).
Potential breaking changes
- Several conditions that formerly included a subclass of "stbl-error-must" no longer include that subclass. This only occurs when "stbl-error-must" was not the most specific subclass (i.e., when a more specific subclass was already included), and therefore should not impact most if any code (#136).
New features
- New long-form and British-spelling synonym functions for all class functions. For example,
to_character()is a synonym forto_chr(),specify_logical()forspecify_lgl(), andstabilise_*()for allstabilize_*()functions (#164, #167). - New
expect_pkg_error_classes()checks that an error with the expected set of classes is thrown bypkg_abort(), andexpect_pkg_error_snapshot()snapshot-tests the full error output in one step by combiningexpect_snapshot()withexpect_pkg_error_classes()(#136, #188). Newpkg_abort()throws errors with a standardized, opinionated collection of classes (#136). - New specification functions:
specify_*()creates a"stbl_specified_fn", a call to the correspondingstabilize_*()function with arguments pre-filled. For example,stabilize_email <- specify_chr(regex = "^[^@]+@[^@]+\\.[^@]+$")creates astabilize_email()function that validates email addresses (#147, #148, #149, #150, #151, #153, #161). - New
stabilize_df()andspecify_df()validate data frame structure and contents (#142). - New
stabilize_lst()andspecify_lst()validate list structure and contents and create pre-configured validators for nested validation (#110, #204). - New
stabilize_present()validates that a value is non-NULLwithout imposing any type constraints (#110). - New
to_df()(and synonymto_data_frame()) coerces compatible objects to a data frame, including named lists and named atomic vectors (e.g.,to_df(letters)), with informative errors for incompatible inputs such as jagged lists (#142, #201, #203). - New
to_lst()(and synonymto_list()) coerces an object to a list, with conditional checks forNULLand functions (#157, #166).
Other changes
- Revised the "Getting started with stbl" vignette to clarify what happens at each step (#139, #143, #144).
- Clarified error messages (#176, #177).
{qcthat} Reports
Milestone
✅ A qcthat issue test matrix with 1 milestone, 20 issues, and 182 tests
└─█─Milestone: v0.3.0 (20 issues, 182 tests)
├─☑️─Bug 204: bug: `stabilize_lst()` with nested list
│ ├─✅─specify_df() accepts columns named 'x_arg', 'call', 'x_class' (#204)
│ ├─✅─specify_lst() accepts elements named 'x_arg', 'call', 'x_class' (#204)
│ └─✅─stabilize_lst() with nested specify_lst() propagates errors correctly (#204)
├─☑️─Feature 161: Show actual args in `specify_*()`
│ ├─✅─specify_cls builds the expected function with at least one arg (#150, #161)
│ ├─✅─specify_cls builds the expected function snapshot with at least one arg (#150, #161)
│ └─✅─The function built via specify_cls errors informatively for duplicated args (#150, #153, #161)
├─☑️─Feature 157: Implement `to_list()`
│ ├─✅─to_lst() works for lists (#157, #166)
│ ├─✅─to_lst() works for NULL (#157)
│ ├─✅─to_lst() respects allow_null (#157)
│ ├─✅─to_lst() works for character vectors (#157)
│ ├─✅─to_lst() errors by default for functions (#157)
│ ├─✅─to_lst() works for functions with coerce_function = TRUE (#157)
│ ├─✅─to_lst() errors informatively for primitives (#157)
│ └─✅─to_list() exists (#157, #166)
├─☑️─Feature 153: Better handling of `...` in `specify_*()`
│ └─✅─The function built via specify_cls errors informatively for duplicated args (#150, #153, #161)
├─☑️─Feature 151: Implement `specify_lgl()`
│ ├─✅─specify_lgl can build a checker (#151)
│ └─✅─specify_lgl_scalar can build a value checker (#151)
├─☑️─Feature 150: Implement `specify_fct()`
│ ├─✅─specify_cls builds the expected function with no args (#150)
│ ├─✅─specify_cls builds the expected function snapshot with no args (#150)
│ ├─✅─specify_cls builds the expected function with at least one arg (#150, #161)
│ ├─✅─specify_cls builds the expected function snapshot with at least one arg (#150, #161)
│ ├─✅─The function built via specify_cls errors informatively for duplicated args (#150, #153, #161)
│ ├─✅─specify_cls can build a scalar specifier (#150)
│ ├─✅─specify_cls builds the expected scalar function snapshot (#150)
│ ├─✅─specify_fct can build a level checker (#150)
│ └─✅─specify_fct_scalar can build a level checker (#150)
├─☑️─Feature 149: Implement `specify_int()`
│ ├─✅─specify_int can build a value checker (#149)
│ └─✅─specify_int_scalar can build a value checker (#149)
├─☑️─Feature 148: Implement `specify_dbl()`
│ ├─✅─specify_dbl can build a value checker (#148)
│ └─✅─specify_dbl_scalar can build a value checker (#148)
├─☑️─Feature 147: Implement `specify_chr()`
│ ├─✅─specify_chr can build a regex checker (#147)
│ └─✅─specify_chr_scalar can build a regex checker (#147)
├─☑️─Feature 142: Implement `stabilize_df()`
│ ├─✅─specify_df() creates a working validator (#142)
│ ├─✅─specify_df() errors when required column is missing (#142)
│ ├─✅─specify_df() passes through .min_rows, .max_rows (#142)
│ ├─✅─specify_df() passes through .col_names (#142)
│ ├─✅─specify_df() allows additional specs via ... (#142)
│ ├─✅─specify_data_frame() exists (#142)
│ ├─✅─stabilize_df() returns NULL for NULL input by default (#142)
│ ├─✅─stabilize_df() respects .allow_null (#142)
│ ├─✅─stabilize_df() errors for non-coercible input (#142)
│ ├─✅─stabilize_df() coerces a named list to a data frame (#142)
│ ├─✅─stabilize_df() returns a valid data frame unchanged (#142)
│ ├─✅─stabilize_df() coerces compatible column types (#142)
│ ├─✅─stabilize_df() errors when required column is missing (#142)
│ ├─✅─stabilize_df() errors informatively when column fails validation (#142)
│ ├─✅─stabilize_df() errors on extra columns by default (#142)
│ ├─✅─stabilize_df() allows extra columns with .extra_cols (#142)
│ ├─✅─stabilize_df() validates extra columns with .extra_cols (#142)
│ ├─✅─stabilize_df() enforces .min_rows (#142)
│ ├─✅─stabilize_df() enforces .min_rows (snapshot) (#142)
│ ├─✅─stabilize_df() enforces .max_rows (#142)
│ ├─✅─stabilize_df() enforces .max_rows (snapshot) (#142)
│ ├─✅─stabilize_df() passes with valid row counts (#142)
│ ├─✅─stabilize_df() enforces .col_names (#142)
│ ├─✅─stabilize_df() enforces .col_names (snapshot) (#142)
│ ├─✅─stabilize_df() allows .col_names alongside ... specs (#142)
│ ├─✅─stabilize_df() preserves data frame class after column coercion (#142)
│ ├─✅─stabilize_df() works with no column specs and .extra_cols (#142)
│ ├─✅─stabilize_df() with unnamed specs errors informatively (#142)
│ ├─✅─stabilise_df() exists (#142)
│ ├─✅─stabilize_data_frame() exists (#142)
│ └─✅─stabilise_data_frame() exists (#142)
├─☑️─Feature 136: Export error functions
│ ├─✅─.compile_pkg_condition_classes() compiles condition class chains (#136)
│ ├─✅─.compile_pkg_error_classes() compiles error class chains (#136)
│ ├─✅─pkg_abort() throws the expected error (#136)
│ ├─✅─pkg_abort() uses parent when provided (#136)
│ ├─✅─pkg_abort() passes dots to cli_abort() (#136)
│ ├─✅─pkg_abort() uses message_env when provided (#136)
│ └─✅─expect_pkg_error_classes() tests expressions for classes (#136)
├─☑️─Feature 203: feat: better `to_df()`
│ ├─✅─.check_all_named() works (#203)
│ ├─✅─.check_not_jagged() works (#203)
│ ├─✅─to_df() errors for an unnamed list (#203)
│ ├─✅─to_df() coerces named vector types to a data frame (#203)
│ └─✅─to_df() errors for inline vector expressions (#203)
├─☑️─Feature 110: Implement `stabilize_lst()`
│ ├─✅─specify_lst() creates a working specifier (#110)
│ ├─✅─specify_lst() respects pre-configured element specs (#110)
│ ├─✅─specify_lst() supports element specs named 'x' and 'y' (#110)
│ ├─✅─specify_lst() passes through additional element specs from ... (#110)
│ ├─✅─specify_lst() respects .min_size (#110)
│ ├─✅─specify_lst() respects .allow_null (#110)
│ ├─✅─specify_list() exists (#110)
│ ├─✅─stabilize_lst() returns NULL for NULL input by default (#110)
│ ├─✅─stabilize_lst() respects .allow_null (#110)
│ ├─✅─stabilize_lst() returns a valid list unchanged (#110)
│ ├─✅─stabilize_lst() validates required named elements (#110)
│ ├─✅─stabilize_lst() errors when required named element is missing (#110)
│ ├─✅─stabilize_lst() errors informatively when element fails validation (#110)
│ ├─✅─stabilize_lst() errors on extra named elements by default (#110)
│ ├─✅─stabilize_lst() validates extra named elements with .named (#110)
│ ├─✅─stabilize_lst() errors on unnamed elements by default (#110)
│ ├─✅─stabilize_lst() validates unnamed elements with .unnamed (#110)
│ ├─✅─stabilize_lst() handles mixed named/unnamed lists (#110)
│ ├─✅─stabilize_lst() enforces .min_size (#110)
│ ├─✅─stabilize_lst() enforces .max_size (#110)
│ ├─✅─stabilize_lst() validates nested lists (#110)
│ ├─✅─stabilize_lst() with unnamed specs errors informatively (#110)
│ ├─✅─.check_duplicate_names(): errors on duplicate names by default (#110)
│ ├─✅─.check_duplicate_names(): allows duplicates with .allow_duplicate_names = TRUE (#110)
│ ├─✅─.check_duplica...
stbl 0.2.0
New features
- New predicate functions check if an object can be safely coerced to a specific type. The
is_*_ish()family (is_chr_ish(),is_dbl_ish(),is_fct_ish(),is_int_ish(), andis_lgl_ish()) checks the entire object at once. Theare_*_ish()family (are_chr_ish(),are_dbl_ish(),are_fct_ish(),are_int_ish(), andare_lgl_ish()) checks each element of a vector individually (#23, #93). - New functions for working with doubles are available:
to_dbl(),to_dbl_scalar(),stabilize_dbl(), andstabilize_dbl_scalar()(#23). stabilize_chr()now accepts patterns fromstringr::regex(),stringr::fixed(), andstringr::coll()(#87), and can generate more informative error messages for regex failures via the newregex_must_match()andregex_must_not_match()helper functions (#52, #85, #86, #89).
Minor improvements and fixes
- Error messages are now clearer and more standardized throughout the package (#95).
to_*()functions now consistently flatten list-like inputs when no information would be lost in the process (#128).to_fct()now lists the allowed values in its error message when a value is not in the expected set, making it easier to debug (#67).to_lgl()now coerces character representations of numbers (e.g., "0" and "1") toFALSEandTRUErespectively (#30).
Documentation
stbl 0.1.1
- Formatting changes in DESCRIPTION and examples.