1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
|
NAME
Data::Checks - Value constraint checking
SYNOPSIS
With Signature::Attribute::Checked:
use v5.26;
use Sublike::Extended;
use Signature::Attribute::Checked;
use Data::Checks qw( Str );
extended sub greet ( $message :Checked(Str) ) {
say "Hello, $message";
}
greet( "world" ); # is fine
greet( undef ); # throws an exception
With Object::Pad::FieldAttr::Checked:
use v5.22;
use Object::Pad;
use Object::Pad::FieldAttr::Checked;
use Data::Checks qw( Str );
class Datum {
field $name :param :reader :Checked(Str);
}
my $x = Datum->new( name => "something" ); # is fine
my $y = Datum->new( name => undef ); # throws an exception
With Syntax::Operator::Is on Perl v5.38 or later:
use v5.38;
use Syntax::Operator::Is;
use Data::Checks qw( Num Object );
my $x = ...;
if($x is Num) {
say "x can be used as a number";
}
elsif($x is Object) {
say "x can be used as an object";
}
DESCRIPTION
This module provides functions that implement various value constraint
checking behaviours. These are the parts made visible by the use
Data::Checks ... import line, in Perl code.
It also provides the underlying common framework XS functions to assist
in writing modules that actually implement such constraint checking.
These parts are not visible in Perl code, but instead made visible at
the XS level by the #include "DataChecks.h" directive.
See the "SYNOPSIS" section above for several examples of other CPAN
modules that make direct use of these constraint checks.
CONSTRAINTS
The following constraint checks are inspired by the same-named ones in
Types::Standard. They may be called fully-qualified, or imported
lexically into the calling scope.
Note to users familiar with Types::Standard: some of these functions
behave slightly differently. In particular, these constraints are
generally happy to accept an object reference to a class that provides
a conversion overload, whereas the ones in Types::Standard often are
not. Additionally functions that are parametric take their parameters
in normal Perl function argument lists, not wrapped in additional array
references.
Defined
Defined()
Accepts any defined value, rejects only undef.
Object
Object()
Accepts any blessed object reference, rejects non-references or
references to unblessed data.
Str
Str()
Accepts any defined non-reference value, or a reference to an object in
a class that overloads stringification. Rejects undefined, unblessed
references, or references to objects in classes that do not overload
stringification.
StrEq
StrEq($s)
StrEq($s1, $s2, ...)
Since version 0.05.
Accepts any value that passes the Str check, and additionally is
exactly equal to any of the given strings.
StrMatch
StrMatch(qr/pattern/)
Since version 0.08.
Accepts any value that passes the Str check, and additionally matches
the given regexp pattern.
Remember that the pattern must be supplied as a qr/.../ expression, not
simply m/.../ or /.../.
Num
Num()
Accepts any defined non-reference value that is either a plain number,
or a string that could be used as one without warning, or a reference
to an object in a class that overloads numification.
Rejects undefined, not-a-number, strings that would raise a warning if
converted to a number, unblessed references, or references to objects
in classes that do not overload numification.
NumGT
NumGE
NumLE
NumLT
NumGT($bound)
NumGE($bound)
NumLE($bound)
NumLT($bound)
Since version 0.05.
Accepts any value that passes the Num check, and additionally is within
the bound given. NumGT and NumLT exclude the bound value itself, NumGE
and NumLE include it.
NumRange
NumRange($boundge, $boundlt)
Since version 0.05.
Accepts any value that passes the Num check, and additionally is
between the two bounds given. The lower bound is inclusive, and the
upper bound is exclusive.
This choice is made so that a set of NumRange constraints can easily be
created that cover distinct sets of numbers:
NumRange(0, 10), NumRange(10, 20), NumRange(20, 30), ...
To implement checks with both lower and upper bounds but other kinds of
inclusivity, use two Num... checks combined with an All(). For example,
to test between 0 and 100 inclusive at both ends:
All(NumGE(0), NumLE(100))
Combinations like this are internally implemented as efficiently as a
single NumRange() constraint.
NumEq
NumEq($n)
NumEq($n1, $n2, ...)
Since version 0.05.
Accepts any value that passes the Num check, and additionally is
exactly equal to any of the given numbers.
Isa
Isa($classname)
Since version 0.04.
Accepts any blessed object reference to an instance of the given class
name, or a subclass derived from it (i.e. anything accepted by the isa
operator).
ArrayRef
ArrayRef()
Since version 0.07.
Accepts any plain reference to an array, or any object reference to an
instance of a class that provides an array dereference overload.
HashRef
HashRef()
Since version 0.07.
Accepts any plain reference to a hash, or any object reference to an
instance of a class that provides a hash dereference overload.
Callable
Callable()
Since version 0.06.
Accepts any plain reference to a subroutine, or any object reference to
an instance of a class that provides a subroutine dereference overload.
Maybe
Maybe($C)
Since version 0.04.
Accepts undef in addition to anything else accepted by the given
constraint.
Any
Any($C1, $C2, ...)
Since version 0.07.
Accepts a value that is accepted by at least one of the given
constraints. Rejects if none of them accept it.
At least one constraint is required; it is an error to try to call
Any() with no arguments. If you need a constraint that accepts any
value at all, see "All".
$C1 | $C2 | ...
Since version 0.08.
This function is used to implement | operator overloading, so
constraint checks can be written using this more convenient syntax.
All
All($C1, $C2, ...)
All()
Since version 0.07.
Accepts a value that is accepted by every one of the given constraints.
Rejects if at least one of them rejects it.
Note that if no constraints are given, this accepts all possible
values. This may be useful as an "accept-all" fallback case for
generated code, or other situations where it is required to provide a
constraint check but you do not wish to constraint allowed values.
CONSTRAINT METHODS
While not intended to be called from regular Perl code, these
constraints still act like objects with the following methods.
check
$ok = $constraint->check( $value );
Since version 0.09.
Returns a boolean value indicating whether the constraint accepts the
given value.
XS FUNCTIONS
The following functions are provided by the DataChecks.h header file
for use in XS modules that implement value constraint checking.
boot_data_checks
void boot_data_checks(double ver);
Call this function from your BOOT section in order to initialise the
module and load the rest of the support functions.
ver should either be 0 or a decimal number for the module version
requirement; e.g.
boot_data_checks(0.01);
make_checkdata
struct DataChecks_Checker *make_checkdata(SV *checkspec);
Creates a struct DataChecks_Checker structure, which wraps the intent
of the value constraint check. The returned value is used as the
checker argument for the remaining functions.
The constraint check itself is specified by the SV given by checkspec,
which should come directly from the user code. The constraint check may
be specified in any of three ways:
* An object reference in a class which has a check method. Value
checks will be invoked as
$ok = $checkerobj->check( $value );
* A package name as a plain string of a package which has a check
method. Value checks will be invoked as
$ok = $checkerpkg->check( $value );
* A code reference. Value checks will be invoked with a single
argument, as
$ok = $checkersub->( $value );
Since version 0.09 this form is now deprecated, because it does not
easily support a way to query the constraint for its name or
stringified form, which is useful when generating error messages.
* Additionally, the constraint check functions provided by this
module may be implemented using any of the above mechanisms, or may
use an unspecified fourth different mechanism. Outside code should
not rely on what that mechanism may be.
Once constructed into a checker structure, the choice of which
implementation is used is fixed, and if a method lookup is involved its
result is stored directly as a CV pointer for efficiency of later
invocations. In either of the first two cases, the reference count on
the checkspec SV is increased to account for the argument value used on
each invocation. In the third case, the reference SV is not retained,
but the underlying CV it refers to has its reference count increased.
free_checkdata
void free_checkdata(struct DataChecks_Checker *checker);
Releases any stored SVs in the checker structure, and the structure
itself.
gen_assertmess
void gen_assertmess(struct DataChecks_Checker *checker, SV *name, SV *constraint);
Generates and stores a message string for the assert message to be used
by "make_assertop" and "assert_value". The message will take the form
NAME requires a value satisfying CONSTRAINT
Both name and constraint SVs used as temporary strings to generate the
stored message string. Neither SV is retained by the checker directly.
make_assertop
OP *make_assertop(struct DataChecks_Checker *checker, OP *argop);
Shortcut to calling "make_assertop_flags" with flags set to zero.
make_assertop_flags
OP *make_assertop_flags(struct DataChecks_Checker *checker, U32 flags, OP *argop);
Creates an optree fragment for a value check assertion operation.
Given an optree fragment in scalar context that generates an argument
value (argop), constructs a larger optree fragment that consumes it and
checks that the value is accepted by the constraint check given by
checker. The behaviours of the returned optree fragment will depend on
the flags.
If flags is OPf_WANT_VOID the returned optree will yield nothing.
If flags is zero, the return behaviour is not otherwise specified.
check_value
bool check_value(struct DataChecks_Checker *checker, SV *value);
Checks whether a given SV is accepted by the given constraint check,
returning true if so, or false if not.
assert_value
void assert_value(struct DataChecks_Checker *checker, SV *value);
Checks whether a given SV is accepted by the given constraint check,
throwing its assertion message if it does not.
TODO
* Unit constraints - maybe Int, some plain-only variants of Str and
Num, some reference types, etc...
* Structural constraints - HashOf, ArrayOf, etc...
* Think about a convenient name for inclusive-bounded numerical
constraints.
* Look into making const-folding work with the MIN .. MAX flip-flop
operator
AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
|