2 package Moose::Meta::TypeConstraint;
8 use overload '""' => sub { shift->name }, # stringify to tc name
11 use Sub::Name 'subname';
13 use Scalar::Util 'blessed';
15 our $VERSION = '0.12';
16 our $AUTHORITY = 'cpan:STEVAN';
18 __PACKAGE__->meta->add_attribute('name' => (reader => 'name'));
19 __PACKAGE__->meta->add_attribute('parent' => (
21 predicate => 'has_parent',
23 __PACKAGE__->meta->add_attribute('constraint' => (
24 reader => 'constraint',
25 writer => '_set_constraint',
26 default => sub { sub { 1 } }
28 __PACKAGE__->meta->add_attribute('message' => (
29 accessor => 'message',
30 predicate => 'has_message'
32 __PACKAGE__->meta->add_attribute('coercion' => (
33 accessor => 'coercion',
34 predicate => 'has_coercion'
36 __PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
37 init_arg => 'optimized',
38 accessor => 'hand_optimized_type_constraint',
39 predicate => 'has_hand_optimized_type_constraint',
44 __PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
45 accessor => '_compiled_type_constraint',
46 predicate => '_has_compiled_type_constraint'
48 __PACKAGE__->meta->add_attribute('package_defined_in' => (
49 accessor => '_package_defined_in'
54 my $self = $class->meta->new_object(@_);
55 $self->compile_type_constraint()
56 unless $self->_has_compiled_type_constraint;
60 sub coerce { ((shift)->coercion || confess "Cannot coerce without a type coercion")->coerce(@_) }
61 sub check { $_[0]->_compiled_type_constraint->($_[1]) ? 1 : undef }
63 my ($self, $value) = @_;
64 if ($self->_compiled_type_constraint->($value)) {
68 $self->get_message($value);
73 my ($self, $value) = @_;
74 $value = (defined $value ? overload::StrVal($value) : 'undef');
75 if (my $msg = $self->message) {
77 return $msg->($value);
80 return "Validation failed for '" . $self->name . "' failed with value $value";
84 ## type predicates ...
87 my ( $self, $type_or_name ) = @_;
89 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
91 $self->name eq $type->name;
95 my ($self, $type_or_name) = @_;
97 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
99 ($self->equals($type) || $self->is_subtype_of($type));
103 my ($self, $type_or_name) = @_;
105 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
109 while (my $parent = $current->parent) {
110 return 1 if $parent->equals($type);
117 ## compiling the type constraint
119 sub compile_type_constraint {
121 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
124 ## type compilers ...
126 sub _actually_compile_type_constraint {
129 return $self->_compile_hand_optimized_type_constraint
130 if $self->has_hand_optimized_type_constraint;
132 my $check = $self->constraint;
134 || confess "Could not compile type constraint '"
136 . "' because no constraint check";
138 return $self->_compile_subtype($check)
139 if $self->has_parent;
141 return $self->_compile_type($check);
144 sub _compile_hand_optimized_type_constraint {
147 my $type_constraint = $self->hand_optimized_type_constraint;
149 confess unless ref $type_constraint;
151 return $type_constraint;
154 sub _compile_subtype {
155 my ($self, $check) = @_;
157 # so we gather all the parents in order
158 # and grab their constraints ...
160 foreach my $parent ($self->_collect_all_parents) {
161 if ($parent->has_hand_optimized_type_constraint) {
162 unshift @parents => $parent->hand_optimized_type_constraint;
166 unshift @parents => $parent->constraint;
170 # then we compile them to run without
171 # having to recurse as we did before
172 return subname $self->name => sub {
174 foreach my $parent (@parents) {
175 return undef unless $parent->($_[0]);
177 return undef unless $check->($_[0]);
183 my ($self, $check) = @_;
184 return subname $self->name => sub {
186 return undef unless $check->($_[0]);
193 sub _collect_all_parents {
196 my $current = $self->parent;
197 while (defined $current) {
198 push @parents => $current;
199 $current = $current->parent;
204 ## this should get deprecated actually ...
206 sub union { Carp::croak "DEPRECATED" }
216 Moose::Meta::TypeConstraint - The Moose Type Constraint metaclass
220 For the most part, the only time you will ever encounter an
221 instance of this class is if you are doing some serious deep
222 introspection. This API should not be considered final, but
223 it is B<highly unlikely> that this will matter to a regular
226 If you wish to use features at this depth, please come to the
227 #moose IRC channel on irc.perl.org and we can talk :)
237 =item B<equals ($type_name_or_object)>
239 =item B<is_a_type_of ($type_name_or_object)>
241 This checks the current type name, and if it does not match,
242 checks if it is a subtype of it.
244 =item B<is_subtype_of ($type_name_or_object)>
246 =item B<compile_type_constraint>
248 =item B<coerce ($value)>
250 This will apply the type-coercion if applicable.
252 =item B<check ($value)>
254 This method will return a true (C<1>) if the C<$value> passes the
255 constraint, and false (C<0>) otherwise.
257 =item B<validate ($value)>
259 This method is similar to C<check>, but it deals with the error
260 message. If the C<$value> passes the constraint, C<undef> will be
261 returned. If the C<$value> does B<not> pass the constraint, then
262 the C<message> will be used to construct a custom error message.
278 =item B<get_message ($value)>
280 =item B<has_coercion>
284 =item B<hand_optimized_type_constraint>
286 =item B<has_hand_optimized_type_constraint>
290 =head2 DEPRECATED METHOD
296 This was just bad idea on my part,.. use the L<Moose::Meta::TypeConstraint::Union>
303 All complex software has bugs lurking in it, and this module is no
304 exception. If you find a bug please either email me, or add the bug
309 Stevan Little E<lt>stevan@iinteractive.comE<gt>
311 =head1 COPYRIGHT AND LICENSE
313 Copyright 2006-2008 by Infinity Interactive, Inc.
315 L<http://www.iinteractive.com>
317 This library is free software; you can redistribute it and/or modify
318 it under the same terms as Perl itself.