remove trailing whitespace
[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
74397c13 15our $VERSION = '0.75_01';
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));
70ea9161 39
c8cf9aaa 40__PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
41 init_arg => 'optimized',
42 accessor => 'hand_optimized_type_constraint',
e27dfc11 43 predicate => 'has_hand_optimized_type_constraint',
c8cf9aaa 44));
45
bd72f3c8 46sub parents {
47 my $self;
48 $self->parent;
49}
50
3726f905 51# private accessors
52
53__PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
54 accessor => '_compiled_type_constraint',
55 predicate => '_has_compiled_type_constraint'
56));
22aed3c0 57__PACKAGE__->meta->add_attribute('package_defined_in' => (
58 accessor => '_package_defined_in'
59));
60
e27dfc11 61sub new {
a27aa600 62 my $class = shift;
8534c69a 63 my ($first, @rest) = @_;
64 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
65 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
70ea9161 66
8534c69a 67 my $self = $class->_new(%args);
3726f905 68 $self->compile_type_constraint()
69 unless $self->_has_compiled_type_constraint;
66811d63 70 return $self;
71}
72
8534c69a 73
74
70ea9161 75sub coerce {
76 my $self = shift;
77
78 my $coercion = $self->coercion;
79
80 unless ($coercion) {
81 require Moose;
82 Moose->throw_error("Cannot coerce without a type coercion");
83 }
84
02679ba4 85 return $_[0] if $self->check($_[0]);
86
70ea9161 87 return $coercion->coerce(@_);
88}
a1257460 89
90sub check {
91 my ($self, @args) = @_;
92 my $constraint_subref = $self->_compiled_type_constraint;
93 return $constraint_subref->(@args) ? 1 : undef;
94}
95
e27dfc11 96sub validate {
76d37e5a 97 my ($self, $value) = @_;
98 if ($self->_compiled_type_constraint->($value)) {
99 return undef;
100 }
101 else {
688fcdda 102 $self->get_message($value);
76d37e5a 103 }
104}
105
688fcdda 106sub get_message {
107 my ($self, $value) = @_;
688fcdda 108 if (my $msg = $self->message) {
109 local $_ = $value;
110 return $msg->($value);
111 }
112 else {
d03bd989 113 $value = (defined $value ? overload::StrVal($value) : 'undef');
688fcdda 114 return "Validation failed for '" . $self->name . "' failed with value $value";
d03bd989 115 }
688fcdda 116}
117
3726f905 118## type predicates ...
119
d9e17f80 120sub equals {
121 my ( $self, $type_or_name ) = @_;
122
e606ae5f 123 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
dabed765 124
125 return 1 if refaddr($self) == refaddr($other);
126
127 if ( $self->has_hand_optimized_type_constraint and $other->has_hand_optimized_type_constraint ) {
128 return 1 if $self->hand_optimized_type_constraint == $other->hand_optimized_type_constraint;
129 }
130
131 return unless $self->constraint == $other->constraint;
132
133 if ( $self->has_parent ) {
134 return unless $other->has_parent;
135 return unless $self->parent->equals( $other->parent );
136 } else {
137 return if $other->has_parent;
138 }
d9e17f80 139
dabed765 140 return 1;
d9e17f80 141}
142
b26e162e 143sub is_a_type_of {
d9e17f80 144 my ($self, $type_or_name) = @_;
145
e606ae5f 146 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
d9e17f80 147
148 ($self->equals($type) || $self->is_subtype_of($type));
b26e162e 149}
150
cce8198b 151sub is_subtype_of {
d9e17f80 152 my ($self, $type_or_name) = @_;
153
e606ae5f 154 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
d9e17f80 155
cce8198b 156 my $current = $self;
d9e17f80 157
cce8198b 158 while (my $parent = $current->parent) {
d9e17f80 159 return 1 if $parent->equals($type);
cce8198b 160 $current = $parent;
161 }
d9e17f80 162
cce8198b 163 return 0;
164}
165
3726f905 166## compiling the type constraint
167
168sub compile_type_constraint {
169 my $self = shift;
170 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
451c8248 171}
172
3726f905 173## type compilers ...
174
175sub _actually_compile_type_constraint {
176 my $self = shift;
e27dfc11 177
3726f905 178 return $self->_compile_hand_optimized_type_constraint
179 if $self->has_hand_optimized_type_constraint;
e27dfc11 180
3726f905 181 my $check = $self->constraint;
70ea9161 182 unless ( defined $check ) {
183 require Moose;
184 Moose->throw_error( "Could not compile type constraint '"
e27dfc11 185 . $self->name
70ea9161 186 . "' because no constraint check" );
187 }
e27dfc11 188
3726f905 189 return $self->_compile_subtype($check)
190 if $self->has_parent;
e27dfc11 191
3726f905 192 return $self->_compile_type($check);
193}
194
195sub _compile_hand_optimized_type_constraint {
196 my $self = shift;
e27dfc11 197
3726f905 198 my $type_constraint = $self->hand_optimized_type_constraint;
e27dfc11 199
70ea9161 200 unless ( ref $type_constraint ) {
201 require Moose;
202 Carp::confess ("Hand optimized type constraint for " . $self->name . " is not a code reference");
203 Moose->throw_error("Hand optimized type constraint is not a code reference");
204 }
42bc21a4 205
206 return $type_constraint;
3726f905 207}
208
209sub _compile_subtype {
210 my ($self, $check) = @_;
e27dfc11 211
baf26cc6 212 # gather all the parent constraintss in order
3726f905 213 my @parents;
baf26cc6 214 my $optimized_parent;
3726f905 215 foreach my $parent ($self->_collect_all_parents) {
baf26cc6 216 # if a parent is optimized, the optimized constraint already includes
217 # all of its parents tcs, so we can break the loop
3726f905 218 if ($parent->has_hand_optimized_type_constraint) {
baf26cc6 219 push @parents => $optimized_parent = $parent->hand_optimized_type_constraint;
e27dfc11 220 last;
3726f905 221 }
222 else {
baf26cc6 223 push @parents => $parent->constraint;
3726f905 224 }
225 }
e27dfc11 226
baf26cc6 227 @parents = grep { $_ != $null_constraint } reverse @parents;
228
229 unless ( @parents ) {
230 return $self->_compile_type($check);
231 } elsif( $optimized_parent and @parents == 1 ) {
232 # the case of just one optimized parent is optimized to prevent
233 # looping and the unnecessary localization
b5981f07 234 if ( $check == $null_constraint ) {
235 return $optimized_parent;
236 } else {
237 return Class::MOP::subname($self->name, sub {
238 return undef unless $optimized_parent->($_[0]);
a1257460 239 my (@args) = @_;
240 local $_ = $args[0];
241 $check->(@args);
b5981f07 242 });
243 }
baf26cc6 244 } else {
245 # general case, check all the constraints, from the first parent to ourselves
b5981f07 246 my @checks = @parents;
247 push @checks, $check if $check != $null_constraint;
baf26cc6 248 return Class::MOP::subname($self->name => sub {
a1257460 249 my (@args) = @_;
250 local $_ = $args[0];
baf26cc6 251 foreach my $check (@checks) {
a1257460 252 return undef unless $check->(@args);
baf26cc6 253 }
254 return 1;
255 });
256 }
3726f905 257}
258
259sub _compile_type {
260 my ($self, $check) = @_;
baf26cc6 261
262 return $check if $check == $null_constraint; # Item, Any
263
1b2aea39 264 return Class::MOP::subname($self->name => sub {
a1257460 265 my (@args) = @_;
266 local $_ = $args[0];
267 $check->(@args);
1b2aea39 268 });
3726f905 269}
270
271## other utils ...
272
273sub _collect_all_parents {
274 my $self = shift;
275 my @parents;
276 my $current = $self->parent;
277 while (defined $current) {
278 push @parents => $current;
279 $current = $current->parent;
280 }
281 return @parents;
282}
283
85a9908f 284sub create_child_type {
9ceb576e 285 my ($self, %opts) = @_;
286 my $class = ref $self;
287 return $class->new(%opts, parent => $self);
288}
289
4e036ee4 2901;
291
292__END__
293
294=pod
295
296=head1 NAME
297
6ba6d68c 298Moose::Meta::TypeConstraint - The Moose Type Constraint metaclass
4e036ee4 299
300=head1 DESCRIPTION
301
cfd006f0 302This class represents a single type constraint. Moose's built-in type
303constraints, as well as constraints you define, are all store in a
304L<Moose::Meta::TypeConstraint::Registry> object as objects of this
305class.
6ba6d68c 306
baf46b9e 307=head1 INHERITANCE
308
309C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>.
310
4e036ee4 311=head1 METHODS
312
313=over 4
314
cfd006f0 315=item B<< Moose::Meta::TypeConstraint->new(%options) >>
4e036ee4 316
cfd006f0 317This creates a new type constraint based on the provided C<%options>:
4e036ee4 318
cfd006f0 319=over 8
d9e17f80 320
cfd006f0 321=item * name
e606ae5f 322
cfd006f0 323The constraint name. If a name is not provided, it will be set to
324"__ANON__".
b26e162e 325
cfd006f0 326=item * parent
b26e162e 327
cfd006f0 328A C<Moose::Meta::TypeConstraint> object which is the parent type for
329the type being created. This is optional.
cce8198b 330
cfd006f0 331=item * constraint
e606ae5f 332
cfd006f0 333This is the subroutine reference that implements the actual constraint
334check. This defaults to a subroutine which always returns true.
6ba6d68c 335
cfd006f0 336=item * message
0a5bd159 337
cfd006f0 338A subroutine reference which is used to generate an error message when
339the constraint fails. This is optional.
0a5bd159 340
cfd006f0 341=item * coercion
76d37e5a 342
cfd006f0 343A L<Moose::Meta::TypeCoercion> object representing the coercions to
344the type. This is optional.
76d37e5a 345
cfd006f0 346=item * optimized
76d37e5a 347
cfd006f0 348This is a variant of the C<constraint> parameter that is somehow
349optimized. Typically, this means incorporating both the type's
350constraint and all of its parents' constraints into a single
351subroutine reference.
6ba6d68c 352
cfd006f0 353=back
4e036ee4 354
cfd006f0 355=item B<< $constraint->equals($type_name_or_object) >>
e606ae5f 356
cfd006f0 357Returns true if the supplied name or type object is the same as the
358current type.
66811d63 359
cfd006f0 360=item B<< $constraint->is_subtype_of($type_name_or_object) >>
e606ae5f 361
cfd006f0 362Returns true if the supplied name or type object is a parent of the
363current type.
3726f905 364
cfd006f0 365=item B<< $constraint->is_a_type_of($type_name_or_object) >>
e606ae5f 366
cfd006f0 367Returns true if the given type is the same as the current type, or is
368a parent of the current type. This is a shortcut for checking
369C<equals> and C<is_subtype_of>.
d9e17f80 370
cfd006f0 371=item B<< $constraint->coerce($value) >>
2f7e4042 372
cfd006f0 373This will attempt to coerce the value to the type. If the type does
374have any defined coercions this will throw an error.
66811d63 375
cfd006f0 376=item B<< $constraint->check($value) >>
2f7e4042 377
cfd006f0 378Returns true if the given value passes the constraint for the type.
76d37e5a 379
cfd006f0 380=item B<< $constraint->validate($value) >>
2f7e4042 381
cfd006f0 382This is similar to C<check>. However, if the type I<is valid> then the
383method returns an explicit C<undef>. If the type is not valid, we call
384C<< $self->get_message($value) >> internally to generate an error
385message.
76d37e5a 386
cfd006f0 387=item B<< $constraint->name >>
2f7e4042 388
cfd006f0 389Returns the type's name, as provided to the constructor.
688fcdda 390
cfd006f0 391=item B<< $constraint->parent >>
2f7e4042 392
cfd006f0 393Returns the type's parent, as provided to the constructor, if any.
4e036ee4 394
cfd006f0 395=item B<< $constraint->has_parent >>
2f7e4042 396
cfd006f0 397Returns true if the type has a parent type.
a27aa600 398
cfd006f0 399=item B<< $constraint->parents >>
2f7e4042 400
cfd006f0 401A synonym for C<parent>. This is useful for polymorphism with types
402that can have more than one parent.
c8cf9aaa 403
cfd006f0 404=item B<< $constraint->constraint >>
c8cf9aaa 405
cfd006f0 406Returns the type's constraint, as provided to the constructor.
9ceb576e 407
cfd006f0 408=item B<< $constraint->get_message($value) >>
4e036ee4 409
cfd006f0 410This generates a method for the given value. If the type does not have
411an explicit message, we generate a default message.
3726f905 412
cfd006f0 413=item B<< $constraint->has_message >>
414
415Returns true if the type has a message.
416
417=item B<< $constraint->message >>
418
419Returns the type's message as a subroutine reference.
420
421=item B<< $constraint->coercion >>
422
423Returns the type's L<Moose::Meta::TypeCoercion> object, if one
424exists.
425
426=item B<< $constraint->has_coercion >>
427
428Returns true if the type has a coercion.
429
430=item B<< $constraint->hand_optimized_type_constraint >>
431
432Returns the type's hand optimized constraint, as provided to the
433constructor via the C<optimized> option.
434
435=item B<< $constraint->has_hand_optimized_type_constraint >>
436
437Returns true if the type has an optimized constraint.
438
439=item B<< $constraint->create_child_type(%options) >>
451c8248 440
cfd006f0 441This returns a new type constraint of the same class using the
442provided C<%options>. The C<parent> option will be the current type.
3726f905 443
cfd006f0 444This method exists so that subclasses of this class can override this
445behavior and change how child types are created.
451c8248 446
447=back
448
4e036ee4 449=head1 BUGS
450
e27dfc11 451All complex software has bugs lurking in it, and this module is no
4e036ee4 452exception. If you find a bug please either email me, or add the bug
453to cpan-RT.
454
455=head1 AUTHOR
456
457Stevan Little E<lt>stevan@iinteractive.comE<gt>
458
459=head1 COPYRIGHT AND LICENSE
460
2840a3b2 461Copyright 2006-2009 by Infinity Interactive, Inc.
4e036ee4 462
463L<http://www.iinteractive.com>
464
465This library is free software; you can redistribute it and/or modify
e27dfc11 466it under the same terms as Perl itself.
4e036ee4 467
c8cf9aaa 468=cut