Skip to content

Releases: wranglezone/stbl

stbl 0.4.0

Choose a tag to compare

@jonthegeek jonthegeek released this 28 Jul 14:16
b88337e

Breaking changes

  • to_df() and to_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 to to_chr_scalar(), stabilize_chr(), and stabilize_chr_scalar() (#251).

New functions

  • New pkg_inform() and pkg_warn() signal classed messages and warnings, respectively, with an opinionated class hierarchy, mirroring pkg_abort(). New expect_pkg_message_classes() and expect_pkg_warning_classes() test that the expected classes are thrown, and expect_pkg_message_snapshot() and expect_pkg_warning_snapshot() snapshot-test the full output in one step (#213).
  • New function to() coerces x to the type of its .to argument. stbl_to() is also registered as a C callable in a new public C API (#182).
  • New to_fn(), are_fn_ish(), and is_fn_ish() add the fn type 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(), and expect_pkg_warning_snapshot() now produce stable snapshots when run under devtools::test_coverage_active_file(). specify_cls() and related specify_*() functions now also produce stable function-body snapshots under coverage (#253).
  • expect_pkg_message_classes() and expect_pkg_warning_classes() now support assignments inside object (e.g. result <- fn_that_warns()). expect_pkg_message_snapshot() and expect_pkg_warning_snapshot() inherit the same fix (#234).

Other changes

  • are_*_ish(), to_*(), stabilize_dbl(), and stabilize_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_chr and *_to_fct families (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(), and stbl_lgl_are_chrish()) (#235, #237, #241).
  • is_fct_ish() now accepts a max_levels argument to limit the number of unique non-NA levels (#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...
Read more

stbl 0.3.0

Choose a tag to compare

@jonthegeek jonthegeek released this 04 Apr 14:51

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(), and specify_lgl_scalar() (and their synonyms) now default to allow_null = FALSE and allow_zero_length = FALSE. Pass allow_null = TRUE or allow_zero_length = TRUE to 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 for to_chr(), specify_logical() for specify_lgl(), and stabilise_*() for all stabilize_*() functions (#164, #167).
  • New expect_pkg_error_classes() checks that an error with the expected set of classes is thrown by pkg_abort(), and expect_pkg_error_snapshot() snapshot-tests the full error output in one step by combining expect_snapshot() with expect_pkg_error_classes() (#136, #188). New pkg_abort() throws errors with a standardized, opinionated collection of classes (#136).
  • New specification functions: specify_*() creates a "stbl_specified_fn", a call to the corresponding stabilize_*() function with arguments pre-filled. For example, stabilize_email <- specify_chr(regex = "^[^@]+@[^@]+\\.[^@]+$") creates a stabilize_email() function that validates email addresses (#147, #148, #149, #150, #151, #153, #161).
  • New stabilize_df() and specify_df() validate data frame structure and contents (#142).
  • New stabilize_lst() and specify_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-NULL without imposing any type constraints (#110).
  • New to_df() (and synonym to_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 synonym to_list()) coerces an object to a list, with conditional checks for NULL and 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...
Read more

stbl 0.2.0

Choose a tag to compare

@jonthegeek jonthegeek released this 16 Sep 23:00

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(), and is_lgl_ish()) checks the entire object at once. The are_*_ish() family (are_chr_ish(), are_dbl_ish(), are_fct_ish(), are_int_ish(), and are_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(), and stabilize_dbl_scalar() (#23).
  • stabilize_chr() now accepts patterns from stringr::regex(), stringr::fixed(), and stringr::coll() (#87), and can generate more informative error messages for regex failures via the new regex_must_match() and regex_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") to FALSE and TRUE respectively (#30).

Documentation

  • The purpose of and vision for this package are now more clearly described in documentation (#56, #77).
  • New vignette("stbl") provides an overview of the package and its functions (#42).

stbl 0.1.1

Choose a tag to compare

@jonthegeek jonthegeek released this 23 May 17:28
ec6b1a0
  • Formatting changes in DESCRIPTION and examples.