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',
60 __PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
61 accessor => '_compiled_type_constraint',
62 predicate => '_has_compiled_type_constraint'
64 __PACKAGE__->meta->add_attribute('package_defined_in' => (
65 accessor => '_package_defined_in'
70 my ($first, @rest) = @_;
71 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
72 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
74 my $self = $class->_new(%args);
75 $self->compile_type_constraint()
76 unless $self->_has_compiled_type_constraint;
85 my $coercion = $self->coercion;
89 Moose->throw_error("Cannot coerce without a type coercion");
92 return $_[0] if $self->check($_[0]);
94 return $coercion->coerce(@_);
100 my $coercion = $self->coercion;
104 Moose->throw_error("Cannot coerce without a type coercion");
107 return $_[0] if $self->check($_[0]);
109 my $result = $coercion->coerce(@_);
111 $self->assert_valid($result);
117 my ($self, @args) = @_;
118 my $constraint_subref = $self->_compiled_type_constraint;
119 return $constraint_subref->(@args) ? 1 : undef;
123 my ($self, $value) = @_;
124 if ($self->_compiled_type_constraint->($value)) {
128 $self->get_message($value);
132 sub has_inlined_type_constraint {
135 if ( $self->has_parent && $self->constraint == $null_constraint ) {
136 return $self->parent->has_inlined_type_constraint;
139 return $self->_has_inlined_type_constraint;
145 unless ( $self->has_inlined_type_constraint ) {
147 Moose->throw_error( 'Cannot inline a type constraint check for ' . $self->name );
150 if ( $self->has_parent && $self->constraint == $null_constraint ) {
151 return $self->parent->_inline_check(@_);
154 return $self->inlined->( $self, @_ );
158 my ($self, $value) = @_;
160 my $error = $self->validate($value);
161 return 1 if ! defined $error;
164 Moose->throw_error($error);
168 my ($self, $value) = @_;
169 if (my $msg = $self->message) {
171 return $msg->($value);
174 # have to load it late like this, since it uses Moose itself
175 my $can_partialdump = try {
176 # versions prior to 0.14 had a potential infinite loop bug
177 Class::MOP::load_class('Devel::PartialDump', { -version => 0.14 });
180 if ($can_partialdump) {
181 $value = Devel::PartialDump->new->dump($value);
184 $value = (defined $value ? overload::StrVal($value) : 'undef');
186 return "Validation failed for '" . $self->name . "' with value $value";
190 ## type predicates ...
193 my ( $self, $type_or_name ) = @_;
195 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
197 return 1 if $self == $other;
199 if ( $self->has_hand_optimized_type_constraint and $other->has_hand_optimized_type_constraint ) {
200 return 1 if $self->hand_optimized_type_constraint == $other->hand_optimized_type_constraint;
203 return unless $self->constraint == $other->constraint;
205 if ( $self->has_parent ) {
206 return unless $other->has_parent;
207 return unless $self->parent->equals( $other->parent );
209 return if $other->has_parent;
216 my ($self, $type_or_name) = @_;
218 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
220 ($self->equals($type) || $self->is_subtype_of($type));
224 my ($self, $type_or_name) = @_;
226 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
230 while (my $parent = $current->parent) {
231 return 1 if $parent->equals($type);
238 ## compiling the type constraint
240 sub compile_type_constraint {
242 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
245 ## type compilers ...
247 sub _actually_compile_type_constraint {
250 return $self->_compile_hand_optimized_type_constraint
251 if $self->has_hand_optimized_type_constraint;
253 if ( $self->has_inlined_type_constraint ) {
255 source => 'sub { ' . $self->_inline_check('$_[0]') . ' }',
259 my $check = $self->constraint;
260 unless ( defined $check ) {
262 Moose->throw_error( "Could not compile type constraint '"
264 . "' because no constraint check" );
267 return $self->_compile_subtype($check)
268 if $self->has_parent;
270 return $self->_compile_type($check);
273 sub _compile_hand_optimized_type_constraint {
276 my $type_constraint = $self->hand_optimized_type_constraint;
278 unless ( ref $type_constraint ) {
280 Moose->throw_error("Hand optimized type constraint is not a code reference");
283 return $type_constraint;
286 sub _compile_subtype {
287 my ($self, $check) = @_;
289 # gather all the parent constraintss in order
291 my $optimized_parent;
292 foreach my $parent ($self->_collect_all_parents) {
293 # if a parent is optimized, the optimized constraint already includes
294 # all of its parents tcs, so we can break the loop
295 if ($parent->has_hand_optimized_type_constraint) {
296 push @parents => $optimized_parent = $parent->hand_optimized_type_constraint;
300 push @parents => $parent->constraint;
304 @parents = grep { $_ != $null_constraint } reverse @parents;
306 unless ( @parents ) {
307 return $self->_compile_type($check);
308 } elsif( $optimized_parent and @parents == 1 ) {
309 # the case of just one optimized parent is optimized to prevent
310 # looping and the unnecessary localization
311 if ( $check == $null_constraint ) {
312 return $optimized_parent;
314 return subname($self->name, sub {
315 return undef unless $optimized_parent->($_[0]);
322 # general case, check all the constraints, from the first parent to ourselves
323 my @checks = @parents;
324 push @checks, $check if $check != $null_constraint;
325 return subname($self->name => sub {
328 foreach my $check (@checks) {
329 return undef unless $check->(@args);
337 my ($self, $check) = @_;
339 return $check if $check == $null_constraint; # Item, Any
341 return subname($self->name => sub {
350 sub _collect_all_parents {
353 my $current = $self->parent;
354 while (defined $current) {
355 push @parents => $current;
356 $current = $current->parent;
361 sub create_child_type {
362 my ($self, %opts) = @_;
363 my $class = ref $self;
364 return $class->new(%opts, parent => $self);
369 # ABSTRACT: The Moose Type Constraint metaclass
377 This class represents a single type constraint. Moose's built-in type
378 constraints, as well as constraints you define, are all stored in a
379 L<Moose::Meta::TypeConstraint::Registry> object as objects of this
384 C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>.
390 =item B<< Moose::Meta::TypeConstraint->new(%options) >>
392 This creates a new type constraint based on the provided C<%options>:
398 The constraint name. If a name is not provided, it will be set to
403 A C<Moose::Meta::TypeConstraint> object which is the parent type for
404 the type being created. This is optional.
408 This is the subroutine reference that implements the actual constraint
409 check. This defaults to a subroutine which always returns true.
413 A subroutine reference which is used to generate an error message when
414 the constraint fails. This is optional.
418 A L<Moose::Meta::TypeCoercion> object representing the coercions to
419 the type. This is optional.
423 This is a variant of the C<constraint> parameter that is somehow
424 optimized. Typically, this means incorporating both the type's
425 constraint and all of its parents' constraints into a single
426 subroutine reference.
430 =item B<< $constraint->equals($type_name_or_object) >>
432 Returns true if the supplied name or type object is the same as the
435 =item B<< $constraint->is_subtype_of($type_name_or_object) >>
437 Returns true if the supplied name or type object is a parent of the
440 =item B<< $constraint->is_a_type_of($type_name_or_object) >>
442 Returns true if the given type is the same as the current type, or is
443 a parent of the current type. This is a shortcut for checking
444 C<equals> and C<is_subtype_of>.
446 =item B<< $constraint->coerce($value) >>
448 This will attempt to coerce the value to the type. If the type does not
449 have any defined coercions this will throw an error.
451 If no coercion can produce a value matching C<$constraint>, the original
454 =item B<< $constraint->assert_coerce($value) >>
456 This method behaves just like C<coerce>, but if the result is not valid
457 according to C<$constraint>, an error is thrown.
459 =item B<< $constraint->check($value) >>
461 Returns true if the given value passes the constraint for the type.
463 =item B<< $constraint->validate($value) >>
465 This is similar to C<check>. However, if the type I<is valid> then the
466 method returns an explicit C<undef>. If the type is not valid, we call
467 C<< $self->get_message($value) >> internally to generate an error
470 =item B<< $constraint->assert_valid($value) >>
472 Like C<check> and C<validate>, this method checks whether C<$value> is
473 valid under the constraint. If it is, it will return true. If it is not,
474 an exception will be thrown with the results of
475 C<< $self->get_message($value) >>.
477 =item B<< $constraint->name >>
479 Returns the type's name, as provided to the constructor.
481 =item B<< $constraint->parent >>
483 Returns the type's parent, as provided to the constructor, if any.
485 =item B<< $constraint->has_parent >>
487 Returns true if the type has a parent type.
489 =item B<< $constraint->parents >>
491 A synonym for C<parent>. This is useful for polymorphism with types
492 that can have more than one parent.
494 =item B<< $constraint->constraint >>
496 Returns the type's constraint, as provided to the constructor.
498 =item B<< $constraint->get_message($value) >>
500 This generates a method for the given value. If the type does not have
501 an explicit message, we generate a default message.
503 =item B<< $constraint->has_message >>
505 Returns true if the type has a message.
507 =item B<< $constraint->message >>
509 Returns the type's message as a subroutine reference.
511 =item B<< $constraint->coercion >>
513 Returns the type's L<Moose::Meta::TypeCoercion> object, if one
516 =item B<< $constraint->has_coercion >>
518 Returns true if the type has a coercion.
520 =item B<< $constraint->hand_optimized_type_constraint >>
522 Returns the type's hand optimized constraint, as provided to the
523 constructor via the C<optimized> option.
525 =item B<< $constraint->has_hand_optimized_type_constraint >>
527 Returns true if the type has an optimized constraint.
529 =item B<< $constraint->create_child_type(%options) >>
531 This returns a new type constraint of the same class using the
532 provided C<%options>. The C<parent> option will be the current type.
534 This method exists so that subclasses of this class can override this
535 behavior and change how child types are created.
541 See L<Moose/BUGS> for details on reporting bugs.