NAME
Object::Pad::FieldAttr::Checked
- apply value constraint checks to Object::Pad
fields
SYNOPSIS
With Types::Standard:
use Object::Pad;
use Object::Pad::FieldAttr::Checked;
use Types::Standard qw( Num );
class Point {
field $x :param :reader :Checked(Num);
field $y :param :reader :Checked(Num);
}
Point->new( x => 123, y => "456" ); # this is fine
Point->new( x => "hello", y => "world" ); # throws an exception
Or, standalone:
use Object::Pad;
use Object::Pad::FieldAttr::Checked;
package Numerical {
use Scalar::Util qw( looks_like_number );
sub check { looks_like_number $_[1]; }
}
class Point {
field $x :param :reader :Checked('Numerical');
field $y :param :reader :Checked('Numerical');
}
...
DESCRIPTION
This module provides a third-party field attribute for Object::Pad-based classes, which declares that values assigned to the field must conform to a given constraint check.
WARNING The ability for Object::Pad to take third-party field attributes is still new and highly experimental, and subject to much API change in future. As a result, this module should be considered equally experimental.
Additionally, the behaviour provided by this module should be considered more of a work-in-progress stepping stone. Ideally, constraint syntax ought to be provided in a much more fundamental way by Perl itself, allowing it to be used on my
lexicals, subroutine parameters, and other places as well as object fields. This module is more of a placeholder to allow some part of that behaviour to be specified for object fields, while not getting in the way of a more general, more powerful system being added in future.
FIELD ATTRIBUTES
:Checked
field $name :Checked(EXPRESSION) ...;
Declares that any value assigned to the field during the constructor or using an accessor method must conform to the constraint checker specified by the expression. Attempts to assign a non-conforming value will throw an exception and the field will not be modified. Currently only scalar fields are supported.
At compiletime, the string given by EXPRESSION is eval()
'ed in scalar context, and its result is stored as part of the field's definition. The expression must yield either an object reference, a code reference, or a string containing the name of a package. In the case of an object or package, a method called check
must exist on it.
If using a plain package name as a checker, be sure to quote package names so it will not upset use strict
.
field $x :Checked('CheckerPackage');
At runtime, this constraint checker is used every time an attempt is made to assign a value to the field from outside the object class, whether that is from :param
initialisation, or invoking a :writer
, :accessor
or :mutator
. The checker is used as the invocant for invoking a check
method, and the new value for the field is passed as an argument. If the method returns true, the assignment is allowed. If false, it is rejected with an exception and the field itself remains unmodified.
$ok = $checkerobj->check( $value ); # if an object
$ok = $checkersub->( $value ); # if a code reference
$ok = $checkerpkg->check( $value ); # if a package name
(For performance reasons, the check
method is actually resolved into a function at compiletime when the :Checked
attribute is applied, and this stored function is the one that is called at assignment time. If the method itself is replaced later by globref assignment or other trickery, this updated function will not be used.)
As this is the interface supported by Types::Standard, any constraint object provided by that module is already supported here.
use Types::Standard qw( Str Num );
field $name :Checked(Str);
field $age :Checked(Num);
Note carefully that direct assignment into the field variable by code within the class is not checked. This is partly because of design considerations, and partly because any way to implement that would be horribly slow, or flat-out impossible. Prior to version 0.04 this module used to claim that even direct assignments would be checked. but this gave a false sense of safety if deeply-nested containers were involved and modified from within.
SEE ALSO
Object::Pad::FieldAttr::Isa - apply class type constraints to
Object::Pad
fields
AUTHOR
Paul Evans <leonerd@leonerd.org.uk>