bump version to 0.66
[gitmo/Moose.git] / lib / Moose / Meta / TypeConstraint.pm
CommitLineData
4e036ee4 1
2package Moose::Meta::TypeConstraint;
3
4use strict;
5use warnings;
6use metaclass;
7
b644e331 8use overload '""' => sub { shift->name }, # stringify to tc name
9 fallback => 1;
900466d6 10
dabed765 11use Scalar::Util qw(blessed refaddr);
66811d63 12
e606ae5f 13use base qw(Class::MOP::Object);
14
aa7bbf26 15our $VERSION = '0.66';
e606ae5f 16$VERSION = eval $VERSION;
d44714be 17our $AUTHORITY = 'cpan:STEVAN';
66811d63 18
3726f905 19__PACKAGE__->meta->add_attribute('name' => (reader => 'name'));
20__PACKAGE__->meta->add_attribute('parent' => (
21 reader => 'parent',
22 predicate => 'has_parent',
23));
baf26cc6 24
25my $null_constraint = sub { 1 };
d67145ed 26__PACKAGE__->meta->add_attribute('constraint' => (
8de73ff1 27 reader => 'constraint',
28 writer => '_set_constraint',
baf26cc6 29 default => sub { $null_constraint }
d67145ed 30));
76d37e5a 31__PACKAGE__->meta->add_attribute('message' => (
32 accessor => 'message',
33 predicate => 'has_message'
34));
a27aa600 35__PACKAGE__->meta->add_attribute('coercion' => (
36 accessor => 'coercion',
37 predicate => 'has_coercion'
38));
c8cf9aaa 39__PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
40 init_arg => 'optimized',
41 accessor => 'hand_optimized_type_constraint',
e27dfc11 42 predicate => 'has_hand_optimized_type_constraint',
c8cf9aaa 43));
44
bd72f3c8 45sub parents {
46 my $self;
47 $self->parent;
48}
49
3726f905 50# private accessors
51
52__PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
53 accessor => '_compiled_type_constraint',
54 predicate => '_has_compiled_type_constraint'
55));
22aed3c0 56__PACKAGE__->meta->add_attribute('package_defined_in' => (
57 accessor => '_package_defined_in'
58));
59
e27dfc11 60sub new {
a27aa600 61 my $class = shift;
8534c69a 62 my ($first, @rest) = @_;
63 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
64 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
65
66 my $self = $class->_new(%args);
3726f905 67 $self->compile_type_constraint()
68 unless $self->_has_compiled_type_constraint;
66811d63 69 return $self;
70}
71
8534c69a 72
73
c245d69b 74sub coerce { ((shift)->coercion || Moose->throw_error("Cannot coerce without a type coercion"))->coerce(@_) }
a1257460 75
76sub check {
77 my ($self, @args) = @_;
78 my $constraint_subref = $self->_compiled_type_constraint;
79 return $constraint_subref->(@args) ? 1 : undef;
80}
81
e27dfc11 82sub validate {
76d37e5a 83 my ($self, $value) = @_;
84 if ($self->_compiled_type_constraint->($value)) {
85 return undef;
86 }
87 else {
688fcdda 88 $self->get_message($value);
76d37e5a 89 }
90}
91
688fcdda 92sub get_message {
93 my ($self, $value) = @_;
688fcdda 94 if (my $msg = $self->message) {
95 local $_ = $value;
96 return $msg->($value);
97 }
98 else {
e606ae5f 99 $value = (defined $value ? overload::StrVal($value) : 'undef');
688fcdda 100 return "Validation failed for '" . $self->name . "' failed with value $value";
101 }
102}
103
3726f905 104## type predicates ...
105
d9e17f80 106sub equals {
107 my ( $self, $type_or_name ) = @_;
108
e606ae5f 109 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
dabed765 110
111 return 1 if refaddr($self) == refaddr($other);
112
113 if ( $self->has_hand_optimized_type_constraint and $other->has_hand_optimized_type_constraint ) {
114 return 1 if $self->hand_optimized_type_constraint == $other->hand_optimized_type_constraint;
115 }
116
117 return unless $self->constraint == $other->constraint;
118
119 if ( $self->has_parent ) {
120 return unless $other->has_parent;
121 return unless $self->parent->equals( $other->parent );
122 } else {
123 return if $other->has_parent;
124 }
d9e17f80 125
dabed765 126 return 1;
d9e17f80 127}
128
b26e162e 129sub is_a_type_of {
d9e17f80 130 my ($self, $type_or_name) = @_;
131
e606ae5f 132 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
d9e17f80 133
134 ($self->equals($type) || $self->is_subtype_of($type));
b26e162e 135}
136
cce8198b 137sub is_subtype_of {
d9e17f80 138 my ($self, $type_or_name) = @_;
139
e606ae5f 140 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
d9e17f80 141
cce8198b 142 my $current = $self;
d9e17f80 143
cce8198b 144 while (my $parent = $current->parent) {
d9e17f80 145 return 1 if $parent->equals($type);
cce8198b 146 $current = $parent;
147 }
d9e17f80 148
cce8198b 149 return 0;
150}
151
3726f905 152## compiling the type constraint
153
154sub compile_type_constraint {
155 my $self = shift;
156 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
451c8248 157}
158
3726f905 159## type compilers ...
160
161sub _actually_compile_type_constraint {
162 my $self = shift;
e27dfc11 163
3726f905 164 return $self->_compile_hand_optimized_type_constraint
165 if $self->has_hand_optimized_type_constraint;
e27dfc11 166
3726f905 167 my $check = $self->constraint;
168 (defined $check)
c245d69b 169 || Moose->throw_error("Could not compile type constraint '"
e27dfc11 170 . $self->name
4c0b3599 171 . "' because no constraint check");
e27dfc11 172
3726f905 173 return $self->_compile_subtype($check)
174 if $self->has_parent;
e27dfc11 175
3726f905 176 return $self->_compile_type($check);
177}
178
179sub _compile_hand_optimized_type_constraint {
180 my $self = shift;
e27dfc11 181
3726f905 182 my $type_constraint = $self->hand_optimized_type_constraint;
e27dfc11 183
c245d69b 184 Moose->throw_error("Hand optimized type constraint is not a code reference") unless ref $type_constraint;
42bc21a4 185
186 return $type_constraint;
3726f905 187}
188
189sub _compile_subtype {
190 my ($self, $check) = @_;
e27dfc11 191
baf26cc6 192 # gather all the parent constraintss in order
3726f905 193 my @parents;
baf26cc6 194 my $optimized_parent;
3726f905 195 foreach my $parent ($self->_collect_all_parents) {
baf26cc6 196 # if a parent is optimized, the optimized constraint already includes
197 # all of its parents tcs, so we can break the loop
3726f905 198 if ($parent->has_hand_optimized_type_constraint) {
baf26cc6 199 push @parents => $optimized_parent = $parent->hand_optimized_type_constraint;
e27dfc11 200 last;
3726f905 201 }
202 else {
baf26cc6 203 push @parents => $parent->constraint;
3726f905 204 }
205 }
e27dfc11 206
baf26cc6 207 @parents = grep { $_ != $null_constraint } reverse @parents;
208
209 unless ( @parents ) {
210 return $self->_compile_type($check);
211 } elsif( $optimized_parent and @parents == 1 ) {
212 # the case of just one optimized parent is optimized to prevent
213 # looping and the unnecessary localization
b5981f07 214 if ( $check == $null_constraint ) {
215 return $optimized_parent;
216 } else {
217 return Class::MOP::subname($self->name, sub {
218 return undef unless $optimized_parent->($_[0]);
a1257460 219 my (@args) = @_;
220 local $_ = $args[0];
221 $check->(@args);
b5981f07 222 });
223 }
baf26cc6 224 } else {
225 # general case, check all the constraints, from the first parent to ourselves
b5981f07 226 my @checks = @parents;
227 push @checks, $check if $check != $null_constraint;
baf26cc6 228 return Class::MOP::subname($self->name => sub {
a1257460 229 my (@args) = @_;
230 local $_ = $args[0];
baf26cc6 231 foreach my $check (@checks) {
a1257460 232 return undef unless $check->(@args);
baf26cc6 233 }
234 return 1;
235 });
236 }
3726f905 237}
238
239sub _compile_type {
240 my ($self, $check) = @_;
baf26cc6 241
242 return $check if $check == $null_constraint; # Item, Any
243
1b2aea39 244 return Class::MOP::subname($self->name => sub {
a1257460 245 my (@args) = @_;
246 local $_ = $args[0];
247 $check->(@args);
1b2aea39 248 });
3726f905 249}
250
251## other utils ...
252
253sub _collect_all_parents {
254 my $self = shift;
255 my @parents;
256 my $current = $self->parent;
257 while (defined $current) {
258 push @parents => $current;
259 $current = $current->parent;
260 }
261 return @parents;
262}
263
85a9908f 264sub create_child_type {
9ceb576e 265 my ($self, %opts) = @_;
266 my $class = ref $self;
267 return $class->new(%opts, parent => $self);
268}
269
3726f905 270## this should get deprecated actually ...
271
547dda77 272sub union { Carp::croak "DEPRECATED" }
3726f905 273
4e036ee4 2741;
275
276__END__
277
278=pod
279
280=head1 NAME
281
6ba6d68c 282Moose::Meta::TypeConstraint - The Moose Type Constraint metaclass
4e036ee4 283
284=head1 DESCRIPTION
285
e27dfc11 286For the most part, the only time you will ever encounter an
287instance of this class is if you are doing some serious deep
288introspection. This API should not be considered final, but
289it is B<highly unlikely> that this will matter to a regular
6ba6d68c 290Moose user.
291
e27dfc11 292If you wish to use features at this depth, please come to the
6ba6d68c 293#moose IRC channel on irc.perl.org and we can talk :)
294
4e036ee4 295=head1 METHODS
296
297=over 4
298
299=item B<meta>
300
301=item B<new>
302
d9e17f80 303=item B<equals ($type_name_or_object)>
304
e606ae5f 305This checks the current type against the supplied type (only).
306Returns false if the two types are not equal. It also returns false if
307you provide the type as a name, and the type name isn't found in the
308type registry.
309
d9e17f80 310=item B<is_a_type_of ($type_name_or_object)>
b26e162e 311
e606ae5f 312This checks the current type against the supplied type, or if the
313current type is a sub-type of the type name or object supplied. It
314also returns false if you provide the type as a name, and the type
315name isn't found in the type registry.
b26e162e 316
d9e17f80 317=item B<is_subtype_of ($type_name_or_object)>
cce8198b 318
e606ae5f 319This checks the current type is a sub-type of the type name or object
320supplied. It also returns false if you provide the type as a name, and
321the type name isn't found in the type registry.
322
6ba6d68c 323=item B<compile_type_constraint>
324
0a5bd159 325=item B<coerce ($value)>
326
327This will apply the type-coercion if applicable.
328
76d37e5a 329=item B<check ($value)>
330
e27dfc11 331This method will return a true (C<1>) if the C<$value> passes the
76d37e5a 332constraint, and false (C<0>) otherwise.
333
334=item B<validate ($value)>
335
e27dfc11 336This method is similar to C<check>, but it deals with the error
337message. If the C<$value> passes the constraint, C<undef> will be
338returned. If the C<$value> does B<not> pass the constraint, then
339the C<message> will be used to construct a custom error message.
6ba6d68c 340
4e036ee4 341=item B<name>
342
e606ae5f 343The name of the type in the global type registry.
344
66811d63 345=item B<parent>
346
2f7e4042 347This type's parent type.
e606ae5f 348
3726f905 349=item B<has_parent>
350
e606ae5f 351Returns true if this type has a parent type.
352
d9e17f80 353=item B<parents>
354
2f7e4042 355Synonym for C<parent>.
356
66811d63 357=item B<constraint>
358
2f7e4042 359Returns this type's constraint. This is the value of C<where> provided
360when defining a type.
361
76d37e5a 362=item B<has_message>
363
2f7e4042 364Returns true if this type has a message.
365
76d37e5a 366=item B<message>
367
2f7e4042 368Returns this type's message.
369
688fcdda 370=item B<get_message ($value)>
371
2f7e4042 372Generate message for $value.
373
4e036ee4 374=item B<has_coercion>
375
2f7e4042 376Returns true if this type has a coercion.
377
a27aa600 378=item B<coercion>
379
2f7e4042 380Returns this type's L<Moose::Meta::TypeCoercion> if one exists.
381
c8cf9aaa 382=item B<hand_optimized_type_constraint>
383
384=item B<has_hand_optimized_type_constraint>
385
85a9908f 386=item B<create_child_type>
9ceb576e 387
4e036ee4 388=back
389
3726f905 390=head2 DEPRECATED METHOD
391
451c8248 392=over 4
393
3726f905 394=item B<union>
395
396This was just bad idea on my part,.. use the L<Moose::Meta::TypeConstraint::Union>
397itself instead.
451c8248 398
399=back
400
4e036ee4 401=head1 BUGS
402
e27dfc11 403All complex software has bugs lurking in it, and this module is no
4e036ee4 404exception. If you find a bug please either email me, or add the bug
405to cpan-RT.
406
407=head1 AUTHOR
408
409Stevan Little E<lt>stevan@iinteractive.comE<gt>
410
411=head1 COPYRIGHT AND LICENSE
412
2840a3b2 413Copyright 2006-2009 by Infinity Interactive, Inc.
4e036ee4 414
415L<http://www.iinteractive.com>
416
417This library is free software; you can redistribute it and/or modify
e27dfc11 418it under the same terms as Perl itself.
4e036ee4 419
c8cf9aaa 420=cut