fixing a bug for Sartak
[gitmo/Moose.git] / lib / Moose / Meta / TypeConstraint.pm
CommitLineData
4e036ee4 1
2package Moose::Meta::TypeConstraint;
3
4use strict;
5use warnings;
6use metaclass;
7
900466d6 8use overload '""' => sub { shift->name }, # stringify to tc name
9 fallback => 1;
10
c07af9d2 11use Sub::Name 'subname';
12use Carp 'confess';
13use Scalar::Util 'blessed';
66811d63 14
8de73ff1 15our $VERSION = '0.10';
d44714be 16our $AUTHORITY = 'cpan:STEVAN';
66811d63 17
3726f905 18__PACKAGE__->meta->add_attribute('name' => (reader => 'name'));
19__PACKAGE__->meta->add_attribute('parent' => (
20 reader => 'parent',
21 predicate => 'has_parent',
22));
d67145ed 23__PACKAGE__->meta->add_attribute('constraint' => (
8de73ff1 24 reader => 'constraint',
25 writer => '_set_constraint',
26 default => sub { sub { 1 } }
d67145ed 27));
76d37e5a 28__PACKAGE__->meta->add_attribute('message' => (
29 accessor => 'message',
30 predicate => 'has_message'
31));
a27aa600 32__PACKAGE__->meta->add_attribute('coercion' => (
33 accessor => 'coercion',
34 predicate => 'has_coercion'
35));
c8cf9aaa 36__PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
37 init_arg => 'optimized',
38 accessor => 'hand_optimized_type_constraint',
e27dfc11 39 predicate => 'has_hand_optimized_type_constraint',
c8cf9aaa 40));
41
3726f905 42# private accessors
43
44__PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
45 accessor => '_compiled_type_constraint',
46 predicate => '_has_compiled_type_constraint'
47));
22aed3c0 48__PACKAGE__->meta->add_attribute('package_defined_in' => (
49 accessor => '_package_defined_in'
50));
51
e27dfc11 52sub new {
a27aa600 53 my $class = shift;
54 my $self = $class->meta->new_object(@_);
3726f905 55 $self->compile_type_constraint()
56 unless $self->_has_compiled_type_constraint;
66811d63 57 return $self;
58}
59
3726f905 60sub coerce { ((shift)->coercion || confess "Cannot coerce without a type coercion")->coerce(@_) }
61sub check { $_[0]->_compiled_type_constraint->($_[1]) }
e27dfc11 62sub validate {
76d37e5a 63 my ($self, $value) = @_;
64 if ($self->_compiled_type_constraint->($value)) {
65 return undef;
66 }
67 else {
68 if ($self->has_message) {
69 local $_ = $value;
70 return $self->message->($value);
71 }
72 else {
451c8248 73 return "Validation failed for '" . $self->name . "' failed";
76d37e5a 74 }
75 }
76}
77
3726f905 78## type predicates ...
79
b26e162e 80sub is_a_type_of {
81 my ($self, $type_name) = @_;
82 ($self->name eq $type_name || $self->is_subtype_of($type_name));
83}
84
cce8198b 85sub is_subtype_of {
86 my ($self, $type_name) = @_;
87 my $current = $self;
88 while (my $parent = $current->parent) {
89 return 1 if $parent->name eq $type_name;
90 $current = $parent;
91 }
92 return 0;
93}
94
3726f905 95## compiling the type constraint
96
97sub compile_type_constraint {
98 my $self = shift;
99 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
451c8248 100}
101
3726f905 102## type compilers ...
103
104sub _actually_compile_type_constraint {
105 my $self = shift;
e27dfc11 106
3726f905 107 return $self->_compile_hand_optimized_type_constraint
108 if $self->has_hand_optimized_type_constraint;
e27dfc11 109
3726f905 110 my $check = $self->constraint;
111 (defined $check)
e27dfc11 112 || confess "Could not compile type constraint '"
113 . $self->name
3726f905 114 . "' because no constraint check";
e27dfc11 115
3726f905 116 return $self->_compile_subtype($check)
117 if $self->has_parent;
e27dfc11 118
3726f905 119 return $self->_compile_type($check);
120}
121
122sub _compile_hand_optimized_type_constraint {
123 my $self = shift;
e27dfc11 124
3726f905 125 my $type_constraint = $self->hand_optimized_type_constraint;
e27dfc11 126
3726f905 127 return sub {
e27dfc11 128 confess unless ref $type_constraint;
3726f905 129 return undef unless $type_constraint->($_[0]);
130 return 1;
e27dfc11 131 };
3726f905 132}
133
134sub _compile_subtype {
135 my ($self, $check) = @_;
e27dfc11 136
3726f905 137 # so we gather all the parents in order
138 # and grab their constraints ...
139 my @parents;
140 foreach my $parent ($self->_collect_all_parents) {
141 if ($parent->has_hand_optimized_type_constraint) {
142 unshift @parents => $parent->hand_optimized_type_constraint;
e27dfc11 143 last;
3726f905 144 }
145 else {
146 unshift @parents => $parent->constraint;
147 }
148 }
e27dfc11 149
3726f905 150 # then we compile them to run without
151 # having to recurse as we did before
e27dfc11 152 return subname $self->name => sub {
153 local $_ = $_[0];
3726f905 154 foreach my $parent (@parents) {
155 return undef unless $parent->($_[0]);
156 }
e27dfc11 157 return undef unless $check->($_[0]);
158 1;
159 };
3726f905 160}
161
162sub _compile_type {
163 my ($self, $check) = @_;
e27dfc11 164 return subname $self->name => sub {
165 local $_ = $_[0];
166 return undef unless $check->($_[0]);
167 1;
168 };
3726f905 169}
170
171## other utils ...
172
173sub _collect_all_parents {
174 my $self = shift;
175 my @parents;
176 my $current = $self->parent;
177 while (defined $current) {
178 push @parents => $current;
179 $current = $current->parent;
180 }
181 return @parents;
182}
183
184## this should get deprecated actually ...
185
186sub union { die "DEPRECATED" }
187
4e036ee4 1881;
189
190__END__
191
192=pod
193
194=head1 NAME
195
6ba6d68c 196Moose::Meta::TypeConstraint - The Moose Type Constraint metaclass
4e036ee4 197
198=head1 DESCRIPTION
199
e27dfc11 200For the most part, the only time you will ever encounter an
201instance of this class is if you are doing some serious deep
202introspection. This API should not be considered final, but
203it is B<highly unlikely> that this will matter to a regular
6ba6d68c 204Moose user.
205
e27dfc11 206If you wish to use features at this depth, please come to the
6ba6d68c 207#moose IRC channel on irc.perl.org and we can talk :)
208
4e036ee4 209=head1 METHODS
210
211=over 4
212
213=item B<meta>
214
215=item B<new>
216
b26e162e 217=item B<is_a_type_of ($type_name)>
218
e27dfc11 219This checks the current type name, and if it does not match,
b26e162e 220checks if it is a subtype of it.
221
222=item B<is_subtype_of ($type_name)>
cce8198b 223
6ba6d68c 224=item B<compile_type_constraint>
225
0a5bd159 226=item B<coerce ($value)>
227
228This will apply the type-coercion if applicable.
229
76d37e5a 230=item B<check ($value)>
231
e27dfc11 232This method will return a true (C<1>) if the C<$value> passes the
76d37e5a 233constraint, and false (C<0>) otherwise.
234
235=item B<validate ($value)>
236
e27dfc11 237This method is similar to C<check>, but it deals with the error
238message. If the C<$value> passes the constraint, C<undef> will be
239returned. If the C<$value> does B<not> pass the constraint, then
240the C<message> will be used to construct a custom error message.
6ba6d68c 241
4e036ee4 242=item B<name>
243
66811d63 244=item B<parent>
245
3726f905 246=item B<has_parent>
247
66811d63 248=item B<constraint>
249
76d37e5a 250=item B<has_message>
251
252=item B<message>
253
4e036ee4 254=item B<has_coercion>
255
a27aa600 256=item B<coercion>
257
c8cf9aaa 258=item B<hand_optimized_type_constraint>
259
260=item B<has_hand_optimized_type_constraint>
261
4e036ee4 262=back
263
3726f905 264=head2 DEPRECATED METHOD
265
451c8248 266=over 4
267
3726f905 268=item B<union>
269
270This was just bad idea on my part,.. use the L<Moose::Meta::TypeConstraint::Union>
271itself instead.
451c8248 272
273=back
274
4e036ee4 275=head1 BUGS
276
e27dfc11 277All complex software has bugs lurking in it, and this module is no
4e036ee4 278exception. If you find a bug please either email me, or add the bug
279to cpan-RT.
280
281=head1 AUTHOR
282
283Stevan Little E<lt>stevan@iinteractive.comE<gt>
284
285=head1 COPYRIGHT AND LICENSE
286
b77fdbed 287Copyright 2006, 2007 by Infinity Interactive, Inc.
4e036ee4 288
289L<http://www.iinteractive.com>
290
291This library is free software; you can redistribute it and/or modify
e27dfc11 292it under the same terms as Perl itself.
4e036ee4 293
c8cf9aaa 294=cut