2 package Moose::Meta::TypeConstraint;
8 use overload '0+' => sub { refaddr(shift) }, # id an object
9 '""' => sub { shift->name }, # stringify to tc name
15 use Scalar::Util qw(blessed refaddr);
16 use Sub::Name qw(subname);
19 use base qw(Class::MOP::Object);
21 __PACKAGE__->meta->add_attribute('name' => (
23 Class::MOP::_definition_context(),
25 __PACKAGE__->meta->add_attribute('parent' => (
27 predicate => 'has_parent',
28 Class::MOP::_definition_context(),
31 my $null_constraint = sub { 1 };
32 __PACKAGE__->meta->add_attribute('constraint' => (
33 reader => 'constraint',
34 writer => '_set_constraint',
35 default => sub { $null_constraint },
36 Class::MOP::_definition_context(),
39 __PACKAGE__->meta->add_attribute('message' => (
40 accessor => 'message',
41 predicate => 'has_message',
42 Class::MOP::_definition_context(),
45 __PACKAGE__->meta->add_attribute('_default_message' => (
46 accessor => '_default_message',
47 Class::MOP::_definition_context(),
50 # can't make this a default because it has to close over the type name, and
51 # cmop attributes don't have lazy
52 my $_default_message_generator = sub {
56 # have to load it late like this, since it uses Moose itself
57 my $can_partialdump = try {
58 # versions prior to 0.14 had a potential infinite loop bug
59 Class::MOP::load_class('Devel::PartialDump', { -version => 0.14 });
62 if ($can_partialdump) {
63 $value = Devel::PartialDump->new->dump($value);
66 $value = (defined $value ? overload::StrVal($value) : 'undef');
68 return "Validation failed for '" . $name . "' with value $value";
71 __PACKAGE__->meta->add_attribute('coercion' => (
72 accessor => 'coercion',
73 predicate => 'has_coercion',
74 Class::MOP::_definition_context(),
77 __PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
78 init_arg => 'optimized',
79 accessor => 'hand_optimized_type_constraint',
80 predicate => 'has_hand_optimized_type_constraint',
81 Class::MOP::_definition_context(),
84 __PACKAGE__->meta->add_attribute('inlined' => (
85 init_arg => 'inlined',
86 accessor => 'inlined',
87 predicate => '_has_inlined_type_constraint',
88 Class::MOP::_definition_context(),
91 __PACKAGE__->meta->add_attribute('inline_environment' => (
92 init_arg => 'inline_environment',
93 accessor => '_inline_environment',
94 default => sub { {} },
95 Class::MOP::_definition_context(),
105 __PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
106 accessor => '_compiled_type_constraint',
107 predicate => '_has_compiled_type_constraint',
108 Class::MOP::_definition_context(),
111 __PACKAGE__->meta->add_attribute('package_defined_in' => (
112 accessor => '_package_defined_in',
113 Class::MOP::_definition_context(),
118 my ($first, @rest) = @_;
119 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
120 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
122 if ( exists $args{message}
123 && (!ref($args{message}) || ref($args{message}) ne 'CODE') ) {
124 confess("The 'message' parameter must be a coderef");
127 my $self = $class->_new(%args);
128 $self->compile_type_constraint()
129 unless $self->_has_compiled_type_constraint;
130 $self->_default_message($_default_message_generator->($self->name))
131 unless $self->has_message;
140 my $coercion = $self->coercion;
144 Moose->throw_error("Cannot coerce without a type coercion");
147 return $_[0] if $self->check($_[0]);
149 return $coercion->coerce(@_);
155 my $coercion = $self->coercion;
159 Moose->throw_error("Cannot coerce without a type coercion");
162 return $_[0] if $self->check($_[0]);
164 my $result = $coercion->coerce(@_);
166 $self->assert_valid($result);
172 my ($self, @args) = @_;
173 my $constraint_subref = $self->_compiled_type_constraint;
174 return $constraint_subref->(@args) ? 1 : undef;
178 my ($self, $value) = @_;
179 if ($self->_compiled_type_constraint->($value)) {
183 $self->get_message($value);
190 if ( $self->has_parent && $self->constraint == $null_constraint ) {
191 return $self->parent->can_be_inlined;
194 return $self->_has_inlined_type_constraint;
200 unless ( $self->can_be_inlined ) {
202 Moose->throw_error( 'Cannot inline a type constraint check for ' . $self->name );
205 if ( $self->has_parent && $self->constraint == $null_constraint ) {
206 return $self->parent->_inline_check(@_);
209 return '( do { ' . $self->inlined->( $self, @_ ) . ' } )';
212 sub inline_environment {
215 if ( $self->has_parent && $self->constraint == $null_constraint ) {
216 return $self->parent->inline_environment;
219 return $self->_inline_environment;
223 my ($self, $value) = @_;
225 my $error = $self->validate($value);
226 return 1 if ! defined $error;
229 Moose->throw_error($error);
233 my ($self, $value) = @_;
234 my $msg = $self->has_message
236 : $self->_default_message;
238 return $msg->($value);
241 ## type predicates ...
244 my ( $self, $type_or_name ) = @_;
246 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
248 return 1 if $self == $other;
250 if ( $self->has_hand_optimized_type_constraint and $other->has_hand_optimized_type_constraint ) {
251 return 1 if $self->hand_optimized_type_constraint == $other->hand_optimized_type_constraint;
254 return unless $self->constraint == $other->constraint;
256 if ( $self->has_parent ) {
257 return unless $other->has_parent;
258 return unless $self->parent->equals( $other->parent );
260 return if $other->has_parent;
267 my ($self, $type_or_name) = @_;
269 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
271 ($self->equals($type) || $self->is_subtype_of($type));
275 my ($self, $type_or_name) = @_;
277 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
281 while (my $parent = $current->parent) {
282 return 1 if $parent->equals($type);
289 ## compiling the type constraint
291 sub compile_type_constraint {
293 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
296 ## type compilers ...
298 sub _actually_compile_type_constraint {
301 return $self->_compile_hand_optimized_type_constraint
302 if $self->has_hand_optimized_type_constraint;
304 if ( $self->can_be_inlined ) {
306 source => 'sub { ' . $self->_inline_check('$_[0]') . ' }',
307 environment => $self->inline_environment,
311 my $check = $self->constraint;
312 unless ( defined $check ) {
314 Moose->throw_error( "Could not compile type constraint '"
316 . "' because no constraint check" );
319 return $self->_compile_subtype($check)
320 if $self->has_parent;
322 return $self->_compile_type($check);
325 sub _compile_hand_optimized_type_constraint {
328 my $type_constraint = $self->hand_optimized_type_constraint;
330 unless ( ref $type_constraint ) {
332 Moose->throw_error("Hand optimized type constraint is not a code reference");
335 return $type_constraint;
338 sub _compile_subtype {
339 my ($self, $check) = @_;
341 # gather all the parent constraintss in order
343 my $optimized_parent;
344 foreach my $parent ($self->_collect_all_parents) {
345 # if a parent is optimized, the optimized constraint already includes
346 # all of its parents tcs, so we can break the loop
347 if ($parent->has_hand_optimized_type_constraint) {
348 push @parents => $optimized_parent = $parent->hand_optimized_type_constraint;
352 push @parents => $parent->constraint;
356 @parents = grep { $_ != $null_constraint } reverse @parents;
358 unless ( @parents ) {
359 return $self->_compile_type($check);
360 } elsif( $optimized_parent and @parents == 1 ) {
361 # the case of just one optimized parent is optimized to prevent
362 # looping and the unnecessary localization
363 if ( $check == $null_constraint ) {
364 return $optimized_parent;
366 return subname($self->name, sub {
367 return undef unless $optimized_parent->($_[0]);
374 # general case, check all the constraints, from the first parent to ourselves
375 my @checks = @parents;
376 push @checks, $check if $check != $null_constraint;
377 return subname($self->name => sub {
380 foreach my $check (@checks) {
381 return undef unless $check->(@args);
389 my ($self, $check) = @_;
391 return $check if $check == $null_constraint; # Item, Any
393 return subname($self->name => sub {
402 sub _collect_all_parents {
405 my $current = $self->parent;
406 while (defined $current) {
407 push @parents => $current;
408 $current = $current->parent;
413 sub create_child_type {
414 my ($self, %opts) = @_;
415 my $class = ref $self;
416 return $class->new(%opts, parent => $self);
421 # ABSTRACT: The Moose Type Constraint metaclass
429 This class represents a single type constraint. Moose's built-in type
430 constraints, as well as constraints you define, are all stored in a
431 L<Moose::Meta::TypeConstraint::Registry> object as objects of this
436 C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>.
442 =item B<< Moose::Meta::TypeConstraint->new(%options) >>
444 This creates a new type constraint based on the provided C<%options>:
450 The constraint name. If a name is not provided, it will be set to
455 A C<Moose::Meta::TypeConstraint> object which is the parent type for
456 the type being created. This is optional.
460 This is the subroutine reference that implements the actual constraint
461 check. This defaults to a subroutine which always returns true.
465 A subroutine reference which is used to generate an error message when
466 the constraint fails. This is optional.
470 A L<Moose::Meta::TypeCoercion> object representing the coercions to
471 the type. This is optional.
475 A subroutine which returns a string suitable for inlining this type
476 constraint. It will be called as a method on the type constraint object, and
477 will receive a single additional parameter, a variable name to be tested
478 (usually C<"$_"> or C<"$_[0]">.
482 =item * inline_environment
484 A hash reference of variables to close over. The keys are variables names, and
485 the values are I<references> to the variables.
489 B<This option is deprecated.>
491 This is a variant of the C<constraint> parameter that is somehow
492 optimized. Typically, this means incorporating both the type's
493 constraint and all of its parents' constraints into a single
494 subroutine reference.
498 =item B<< $constraint->equals($type_name_or_object) >>
500 Returns true if the supplied name or type object is the same as the
503 =item B<< $constraint->is_subtype_of($type_name_or_object) >>
505 Returns true if the supplied name or type object is a parent of the
508 =item B<< $constraint->is_a_type_of($type_name_or_object) >>
510 Returns true if the given type is the same as the current type, or is
511 a parent of the current type. This is a shortcut for checking
512 C<equals> and C<is_subtype_of>.
514 =item B<< $constraint->coerce($value) >>
516 This will attempt to coerce the value to the type. If the type does not
517 have any defined coercions this will throw an error.
519 If no coercion can produce a value matching C<$constraint>, the original
522 =item B<< $constraint->assert_coerce($value) >>
524 This method behaves just like C<coerce>, but if the result is not valid
525 according to C<$constraint>, an error is thrown.
527 =item B<< $constraint->check($value) >>
529 Returns true if the given value passes the constraint for the type.
531 =item B<< $constraint->validate($value) >>
533 This is similar to C<check>. However, if the type I<is valid> then the
534 method returns an explicit C<undef>. If the type is not valid, we call
535 C<< $self->get_message($value) >> internally to generate an error
538 =item B<< $constraint->assert_valid($value) >>
540 Like C<check> and C<validate>, this method checks whether C<$value> is
541 valid under the constraint. If it is, it will return true. If it is not,
542 an exception will be thrown with the results of
543 C<< $self->get_message($value) >>.
545 =item B<< $constraint->name >>
547 Returns the type's name, as provided to the constructor.
549 =item B<< $constraint->parent >>
551 Returns the type's parent, as provided to the constructor, if any.
553 =item B<< $constraint->has_parent >>
555 Returns true if the type has a parent type.
557 =item B<< $constraint->parents >>
559 A synonym for C<parent>. This is useful for polymorphism with types
560 that can have more than one parent.
562 =item B<< $constraint->constraint >>
564 Returns the type's constraint, as provided to the constructor.
566 =item B<< $constraint->get_message($value) >>
568 This generates a method for the given value. If the type does not have
569 an explicit message, we generate a default message.
571 =item B<< $constraint->has_message >>
573 Returns true if the type has a message.
575 =item B<< $constraint->message >>
577 Returns the type's message as a subroutine reference.
579 =item B<< $constraint->coercion >>
581 Returns the type's L<Moose::Meta::TypeCoercion> object, if one
584 =item B<< $constraint->has_coercion >>
586 Returns true if the type has a coercion.
588 =item B<< $constraint->can_be_inlined >>
590 Returns true if this type constraint can be inlined. A type constraint which
591 subtypes an inlinable constraint and does not add an additional constraint
592 "inherits" its parent type's inlining.
594 =item B<< $constraint->hand_optimized_type_constraint >>
596 B<This method is deprecated.>
598 Returns the type's hand optimized constraint, as provided to the
599 constructor via the C<optimized> option.
601 =item B<< $constraint->has_hand_optimized_type_constraint >>
603 B<This method is deprecated.>
605 Returns true if the type has an optimized constraint.
607 =item B<< $constraint->create_child_type(%options) >>
609 This returns a new type constraint of the same class using the
610 provided C<%options>. The C<parent> option will be the current type.
612 This method exists so that subclasses of this class can override this
613 behavior and change how child types are created.
619 See L<Moose/BUGS> for details on reporting bugs.