moving things around to get ready to support Class::MOP 0.36
[gitmo/Moose.git] / lib / Moose / Meta / TypeConstraint.pm
CommitLineData
4e036ee4 1
2package Moose::Meta::TypeConstraint;
3
4use strict;
5use warnings;
6use metaclass;
7
c07af9d2 8use Sub::Name 'subname';
9use Carp 'confess';
10use Scalar::Util 'blessed';
66811d63 11
43123819 12our $VERSION = '0.06';
66811d63 13
8ee73eeb 14use Moose::Meta::TypeConstraint::Union;
15
66811d63 16__PACKAGE__->meta->add_attribute('name' => (reader => 'name' ));
17__PACKAGE__->meta->add_attribute('parent' => (reader => 'parent' ));
18__PACKAGE__->meta->add_attribute('constraint' => (reader => 'constraint'));
76d37e5a 19__PACKAGE__->meta->add_attribute('message' => (
20 accessor => 'message',
21 predicate => 'has_message'
22));
a27aa600 23__PACKAGE__->meta->add_attribute('coercion' => (
24 accessor => 'coercion',
25 predicate => 'has_coercion'
26));
66811d63 27
28# private accessor
29__PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
30 accessor => '_compiled_type_constraint'
31));
32
66811d63 33sub new {
a27aa600 34 my $class = shift;
35 my $self = $class->meta->new_object(@_);
66811d63 36 $self->compile_type_constraint();
37 return $self;
38}
39
0a5bd159 40sub coerce {
41 ((shift)->coercion || confess "Cannot coerce without a type coercion")->coerce(@_)
42}
43
43123819 44sub _collect_all_parents {
45 my $self = shift;
46 my @parents;
47 my $current = $self->parent;
48 while (defined $current) {
49 unshift @parents => $current;
50 $current = $current->parent;
51 }
52 return @parents;
53}
54
451c8248 55sub compile_type_constraint {
a27aa600 56 my $self = shift;
57 my $check = $self->constraint;
66811d63 58 (defined $check)
59 || confess "Could not compile type constraint '" . $self->name . "' because no constraint check";
60 my $parent = $self->parent;
61 if (defined $parent) {
43123819 62 # we have a subtype ...
63 # so we gather all the parents in order
64 # and grab their constraints ...
65 my @parents = map { $_->constraint } $self->_collect_all_parents;
66 # then we compile them to run without
67 # having to recurse as we did before
66811d63 68 $self->_compiled_type_constraint(subname $self->name => sub {
69 local $_ = $_[0];
43123819 70 foreach my $parent (@parents) {
71 return undef unless $parent->($_[0]);
72 }
73 return undef unless $check->($_[0]);
5a4c5493 74 1;
66811d63 75 });
43123819 76
66811d63 77 }
78 else {
a27aa600 79 # we have a type ....
66811d63 80 $self->_compiled_type_constraint(subname $self->name => sub {
81 local $_ = $_[0];
82 return undef unless $check->($_[0]);
5a4c5493 83 1;
66811d63 84 });
85 }
86}
87
a27aa600 88sub check { $_[0]->_compiled_type_constraint->($_[1]) }
4e036ee4 89
76d37e5a 90sub validate {
91 my ($self, $value) = @_;
92 if ($self->_compiled_type_constraint->($value)) {
93 return undef;
94 }
95 else {
96 if ($self->has_message) {
97 local $_ = $value;
98 return $self->message->($value);
99 }
100 else {
451c8248 101 return "Validation failed for '" . $self->name . "' failed";
76d37e5a 102 }
103 }
104}
105
b26e162e 106sub is_a_type_of {
107 my ($self, $type_name) = @_;
108 ($self->name eq $type_name || $self->is_subtype_of($type_name));
109}
110
cce8198b 111sub is_subtype_of {
112 my ($self, $type_name) = @_;
113 my $current = $self;
114 while (my $parent = $current->parent) {
115 return 1 if $parent->name eq $type_name;
116 $current = $parent;
117 }
118 return 0;
119}
120
451c8248 121sub union {
122 my ($class, @type_constraints) = @_;
c07af9d2 123 (scalar @type_constraints >= 2)
124 || confess "You must pass in at least 2 Moose::Meta::TypeConstraint instances to make a union";
125 (blessed($_) && $_->isa('Moose::Meta::TypeConstraint'))
126 || confess "You must pass in only Moose::Meta::TypeConstraint instances to make unions"
127 foreach @type_constraints;
451c8248 128 return Moose::Meta::TypeConstraint::Union->new(
0a5bd159 129 type_constraints => \@type_constraints,
451c8248 130 );
131}
132
4e036ee4 1331;
134
135__END__
136
137=pod
138
139=head1 NAME
140
6ba6d68c 141Moose::Meta::TypeConstraint - The Moose Type Constraint metaclass
4e036ee4 142
143=head1 DESCRIPTION
144
6ba6d68c 145For the most part, the only time you will ever encounter an
146instance of this class is if you are doing some serious deep
147introspection. This API should not be considered final, but
148it is B<highly unlikely> that this will matter to a regular
149Moose user.
150
151If you wish to use features at this depth, please come to the
152#moose IRC channel on irc.perl.org and we can talk :)
153
4e036ee4 154=head1 METHODS
155
156=over 4
157
158=item B<meta>
159
160=item B<new>
161
b26e162e 162=item B<is_a_type_of ($type_name)>
163
164This checks the current type name, and if it does not match,
165checks if it is a subtype of it.
166
167=item B<is_subtype_of ($type_name)>
cce8198b 168
6ba6d68c 169=item B<compile_type_constraint>
170
0a5bd159 171=item B<coerce ($value)>
172
173This will apply the type-coercion if applicable.
174
76d37e5a 175=item B<check ($value)>
176
177This method will return a true (C<1>) if the C<$value> passes the
178constraint, and false (C<0>) otherwise.
179
180=item B<validate ($value)>
181
182This method is similar to C<check>, but it deals with the error
183message. If the C<$value> passes the constraint, C<undef> will be
184returned. If the C<$value> does B<not> pass the constraint, then
185the C<message> will be used to construct a custom error message.
6ba6d68c 186
4e036ee4 187=item B<name>
188
66811d63 189=item B<parent>
190
66811d63 191=item B<constraint>
192
76d37e5a 193=item B<has_message>
194
195=item B<message>
196
4e036ee4 197=item B<has_coercion>
198
a27aa600 199=item B<coercion>
200
4e036ee4 201=back
202
451c8248 203=over 4
204
205=item B<union (@type_constraints)>
206
207=back
208
4e036ee4 209=head1 BUGS
210
211All complex software has bugs lurking in it, and this module is no
212exception. If you find a bug please either email me, or add the bug
213to cpan-RT.
214
215=head1 AUTHOR
216
217Stevan Little E<lt>stevan@iinteractive.comE<gt>
218
219=head1 COPYRIGHT AND LICENSE
220
221Copyright 2006 by Infinity Interactive, Inc.
222
223L<http://www.iinteractive.com>
224
225This library is free software; you can redistribute it and/or modify
226it under the same terms as Perl itself.
227
228=cut