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);
16 use base qw(Class::MOP::Object);
18 our $AUTHORITY = 'cpan:STEVAN';
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',
54 __PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
55 accessor => '_compiled_type_constraint',
56 predicate => '_has_compiled_type_constraint'
58 __PACKAGE__->meta->add_attribute('package_defined_in' => (
59 accessor => '_package_defined_in'
64 my ($first, @rest) = @_;
65 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
66 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
68 my $self = $class->_new(%args);
69 $self->compile_type_constraint()
70 unless $self->_has_compiled_type_constraint;
79 my $coercion = $self->coercion;
83 Moose->throw_error("Cannot coerce without a type coercion");
86 return $_[0] if $self->check($_[0]);
88 return $coercion->coerce(@_);
94 my $coercion = $self->coercion;
98 Moose->throw_error("Cannot coerce without a type coercion");
101 return $_[0] if $self->check($_[0]);
103 my $result = $coercion->coerce(@_);
105 $self->assert_valid($result);
111 my ($self, @args) = @_;
112 my $constraint_subref = $self->_compiled_type_constraint;
113 return $constraint_subref->(@args) ? 1 : undef;
117 my ($self, $value) = @_;
118 if ($self->_compiled_type_constraint->($value)) {
122 $self->get_message($value);
127 my ($self, $value) = @_;
129 my $error = $self->validate($value);
130 return 1 if ! defined $error;
133 Moose->throw_error($error);
137 my ($self, $value) = @_;
138 if (my $msg = $self->message) {
140 return $msg->($value);
143 $value = (defined $value ? overload::StrVal($value) : 'undef');
144 return "Validation failed for '" . $self->name . "' with value $value";
148 ## type predicates ...
151 my ( $self, $type_or_name ) = @_;
153 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
155 return 1 if $self == $other;
157 if ( $self->has_hand_optimized_type_constraint and $other->has_hand_optimized_type_constraint ) {
158 return 1 if $self->hand_optimized_type_constraint == $other->hand_optimized_type_constraint;
161 return unless $self->constraint == $other->constraint;
163 if ( $self->has_parent ) {
164 return unless $other->has_parent;
165 return unless $self->parent->equals( $other->parent );
167 return if $other->has_parent;
174 my ($self, $type_or_name) = @_;
176 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
178 ($self->equals($type) || $self->is_subtype_of($type));
182 my ($self, $type_or_name) = @_;
184 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
188 while (my $parent = $current->parent) {
189 return 1 if $parent->equals($type);
196 ## compiling the type constraint
198 sub compile_type_constraint {
200 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
203 ## type compilers ...
205 sub _actually_compile_type_constraint {
208 return $self->_compile_hand_optimized_type_constraint
209 if $self->has_hand_optimized_type_constraint;
211 my $check = $self->constraint;
212 unless ( defined $check ) {
214 Moose->throw_error( "Could not compile type constraint '"
216 . "' because no constraint check" );
219 return $self->_compile_subtype($check)
220 if $self->has_parent;
222 return $self->_compile_type($check);
225 sub _compile_hand_optimized_type_constraint {
228 my $type_constraint = $self->hand_optimized_type_constraint;
230 unless ( ref $type_constraint ) {
232 Carp::confess ("Hand optimized type constraint for " . $self->name . " is not a code reference");
233 Moose->throw_error("Hand optimized type constraint is not a code reference");
236 return $type_constraint;
239 sub _compile_subtype {
240 my ($self, $check) = @_;
242 # gather all the parent constraintss in order
244 my $optimized_parent;
245 foreach my $parent ($self->_collect_all_parents) {
246 # if a parent is optimized, the optimized constraint already includes
247 # all of its parents tcs, so we can break the loop
248 if ($parent->has_hand_optimized_type_constraint) {
249 push @parents => $optimized_parent = $parent->hand_optimized_type_constraint;
253 push @parents => $parent->constraint;
257 @parents = grep { $_ != $null_constraint } reverse @parents;
259 unless ( @parents ) {
260 return $self->_compile_type($check);
261 } elsif( $optimized_parent and @parents == 1 ) {
262 # the case of just one optimized parent is optimized to prevent
263 # looping and the unnecessary localization
264 if ( $check == $null_constraint ) {
265 return $optimized_parent;
267 return subname($self->name, sub {
268 return undef unless $optimized_parent->($_[0]);
275 # general case, check all the constraints, from the first parent to ourselves
276 my @checks = @parents;
277 push @checks, $check if $check != $null_constraint;
278 return subname($self->name => sub {
281 foreach my $check (@checks) {
282 return undef unless $check->(@args);
290 my ($self, $check) = @_;
292 return $check if $check == $null_constraint; # Item, Any
294 return subname($self->name => sub {
303 sub _collect_all_parents {
306 my $current = $self->parent;
307 while (defined $current) {
308 push @parents => $current;
309 $current = $current->parent;
314 sub create_child_type {
315 my ($self, %opts) = @_;
316 my $class = ref $self;
317 return $class->new(%opts, parent => $self);
322 # ABSTRACT: The Moose Type Constraint metaclass
330 This class represents a single type constraint. Moose's built-in type
331 constraints, as well as constraints you define, are all stored in a
332 L<Moose::Meta::TypeConstraint::Registry> object as objects of this
337 C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>.
343 =item B<< Moose::Meta::TypeConstraint->new(%options) >>
345 This creates a new type constraint based on the provided C<%options>:
351 The constraint name. If a name is not provided, it will be set to
356 A C<Moose::Meta::TypeConstraint> object which is the parent type for
357 the type being created. This is optional.
361 This is the subroutine reference that implements the actual constraint
362 check. This defaults to a subroutine which always returns true.
366 A subroutine reference which is used to generate an error message when
367 the constraint fails. This is optional.
371 A L<Moose::Meta::TypeCoercion> object representing the coercions to
372 the type. This is optional.
376 This is a variant of the C<constraint> parameter that is somehow
377 optimized. Typically, this means incorporating both the type's
378 constraint and all of its parents' constraints into a single
379 subroutine reference.
383 =item B<< $constraint->equals($type_name_or_object) >>
385 Returns true if the supplied name or type object is the same as the
388 =item B<< $constraint->is_subtype_of($type_name_or_object) >>
390 Returns true if the supplied name or type object is a parent of the
393 =item B<< $constraint->is_a_type_of($type_name_or_object) >>
395 Returns true if the given type is the same as the current type, or is
396 a parent of the current type. This is a shortcut for checking
397 C<equals> and C<is_subtype_of>.
399 =item B<< $constraint->coerce($value) >>
401 This will attempt to coerce the value to the type. If the type does not
402 have any defined coercions this will throw an error.
404 If no coercion can produce a value matching C<$constraint>, the original
407 =item B<< $constraint->assert_coerce($value) >>
409 This method behaves just like C<coerce>, but if the result is not valid
410 according to C<$constraint>, an error is thrown.
412 =item B<< $constraint->check($value) >>
414 Returns true if the given value passes the constraint for the type.
416 =item B<< $constraint->validate($value) >>
418 This is similar to C<check>. However, if the type I<is valid> then the
419 method returns an explicit C<undef>. If the type is not valid, we call
420 C<< $self->get_message($value) >> internally to generate an error
423 =item B<< $constraint->assert_valid($value) >>
425 Like C<check> and C<validate>, this method checks whether C<$value> is
426 valid under the constraint. If it is, it will return true. If it is not,
427 an exception will be thrown with the results of
428 C<< $self->get_message($value) >>.
430 =item B<< $constraint->name >>
432 Returns the type's name, as provided to the constructor.
434 =item B<< $constraint->parent >>
436 Returns the type's parent, as provided to the constructor, if any.
438 =item B<< $constraint->has_parent >>
440 Returns true if the type has a parent type.
442 =item B<< $constraint->parents >>
444 A synonym for C<parent>. This is useful for polymorphism with types
445 that can have more than one parent.
447 =item B<< $constraint->constraint >>
449 Returns the type's constraint, as provided to the constructor.
451 =item B<< $constraint->get_message($value) >>
453 This generates a method for the given value. If the type does not have
454 an explicit message, we generate a default message.
456 =item B<< $constraint->has_message >>
458 Returns true if the type has a message.
460 =item B<< $constraint->message >>
462 Returns the type's message as a subroutine reference.
464 =item B<< $constraint->coercion >>
466 Returns the type's L<Moose::Meta::TypeCoercion> object, if one
469 =item B<< $constraint->has_coercion >>
471 Returns true if the type has a coercion.
473 =item B<< $constraint->hand_optimized_type_constraint >>
475 Returns the type's hand optimized constraint, as provided to the
476 constructor via the C<optimized> option.
478 =item B<< $constraint->has_hand_optimized_type_constraint >>
480 Returns true if the type has an optimized constraint.
482 =item B<< $constraint->create_child_type(%options) >>
484 This returns a new type constraint of the same class using the
485 provided C<%options>. The C<parent> option will be the current type.
487 This method exists so that subclasses of this class can override this
488 behavior and change how child types are created.
494 See L<Moose/BUGS> for details on reporting bugs.