Revision history for Params-Validate-Strict

0.38	Tue Aug 11 09:36:18 PM EDT 2026
	[Enhancements]
	- Reduce dependancies
	- Rule dispatch now processes the 'type' rule before all other rules,
	  guaranteeing that min/max handlers can rely on the type having been
	  validated.  Redundant arrayref re-validation in min/max handlers removed
	  as dead code (type fires first; non-array values are caught before min/max
	  can execute).
	- Optional-parameter detection now uses a ternary expression in place of
	  an intermediate $look_for_default boolean.
	- Private helpers extracted to eliminate duplicated code:
	    _rule_error($logger, $rules, @parts) — emits error_msg or default
	    _value_in_list($val, $list, $type, $cs) — O(1) cached memberof lookup
	    _param_defined($args, $param) — exists+defined check
	- _value_in_list cache uses Scalar::Util::weaken to detect address reuse
	  (ABA problem) after list GC; cache entries with a dead weak ref are
	  discarded before use.
	- nomatch handler now wraps plain-string patterns in qr/\Q...\E/ and guards
	  the arrayref arm with any{} (was using the raw pattern variable).
	- float/number regex in element_type changed from capturing to non-capturing
	  groups and restructured to avoid O(n^2) alternation.
	- Typo fix: custom-type minimum-key fallback used 'minumum' instead of
	  'minimum'; the constraint was silently ignored for custom types that
	  specified 'minimum' (not 'min').
	- Dead code annotated with TODO comments: unreachable die after croak in
	  _error; unreachable next/last after _error calls; unreachable position < 0
	  guard (any negative number stringifies with '-' which already matches /\D/).
	[Tests]
	- t/logic_reducer.t (23 subtests): equivalence-partition tests for the
	  type-first dispatch ordering, min/max arrayref and hashref exact boundaries,
	  void type boundaries, unix_timestamp four-point boundary, custom-type
	  minimum key (typo fix), and optional-arrayref skips min when absent.
	- t/path.t (20 subtests): path-coverage tests for CFG branches not exercised
	  by the existing suite: _schema_from_arrayref guards (non-hashref element,
	  missing name, duplicate name); validate/validator non-CODE rule; unknown
	  relationship type; position rule \D guard; duplicate position collision in
	  return loop; cross_validation non-CODE; nested arrayref field-schema form
	  (is_field_schema path); element_type unsupported-type BUG path; required_group
	  < 2 params guard; value_constraint unrecognised operator; conditional_requirement
	  and dependency missing-key guards; value_conditional condition-false path;
	  positional return-arrayref path; args=>undef with args key present.
	- Bump minimum Test::Mockingbird

0.37	Tue Jul 28 09:29:48 EDT 2026
  [Enhancements]
  - New type 'void': asserts that the parameter value is undef, representing
    a void return or absent output.  A schema using 'void' must contain
    exactly one parameter; a defined value is an error.  The void parameter
    is implicitly optional (undef is the expected value, not an absent one),
    so 'optional => 1' is not required.  Supports 'error_msg' override.
  - 'semantic' rule documented in POD (was implemented but undocumented):
    semantic => 'unix_timestamp' validates that the value is a non-negative
    integer no greater than 2147483647.

  [Bug Fixes]
  - Fixed: 'semantic => unix_timestamp' rejection path called the non-existent
    bare function error() instead of the internal helper _error(); out-of-range
    timestamps now correctly croak instead of dying with "Undefined subroutine".
    The error message also used single-quotes so $value was not interpolated;
    both are now fixed.

  [Tests]
  - function.t: 5 new subtests for type 'void' covering undef acceptance,
    absent-key acceptance, all defined-value rejections (0, 1, empty string,
    string, arrayref, hashref), multiple-schema-key rejection, and
    error_msg override.
  - unit.t: 17 new subtests covering: type 'void' (undef passes, defined
    rejected, multiple-key schema rejected, error_msg override); type synonyms
    'num' and 'double'; 'minimum' alias for 'min' on string and integer;
    'semantic => unix_timestamp' (valid pass, below-0 rejection,
    above-2147483647 rejection, unknown semantic warns); as_string() coercion
    on schema rule values; control-character stripping from error messages;
    invalid unknown_parameter_handler value; unknown rule name.  API ledger
    asserts all new states are triggered.

0.36	Wed Jul 22 21:02:37 EDT 2026

  [Tests]
  - t/50-even-more.t: fixed inline Test::Logger mock whose error() method
    called die($_[2]), which is the literal string ' line ' (the third
    argument to the logger call), not the error message.  The method now
    records join('', @_[1..$#_]) and does not die; _error's own croak fires
    instead, setting $@ correctly.  Fixes three subtests: 'invalid min/max',
    'checks number of characters not bytes', and 'invalid regex'.
    Fixes https://www.cpantesters.org/cpan/report/5d5260f2-84d0-11f1-a803-c5b888e1d5bf
  - t/50-even-more.t: corrected 'invalid regex' assertion from
    qr/invalid regex/ to qr/regex.*error/i.  String patterns passed to
    'matches' are always wrapped in qr/\Q...\E/ so they can never be invalid;
    the test was asserting an error message the module never emits.

0.35	Sat Jun 27 21:28:03 EDT 2026

  [Tests]
  - function.t: the "1e309 overflows to Inf" subtest now skips on
    -Duselongdouble builds where 1e309 is a finite value, not Inf.
    Fixes GitHub#3

  [Bug Fixes]
  - Better message when the number of items in an arrayref is too small

0.34	Sat Jun 13 15:55:13 EDT 2026

  [Enhancements]
  - New type 'stringref': accepts a reference to a scalar that contains a
    plain string (e.g. \$var).  Rejects plain scalars, arrayrefs, hashrefs,
    coderefs, blessed objects, and REF-of-REF values.  Dereferences the
    string before further processing, so min/max (character length),
    matches, nomatch, memberof, notmemberof, transform, callback, and all
    other rules operate on the plain string.  The validated return value is
    the dereferenced string.
  - Union types such as type => ['string', 'stringref'] are fully supported.
  - Integer validation now accepts any numeric representation whose value
    has no fractional part, including scientific notation (e.g.
    1.38255823391608e+18) and trailing-zero decimals (e.g. 42.0).  Values
    with a non-zero fractional part (e.g. 3.14, 42.9) are still rejected.
    The coerced return value is always a Perl integer (via int()).

  [Bug Fixes]
  - Fixed: integer type accepted "Inf", "-Inf", and overflowing scientific
    notation (e.g. "1e309") because int(Inf)==Inf makes the $v != int($v)
    guard transparent to infinity.  Added a ($v - $v) != 0 pre-check:
    Inf - Inf produces NaN, and NaN != 0 is true, so non-finite values are
    now correctly rejected.
  - Fixed: a 'stringref' parameter whose 'transform' coderef returned a
    reference (hashref, arrayref, etc.) was silently stored in the validated
    result because the dispatch-loop arm for 'stringref' was a no-op stub.
    The stub now checks ref($value) after transform and croaks if a reference
    is returned.
  - Fixed: when 'stringref' was combined with 'optional => CODE', the
    coderef received the internally-dereferenced plain string rather than the
    original SCALAR reference the caller supplied.  The pre-deref value is
    now preserved and passed to the optional coderef for stringref parameters;
    all other types continue to receive the post-transform value as before.

  [Tests]
  - Comprehensive stringref tests across unit.t (acceptance, rejection,
    min, max, matches, memberof, optional, default, error_msg, logger,
    union types), extended_tests.t (all rule combinations, union types with
    constraints), and edge_cases.t (pathological inputs, NUL bytes, unicode,
    transform, callback, positional args, schema reuse).
  - function.t: 30 new stringref subtests covering all type-rejection paths,
    min/max on dereferenced length, matches, memberof, transform ordering,
    callback, optional/default, and union types.
  - function.t: scientific-notation integer subtest (1.38255823391608e+18).
  - function.t: 7 new subtests covering the three bug fixes above (Inf/-Inf/
    1e309 rejected as integer; transform returning a ref rejected for
    stringref; optional CODE receives the original SCALAR ref).
  - Updated stale subtests in edge_cases.t and extended_tests.t that
    incorrectly asserted scientific-notation and trailing-.0 integers are
    rejected.

0.33	Mon May 25 09:21:12 EDT 2026

  [Enhancements]
  - More informative boundary messages
  - New type 'scalar': accepts any plain scalar value but rejects references
  - New type 'scalarref': accepts a reference to a scalar (\$var) but rejects
    plain scalars, arrayrefs, hashrefs, coderefs, and objects; error message
    distinguishes "a plain scalar" from other reference kinds

  [Tests]
  - Comprehensive combinatorial test suite (t/extended_tests.t) covering every
    type paired with every applicable rule: type×min, type×max, type×min×max
    for string/integer/number/float/arrayref/hashref; type×matches,
    type×nomatch, type×memberof (case-sensitive and case-insensitive),
    type×notmemberof; optional×default for all types; transform combined with
    min/max/matches/memberof/notmemberof; callback with coercion and
    cross-field access; validate/validator; description in errors; union types;
    isa/can fail cases and multi-method arrays; element_type×min×max; nested
    schema fail cases; cross-validation and relationship fail cases;
    positional argument coercion; all rule synonyms (regex, enum, values, str,
    bool, float, minimum); min-as-coderef; and complex multi-rule combinations

0.32	Mon May 11 20:34:23 EDT 2026

  [Enhancements]
  - Schema now accepts an arrayref of parameter hashrefs as an alternative
    to the named-parameter hashref format:

      schema => [
        { name => 'username', type => 'string', min => 3 },
        { name => 'age',      type => 'integer', min => 0 },
      ]

    The arrayref is normalised to the standard hashref form before any
    further processing.  All existing rules (optional, default, transform,
    schema, relationships, cross_validation, positional position, etc.)
    continue to work unchanged.  Particularly useful for modules that use
    positional or mixed calling conventions.  Duplicate names and missing
    'name' keys are caught and reported.  The members wrapper also accepts
    arrayref form.

  - 'enum' is now fully synonymous with 'memberof': the min/max
    incompatibility guard (which previously only checked 'memberof') now
    also fires when 'enum' is combined with min or max.

  - 'values' added as a synomym for 'memberof'

  [Bug Fixes]
  - In the case of position parameters, an input value of 0, could set an output value of undef.
    Fixed by using exists() in the return loop

0.31	Fri May  8 08:03:03 EDT 2026

  [Enhancements]
  - Use Readonly::Values::Boolean for the boolean type — boolean values are
    now drawn from that module's %booleans hash, giving a consistent and
    extensible set of recognised truthy/falsy strings across the codebase.
  - Allow 'minimum' as a synonym for 'min' in schema rules.
  - Allow 'regex' as a synonym for 'matches' in schema rules.

  [Bug Fixes]
  - Fixed: 'nullable' with a present value triggered "Unknown rule 'nullable'"
    because the rule-name was handled before the dispatch loop (to set
    $is_optional) but had no corresponding no-op elsif in the loop itself.
    The absent-value path was unaffected because the optional block exits
    with 'next' before the loop runs; only the present-value path was broken.
  - Fixed: nested hashref defaults were not applied when the input hashref
    was empty ({}).  The guard condition checked scalar keys of the original
    input value rather than of the post-defaults hashref, so an empty input
    caused the nested validate_strict call to be skipped entirely.
  - Fixed: when an optional parameter had both 'default' and 'schema' set and
    the parameter was absent, the 'default' value was overwritten by the
    result of nested schema processing because there was no 'next' after
    storing the default.  The default now wins: a 'next' is inserted
    immediately after $validated_args{$key} = $rules->{'default'}.
  - Fixed: arrayref fields with a field-schema hash (e.g. schema => { name =>
    { type => 'string' }, age => { type => 'integer' } }) caused "Unknown
    rule 'name'" because the inner validate_strict call wrapped the element
    and schema incorrectly, causing field names to be treated as rule names.
    The handler now distinguishes a field-schema hash (no top-level 'type'
    key) from a rule hash (has 'type') and calls validate_strict accordingly.
  - Fixed: the 'transform' coderef was invoked twice for every present field —
    once explicitly before the rule-dispatch loop, and again by the generic
    "coerce CODE rule-values by calling them" guard inside the loop.  The
    'optional' coderef had the same double-invocation bug.  Both are now
    added to the exclusion list alongside 'validate', 'callback', and
    'validator'.

0.30	Sun Feb 22 21:03:42 EST 2026
	Added carp_on_warn support
	In support of better OOP, a value can now be an object if it understands 'as_string()'
	If no schema is given, allow all arguments
	Better error message when a positional argument makes no sense
	Pass $args and $schema to a validation callback

0.29	Sat Jan 31 16:29:42 EST 2026
	Document "can" and "optional" as a code ref a bit more
	Added nullable as a synonym for optional
	Updated to the latest test dashboard
	Fix https://www.cpantesters.org/cpan/report/c1353bb2-fd80-11f0-a3bc-a055f9c4ba34

0.28	Tue Dec 23 20:28:19 EST 2025
	Added relationship validator
	Handle undefined value in 'isa' test
	Fixed handling of min or max set to 0
	Allow type to be 'Str' or 'Bool' to be compatible with other schema definitions
	Increased test coverage

0.27	Sat Dec 13 11:03:00 EST 2025
	Added enum as a synonym of memberof
	Support unix_timestamp semantic

0.26	Tue Dec  9 20:11:39 EST 2025
	Don't error if utf-8 doesn't decode
	Create helper routine _number_of_characters()

0.25	Thu Dec  4 08:05:49 EST 2025
	Now dies if the schema says that the minimum length of a string should be < 0
	String length comparisons are now character counts, not bytes

0.24	Mon Nov 17 08:19:19 EST 2025
	error_message renamed error_msg (now consistent with Data::Processor)
	added description field (inspired by Data::Processor)
	Call die after croak to be sure of death
	Fixed RT#171339

0.23	Thu Oct 30 13:37:31 EDT 2025
	Flag attempting to compare numbers as strings
	Added handling for positional arguments

0.22	Sat Oct 25 21:51:13 EDT 2025
	If a cross_validation fails, invalidate all arguments
	Args were being passed as valid with some settings of logger
	Improved handling of defaults within nested schemas

0.21	Thu Oct 23 20:12:51 EDT 2025
	Added cross_validation parameter for validating relationships between fields
	Added notmemberof to blacklist items
	Added case_sensitive flag (defaults to 1)

0.20	Thu Oct 23 08:22:29 EDT 2025
	Added conditional validation rules
	Added custom types
	Added transformation/sanitization rules

0.19	Tue Oct 21 15:34:58 EDT 2025
	Allow a parameter to have different allowable types

0.18	Mon Oct 20 11:56:19 EDT 2025
	Handle when an undefined object is passed in

0.17	Fri Oct 17 21:00:50 EDT 2025
	Allow regexes in a schema to be a simple string

0.16	Sat Oct 11 18:35:15 EDT 2025
	Added 'validate' to the schema language
	Allow yes/no for booleans
	Fix value => 0 for default

0.15	Thu Oct  9 16:48:57 EDT 2025
	Added float as a synomym of number
	Do string compares on bools for edge case testing

0.14	Mon Sep 29 15:17:39 EDT 2025
	Support optionals for memberof
	Min/max make no sense with memberof

0.13	Sat Sep 27 10:27:25 EDT 2025
	Say how long the text is, when complaining it's too long
	Say what the current value is when testing max
	Better assertion that the type of a value has not been given
	Give line number of the assertion failure
	Fix https://www.cpantesters.org/cpan/report/905b8bfc-9a5e-11f0-a3bc-a055f9c4ba34
	Support the boolean data type

0.12	Tue Sep 16 16:25:18 EDT 2025
	Support the logger argument
	Remove unneeded regex
	Allow 'can' to take a list of methods as arrayref
	Added the default and error_message and schema options
	Added array element validation for nested validation

0.11	Tue Aug 26 15:02:00 EDT 2025
	args can now also be input, to be used with Return::Set which takes output
	Matches and nomatch now works on arrayrefs, checking each member of the array

0.10	Wed Aug  6 20:40:12 EDT 2025
	Allow args to be not given, will allow if everything is optional
	Allow { arg => undef }

0.09	Wed Aug  6 15:29:55 EDT 2025
	Optimize conditional
	Added missing dependencies
	Safer numeric coercion
	Use Scalar::Util::looks_like_number for number verification
	Changed some of the messages
	Documented migration from legacy validators

0.08	Tue Aug  5 18:58:37 EDT 2025
	Validate objects

0.07	Tue Aug  5 10:43:55 EDT 2025
	Validate that max > min in the schema

0.06	Wed Jul 30 14:37:31 EDT 2025
	Added the 'nomatch' and 'memberof' rules

0.05	Tue Jul 29 08:24:59 EDT 2025
	Bump the minimum version of Params::Get
		https://www.cpantesters.org/cpan/report/9433e5e2-6c2f-11f0-8186-d3a6de164758
	Fix counting of keys in a hash

0.04	Mon Jul 28 12:09:13 EDT 2025
	Added arrayref, hashref and coderef as valid value types

0.03	Mon Apr  7 07:42:43 EDT 2025
	Use Params::Get

0.02	Wed Feb 26 16:24:49 EST 2025
	Added the "unknown_parameter_handler" argument
	Added CI tools
	Use named parameters rather than positional ones

0.01	Wed Feb 26 11:35:19 EST 2025
        First draft
