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