2 package Moose::Meta::TypeConstraint;
8 use overload '0+' => sub { refaddr(shift) }, # id an object
9 '""' => sub { shift->name }, # stringify to tc name
14 use Scalar::Util qw(blessed refaddr);
15 use Sub::Name qw(subname);
18 use base qw(Class::MOP::Object);
20 __PACKAGE__->meta->add_attribute('name' => (reader => 'name'));
21 __PACKAGE__->meta->add_attribute('parent' => (
23 predicate => 'has_parent',
26 my $null_constraint = sub { 1 };
27 __PACKAGE__->meta->add_attribute('constraint' => (
28 reader => 'constraint',
29 writer => '_set_constraint',
30 default => sub { $null_constraint }
32 __PACKAGE__->meta->add_attribute('message' => (
33 accessor => 'message',
34 predicate => 'has_message'
36 __PACKAGE__->meta->add_attribute('coercion' => (
37 accessor => 'coercion',
38 predicate => 'has_coercion'
41 __PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
42 init_arg => 'optimized',
43 accessor => 'hand_optimized_type_constraint',
44 predicate => 'has_hand_optimized_type_constraint',
47 __PACKAGE__->meta->add_attribute('inlined' => (
48 init_arg => 'inlined',
49 accessor => 'inlined',
50 predicate => '_has_inlined_type_constraint',
53 __PACKAGE__->meta->add_attribute('inline_environment' => (
54 init_arg => 'inline_environment',
55 accessor => '_inline_environment',
56 default => sub { {} },
66 __PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
67 accessor => '_compiled_type_constraint',
68 predicate => '_has_compiled_type_constraint'
70 __PACKAGE__->meta->add_attribute('package_defined_in' => (
71 accessor => '_package_defined_in'
76 my ($first, @rest) = @_;
77 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
78 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
80 my $self = $class->_new(%args);
81 $self->compile_type_constraint()
82 unless $self->_has_compiled_type_constraint;
91 my $coercion = $self->coercion;
95 Moose->throw_error("Cannot coerce without a type coercion");
98 return $_[0] if $self->check($_[0]);
100 return $coercion->coerce(@_);
106 my $coercion = $self->coercion;
110 Moose->throw_error("Cannot coerce without a type coercion");
113 return $_[0] if $self->check($_[0]);
115 my $result = $coercion->coerce(@_);
117 $self->assert_valid($result);
123 my ($self, @args) = @_;
124 my $constraint_subref = $self->_compiled_type_constraint;
125 return $constraint_subref->(@args) ? 1 : undef;
129 my ($self, $value) = @_;
130 if ($self->_compiled_type_constraint->($value)) {
134 $self->get_message($value);
141 if ( $self->has_parent && $self->constraint == $null_constraint ) {
142 return $self->parent->can_be_inlined;
145 return $self->_has_inlined_type_constraint;
151 unless ( $self->can_be_inlined ) {
153 Moose->throw_error( 'Cannot inline a type constraint check for ' . $self->name );
156 if ( $self->has_parent && $self->constraint == $null_constraint ) {
157 return $self->parent->_inline_check(@_);
160 return $self->inlined->( $self, @_ );
163 sub inline_environment {
166 if ( $self->has_parent && $self->constraint == $null_constraint ) {
167 return $self->parent->inline_environment;
170 return $self->_inline_environment;
174 my ($self, $value) = @_;
176 my $error = $self->validate($value);
177 return 1 if ! defined $error;
180 Moose->throw_error($error);
184 my ($self, $value) = @_;
185 if (my $msg = $self->message) {
187 return $msg->($value);
190 # have to load it late like this, since it uses Moose itself
191 my $can_partialdump = try {
192 # versions prior to 0.14 had a potential infinite loop bug
193 Class::MOP::load_class('Devel::PartialDump', { -version => 0.14 });
196 if ($can_partialdump) {
197 $value = Devel::PartialDump->new->dump($value);
200 $value = (defined $value ? overload::StrVal($value) : 'undef');
202 return "Validation failed for '" . $self->name . "' with value $value";
206 ## type predicates ...
209 my ( $self, $type_or_name ) = @_;
211 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
213 return 1 if $self == $other;
215 if ( $self->has_hand_optimized_type_constraint and $other->has_hand_optimized_type_constraint ) {
216 return 1 if $self->hand_optimized_type_constraint == $other->hand_optimized_type_constraint;
219 return unless $self->constraint == $other->constraint;
221 if ( $self->has_parent ) {
222 return unless $other->has_parent;
223 return unless $self->parent->equals( $other->parent );
225 return if $other->has_parent;
232 my ($self, $type_or_name) = @_;
234 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
236 ($self->equals($type) || $self->is_subtype_of($type));
240 my ($self, $type_or_name) = @_;
242 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
246 while (my $parent = $current->parent) {
247 return 1 if $parent->equals($type);
254 ## compiling the type constraint
256 sub compile_type_constraint {
258 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
261 ## type compilers ...
263 sub _actually_compile_type_constraint {
266 return $self->_compile_hand_optimized_type_constraint
267 if $self->has_hand_optimized_type_constraint;
269 if ( $self->can_be_inlined ) {
271 source => 'sub { ' . $self->_inline_check('$_[0]') . ' }',
272 environment => $self->inline_environment,
276 my $check = $self->constraint;
277 unless ( defined $check ) {
279 Moose->throw_error( "Could not compile type constraint '"
281 . "' because no constraint check" );
284 return $self->_compile_subtype($check)
285 if $self->has_parent;
287 return $self->_compile_type($check);
290 sub _compile_hand_optimized_type_constraint {
293 my $type_constraint = $self->hand_optimized_type_constraint;
295 unless ( ref $type_constraint ) {
297 Moose->throw_error("Hand optimized type constraint is not a code reference");
300 return $type_constraint;
303 sub _compile_subtype {
304 my ($self, $check) = @_;
306 # gather all the parent constraintss in order
308 my $optimized_parent;
309 foreach my $parent ($self->_collect_all_parents) {
310 # if a parent is optimized, the optimized constraint already includes
311 # all of its parents tcs, so we can break the loop
312 if ($parent->has_hand_optimized_type_constraint) {
313 push @parents => $optimized_parent = $parent->hand_optimized_type_constraint;
317 push @parents => $parent->constraint;
321 @parents = grep { $_ != $null_constraint } reverse @parents;
323 unless ( @parents ) {
324 return $self->_compile_type($check);
325 } elsif( $optimized_parent and @parents == 1 ) {
326 # the case of just one optimized parent is optimized to prevent
327 # looping and the unnecessary localization
328 if ( $check == $null_constraint ) {
329 return $optimized_parent;
331 return subname($self->name, sub {
332 return undef unless $optimized_parent->($_[0]);
339 # general case, check all the constraints, from the first parent to ourselves
340 my @checks = @parents;
341 push @checks, $check if $check != $null_constraint;
342 return subname($self->name => sub {
345 foreach my $check (@checks) {
346 return undef unless $check->(@args);
354 my ($self, $check) = @_;
356 return $check if $check == $null_constraint; # Item, Any
358 return subname($self->name => sub {
367 sub _collect_all_parents {
370 my $current = $self->parent;
371 while (defined $current) {
372 push @parents => $current;
373 $current = $current->parent;
378 sub create_child_type {
379 my ($self, %opts) = @_;
380 my $class = ref $self;
381 return $class->new(%opts, parent => $self);
386 # ABSTRACT: The Moose Type Constraint metaclass
394 This class represents a single type constraint. Moose's built-in type
395 constraints, as well as constraints you define, are all stored in a
396 L<Moose::Meta::TypeConstraint::Registry> object as objects of this
401 C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>.
407 =item B<< Moose::Meta::TypeConstraint->new(%options) >>
409 This creates a new type constraint based on the provided C<%options>:
415 The constraint name. If a name is not provided, it will be set to
420 A C<Moose::Meta::TypeConstraint> object which is the parent type for
421 the type being created. This is optional.
425 This is the subroutine reference that implements the actual constraint
426 check. This defaults to a subroutine which always returns true.
430 A subroutine reference which is used to generate an error message when
431 the constraint fails. This is optional.
435 A L<Moose::Meta::TypeCoercion> object representing the coercions to
436 the type. This is optional.
440 A subroutine which returns a string suitable for inlining this type
441 constraint. It will be called as a method on the type constraint object, and
442 will receive a single additional parameter, a variable name to be tested
443 (usually C<"$_"> or C<"$_[0]">.
447 =item * inline_environment
449 A hash reference of variables to close over. The keys are variables names, and
450 the values are I<references> to the variables.
454 B<This option is deprecated.>
456 This is a variant of the C<constraint> parameter that is somehow
457 optimized. Typically, this means incorporating both the type's
458 constraint and all of its parents' constraints into a single
459 subroutine reference.
463 =item B<< $constraint->equals($type_name_or_object) >>
465 Returns true if the supplied name or type object is the same as the
468 =item B<< $constraint->is_subtype_of($type_name_or_object) >>
470 Returns true if the supplied name or type object is a parent of the
473 =item B<< $constraint->is_a_type_of($type_name_or_object) >>
475 Returns true if the given type is the same as the current type, or is
476 a parent of the current type. This is a shortcut for checking
477 C<equals> and C<is_subtype_of>.
479 =item B<< $constraint->coerce($value) >>
481 This will attempt to coerce the value to the type. If the type does not
482 have any defined coercions this will throw an error.
484 If no coercion can produce a value matching C<$constraint>, the original
487 =item B<< $constraint->assert_coerce($value) >>
489 This method behaves just like C<coerce>, but if the result is not valid
490 according to C<$constraint>, an error is thrown.
492 =item B<< $constraint->check($value) >>
494 Returns true if the given value passes the constraint for the type.
496 =item B<< $constraint->validate($value) >>
498 This is similar to C<check>. However, if the type I<is valid> then the
499 method returns an explicit C<undef>. If the type is not valid, we call
500 C<< $self->get_message($value) >> internally to generate an error
503 =item B<< $constraint->assert_valid($value) >>
505 Like C<check> and C<validate>, this method checks whether C<$value> is
506 valid under the constraint. If it is, it will return true. If it is not,
507 an exception will be thrown with the results of
508 C<< $self->get_message($value) >>.
510 =item B<< $constraint->name >>
512 Returns the type's name, as provided to the constructor.
514 =item B<< $constraint->parent >>
516 Returns the type's parent, as provided to the constructor, if any.
518 =item B<< $constraint->has_parent >>
520 Returns true if the type has a parent type.
522 =item B<< $constraint->parents >>
524 A synonym for C<parent>. This is useful for polymorphism with types
525 that can have more than one parent.
527 =item B<< $constraint->constraint >>
529 Returns the type's constraint, as provided to the constructor.
531 =item B<< $constraint->get_message($value) >>
533 This generates a method for the given value. If the type does not have
534 an explicit message, we generate a default message.
536 =item B<< $constraint->has_message >>
538 Returns true if the type has a message.
540 =item B<< $constraint->message >>
542 Returns the type's message as a subroutine reference.
544 =item B<< $constraint->coercion >>
546 Returns the type's L<Moose::Meta::TypeCoercion> object, if one
549 =item B<< $constraint->has_coercion >>
551 Returns true if the type has a coercion.
553 =item B<< $constraint->can_be_inlined >>
555 Returns true if this type constraint can be inlined. A type constraint which
556 subtypes an inlinable constraint and does not add an additional constraint
557 "inherits" its parent type's inlining.
559 =item B<< $constraint->hand_optimized_type_constraint >>
561 B<This method is deprecated.>
563 Returns the type's hand optimized constraint, as provided to the
564 constructor via the C<optimized> option.
566 =item B<< $constraint->has_hand_optimized_type_constraint >>
568 B<This method is deprecated.>
570 Returns true if the type has an optimized constraint.
572 =item B<< $constraint->create_child_type(%options) >>
574 This returns a new type constraint of the same class using the
575 provided C<%options>. The C<parent> option will be the current type.
577 This method exists so that subclasses of this class can override this
578 behavior and change how child types are created.
584 See L<Moose/BUGS> for details on reporting bugs.