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