2 package Moose::Meta::TypeConstraint;
8 use overload '0+' => sub { refaddr(shift) }, # id an object
9 '""' => sub { shift->name }, # stringify to tc name
13 use Scalar::Util qw(blessed refaddr);
14 use Sub::Name qw(subname);
17 use base qw(Class::MOP::Object);
19 __PACKAGE__->meta->add_attribute('name' => (reader => 'name'));
20 __PACKAGE__->meta->add_attribute('parent' => (
22 predicate => 'has_parent',
25 my $null_constraint = sub { 1 };
26 __PACKAGE__->meta->add_attribute('constraint' => (
27 reader => 'constraint',
28 writer => '_set_constraint',
29 default => sub { $null_constraint }
31 __PACKAGE__->meta->add_attribute('message' => (
32 accessor => 'message',
33 predicate => 'has_message'
35 __PACKAGE__->meta->add_attribute('coercion' => (
36 accessor => 'coercion',
37 predicate => 'has_coercion'
40 __PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
41 init_arg => 'optimized',
42 accessor => 'hand_optimized_type_constraint',
43 predicate => 'has_hand_optimized_type_constraint',
46 __PACKAGE__->meta->add_attribute('inlined' => (
47 init_arg => 'inlined',
48 accessor => 'inlined',
49 predicate => '_has_inlined_type_constraint',
59 __PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
60 accessor => '_compiled_type_constraint',
61 predicate => '_has_compiled_type_constraint'
63 __PACKAGE__->meta->add_attribute('package_defined_in' => (
64 accessor => '_package_defined_in'
69 my ($first, @rest) = @_;
70 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
71 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
73 my $self = $class->_new(%args);
74 $self->compile_type_constraint()
75 unless $self->_has_compiled_type_constraint;
84 my $coercion = $self->coercion;
88 Moose->throw_error("Cannot coerce without a type coercion");
91 return $_[0] if $self->check($_[0]);
93 return $coercion->coerce(@_);
99 my $coercion = $self->coercion;
103 Moose->throw_error("Cannot coerce without a type coercion");
106 return $_[0] if $self->check($_[0]);
108 my $result = $coercion->coerce(@_);
110 $self->assert_valid($result);
116 my ($self, @args) = @_;
117 my $constraint_subref = $self->_compiled_type_constraint;
118 return $constraint_subref->(@args) ? 1 : undef;
122 my ($self, $value) = @_;
123 if ($self->_compiled_type_constraint->($value)) {
127 $self->get_message($value);
131 sub has_inlined_type_constraint {
134 if ( $self->has_parent && $self->constraint eq $null_constraint ) {
135 return $self->parent->has_inlined_type_constraint;
138 return $self->_has_inlined_type_constraint;
144 unless ( $self->has_inlined_type_constraint ) {
146 Moose->throw_error( 'Cannot inline a type constraint check for ' . $self->name );
149 if ( $self->has_parent && $self->constraint eq $null_constraint ) {
150 return $self->parent->_inline_check(@_);
153 return $self->inlined->( $self, @_ );
157 my ($self, $value) = @_;
159 my $error = $self->validate($value);
160 return 1 if ! defined $error;
163 Moose->throw_error($error);
167 my ($self, $value) = @_;
168 if (my $msg = $self->message) {
170 return $msg->($value);
173 # have to load it late like this, since it uses Moose itself
174 my $can_partialdump = try {
175 # versions prior to 0.14 had a potential infinite loop bug
176 Class::MOP::load_class('Devel::PartialDump', { -version => 0.14 });
179 if ($can_partialdump) {
180 $value = Devel::PartialDump->new->dump($value);
183 $value = (defined $value ? overload::StrVal($value) : 'undef');
185 return "Validation failed for '" . $self->name . "' with value $value";
189 ## type predicates ...
192 my ( $self, $type_or_name ) = @_;
194 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
196 return 1 if $self == $other;
198 if ( $self->has_hand_optimized_type_constraint and $other->has_hand_optimized_type_constraint ) {
199 return 1 if $self->hand_optimized_type_constraint == $other->hand_optimized_type_constraint;
202 return unless $self->constraint == $other->constraint;
204 if ( $self->has_parent ) {
205 return unless $other->has_parent;
206 return unless $self->parent->equals( $other->parent );
208 return if $other->has_parent;
215 my ($self, $type_or_name) = @_;
217 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
219 ($self->equals($type) || $self->is_subtype_of($type));
223 my ($self, $type_or_name) = @_;
225 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
229 while (my $parent = $current->parent) {
230 return 1 if $parent->equals($type);
237 ## compiling the type constraint
239 sub compile_type_constraint {
241 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
244 ## type compilers ...
246 sub _actually_compile_type_constraint {
249 return $self->_compile_hand_optimized_type_constraint
250 if $self->has_hand_optimized_type_constraint;
252 if ( $self->has_inlined_type_constraint ) {
254 my $sub = eval 'sub { ' . $self->_inline_check('$_[0]') . '}';
260 my $check = $self->constraint;
261 unless ( defined $check ) {
263 Moose->throw_error( "Could not compile type constraint '"
265 . "' because no constraint check" );
268 return $self->_compile_subtype($check)
269 if $self->has_parent;
271 return $self->_compile_type($check);
274 sub _compile_hand_optimized_type_constraint {
277 my $type_constraint = $self->hand_optimized_type_constraint;
279 unless ( ref $type_constraint ) {
281 Moose->throw_error("Hand optimized type constraint is not a code reference");
284 return $type_constraint;
287 sub _compile_subtype {
288 my ($self, $check) = @_;
290 # gather all the parent constraintss in order
292 my $optimized_parent;
293 foreach my $parent ($self->_collect_all_parents) {
294 # if a parent is optimized, the optimized constraint already includes
295 # all of its parents tcs, so we can break the loop
296 if ($parent->has_hand_optimized_type_constraint) {
297 push @parents => $optimized_parent = $parent->hand_optimized_type_constraint;
301 push @parents => $parent->constraint;
305 @parents = grep { $_ != $null_constraint } reverse @parents;
307 unless ( @parents ) {
308 return $self->_compile_type($check);
309 } elsif( $optimized_parent and @parents == 1 ) {
310 # the case of just one optimized parent is optimized to prevent
311 # looping and the unnecessary localization
312 if ( $check == $null_constraint ) {
313 return $optimized_parent;
315 return subname($self->name, sub {
316 return undef unless $optimized_parent->($_[0]);
323 # general case, check all the constraints, from the first parent to ourselves
324 my @checks = @parents;
325 push @checks, $check if $check != $null_constraint;
326 return subname($self->name => sub {
329 foreach my $check (@checks) {
330 return undef unless $check->(@args);
338 my ($self, $check) = @_;
340 return $check if $check == $null_constraint; # Item, Any
342 return subname($self->name => sub {
351 sub _collect_all_parents {
354 my $current = $self->parent;
355 while (defined $current) {
356 push @parents => $current;
357 $current = $current->parent;
362 sub create_child_type {
363 my ($self, %opts) = @_;
364 my $class = ref $self;
365 return $class->new(%opts, parent => $self);
370 # ABSTRACT: The Moose Type Constraint metaclass
378 This class represents a single type constraint. Moose's built-in type
379 constraints, as well as constraints you define, are all stored in a
380 L<Moose::Meta::TypeConstraint::Registry> object as objects of this
385 C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>.
391 =item B<< Moose::Meta::TypeConstraint->new(%options) >>
393 This creates a new type constraint based on the provided C<%options>:
399 The constraint name. If a name is not provided, it will be set to
404 A C<Moose::Meta::TypeConstraint> object which is the parent type for
405 the type being created. This is optional.
409 This is the subroutine reference that implements the actual constraint
410 check. This defaults to a subroutine which always returns true.
414 A subroutine reference which is used to generate an error message when
415 the constraint fails. This is optional.
419 A L<Moose::Meta::TypeCoercion> object representing the coercions to
420 the type. This is optional.
424 This is a variant of the C<constraint> parameter that is somehow
425 optimized. Typically, this means incorporating both the type's
426 constraint and all of its parents' constraints into a single
427 subroutine reference.
431 =item B<< $constraint->equals($type_name_or_object) >>
433 Returns true if the supplied name or type object is the same as the
436 =item B<< $constraint->is_subtype_of($type_name_or_object) >>
438 Returns true if the supplied name or type object is a parent of the
441 =item B<< $constraint->is_a_type_of($type_name_or_object) >>
443 Returns true if the given type is the same as the current type, or is
444 a parent of the current type. This is a shortcut for checking
445 C<equals> and C<is_subtype_of>.
447 =item B<< $constraint->coerce($value) >>
449 This will attempt to coerce the value to the type. If the type does not
450 have any defined coercions this will throw an error.
452 If no coercion can produce a value matching C<$constraint>, the original
455 =item B<< $constraint->assert_coerce($value) >>
457 This method behaves just like C<coerce>, but if the result is not valid
458 according to C<$constraint>, an error is thrown.
460 =item B<< $constraint->check($value) >>
462 Returns true if the given value passes the constraint for the type.
464 =item B<< $constraint->validate($value) >>
466 This is similar to C<check>. However, if the type I<is valid> then the
467 method returns an explicit C<undef>. If the type is not valid, we call
468 C<< $self->get_message($value) >> internally to generate an error
471 =item B<< $constraint->assert_valid($value) >>
473 Like C<check> and C<validate>, this method checks whether C<$value> is
474 valid under the constraint. If it is, it will return true. If it is not,
475 an exception will be thrown with the results of
476 C<< $self->get_message($value) >>.
478 =item B<< $constraint->name >>
480 Returns the type's name, as provided to the constructor.
482 =item B<< $constraint->parent >>
484 Returns the type's parent, as provided to the constructor, if any.
486 =item B<< $constraint->has_parent >>
488 Returns true if the type has a parent type.
490 =item B<< $constraint->parents >>
492 A synonym for C<parent>. This is useful for polymorphism with types
493 that can have more than one parent.
495 =item B<< $constraint->constraint >>
497 Returns the type's constraint, as provided to the constructor.
499 =item B<< $constraint->get_message($value) >>
501 This generates a method for the given value. If the type does not have
502 an explicit message, we generate a default message.
504 =item B<< $constraint->has_message >>
506 Returns true if the type has a message.
508 =item B<< $constraint->message >>
510 Returns the type's message as a subroutine reference.
512 =item B<< $constraint->coercion >>
514 Returns the type's L<Moose::Meta::TypeCoercion> object, if one
517 =item B<< $constraint->has_coercion >>
519 Returns true if the type has a coercion.
521 =item B<< $constraint->hand_optimized_type_constraint >>
523 Returns the type's hand optimized constraint, as provided to the
524 constructor via the C<optimized> option.
526 =item B<< $constraint->has_hand_optimized_type_constraint >>
528 Returns true if the type has an optimized constraint.
530 =item B<< $constraint->create_child_type(%options) >>
532 This returns a new type constraint of the same class using the
533 provided C<%options>. The C<parent> option will be the current type.
535 This method exists so that subclasses of this class can override this
536 behavior and change how child types are created.
542 See L<Moose/BUGS> for details on reporting bugs.