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