File Coverage

blib/lib/Moose/Meta/TypeConstraint.pm
Criterion Covered Total %
statement 145 147 98.6
branch 61 68 89.7
condition 13 15 86.6
subroutine 35 35 100.0
pod 14 15 93.3
total 268 280 95.7


line stmt bran cond sub pod time code
1             package Moose::Meta::TypeConstraint;
2             our $VERSION = '2.2205';
3              
4 390     390   73977 use strict;
  390         909  
  390         12565  
5 390     390   2120 use warnings;
  390         905  
  390         10167  
6 390     390   156678 use metaclass;
  390         1066  
  390         2288  
7              
8 3529     3529   15976 use overload '0+' => sub { refaddr(shift) }, # id an object
9 169     169   24543 '""' => sub { shift->name }, # stringify to tc name
10 90163     90163   300832 bool => sub { 1 },
11 390     390   4496 fallback => 1;
  390         1025  
  390         7341  
12              
13 390     390   49909 use Eval::Closure;
  390         2401  
  390         27581  
14 390     390   2960 use Scalar::Util qw(refaddr);
  390         1031  
  390         25830  
15 390     390   2714 use Sub::Util qw(set_subname);
  390         2214  
  390         20206  
16 390     390   3827 use Try::Tiny;
  390         1056  
  390         24158  
17              
18 390     390   2952 use parent 'Class::MOP::Object';
  390         981  
  390         3071  
19              
20 390     390   30144 use Moose::Util 'throw_exception';
  390         2525  
  390         3105  
21              
22             __PACKAGE__->meta->add_attribute('name' => (
23             reader => 'name',
24             Class::MOP::_definition_context(),
25             ));
26             __PACKAGE__->meta->add_attribute('parent' => (
27             reader => 'parent',
28             predicate => 'has_parent',
29             Class::MOP::_definition_context(),
30             ));
31              
32             my $null_constraint = sub { 1 };
33             __PACKAGE__->meta->add_attribute('constraint' => (
34             reader => 'constraint',
35             writer => '_set_constraint',
36             default => sub { $null_constraint },
37             Class::MOP::_definition_context(),
38             ));
39              
40             __PACKAGE__->meta->add_attribute('message' => (
41             accessor => 'message',
42             predicate => 'has_message',
43             Class::MOP::_definition_context(),
44             ));
45              
46             __PACKAGE__->meta->add_attribute('_default_message' => (
47             accessor => '_default_message',
48             Class::MOP::_definition_context(),
49             ));
50              
51             # can't make this a default because it has to close over the type name, and
52             # cmop attributes don't have lazy
53             my $_default_message_generator = sub {
54             my $name = shift;
55             sub {
56             my $value = shift;
57             # have to load it late like this, since it uses Moose itself
58             my $can_partialdump = try {
59             # versions prior to 0.14 had a potential infinite loop bug
60             require Devel::PartialDump;
61             Devel::PartialDump->VERSION(0.14);
62             1;
63             };
64             if ($can_partialdump) {
65             $value = Devel::PartialDump->new->dump($value);
66             }
67             else {
68             $value = (defined $value ? overload::StrVal($value) : 'undef');
69             }
70             return "Validation failed for '" . $name . "' with value $value";
71             }
72             };
73             __PACKAGE__->meta->add_attribute('coercion' => (
74             accessor => 'coercion',
75             predicate => 'has_coercion',
76             Class::MOP::_definition_context(),
77             ));
78              
79             __PACKAGE__->meta->add_attribute('inlined' => (
80             init_arg => 'inlined',
81             accessor => 'inlined',
82             predicate => '_has_inlined_type_constraint',
83             Class::MOP::_definition_context(),
84             ));
85              
86             __PACKAGE__->meta->add_attribute('inline_environment' => (
87             init_arg => 'inline_environment',
88             accessor => '_inline_environment',
89             default => sub { {} },
90             Class::MOP::_definition_context(),
91             ));
92              
93             sub parents {
94 1     1 1 6 my $self = shift;
95 1         4 $self->parent;
96             }
97              
98             # private accessors
99              
100             __PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
101             accessor => '_compiled_type_constraint',
102             predicate => '_has_compiled_type_constraint',
103             Class::MOP::_definition_context(),
104             ));
105              
106             __PACKAGE__->meta->add_attribute('package_defined_in' => (
107             accessor => '_package_defined_in',
108             Class::MOP::_definition_context(),
109             ));
110              
111             sub new {
112 11624     11624 1 26462 my $class = shift;
113 11624         33763 my ($first, @rest) = @_;
114 11624 100       58858 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
    100          
115 11624 100       40873 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
116              
117 11624 100 66     29115 if ( exists $args{message}
      66        
118             && (!ref($args{message}) || ref($args{message}) ne 'CODE') ) {
119 1         5 throw_exception( MessageParameterMustBeCodeRef => params => \%args,
120             class => $class
121             );
122             }
123              
124 11623         383775 my $self = $class->_new(%args);
125 11623 50       457240 $self->compile_type_constraint()
126             unless $self->_has_compiled_type_constraint;
127 11617 100       382021 $self->_default_message($_default_message_generator->($self->name))
128             unless $self->has_message;
129 11617         67155 return $self;
130             }
131              
132              
133              
134             sub coerce {
135 133     133 1 1066 my $self = shift;
136              
137 133         3600 my $coercion = $self->coercion;
138              
139 133 100       443 unless ($coercion) {
140 2         59 throw_exception( CoercingWithoutCoercions => type_name => $self->name );
141             }
142              
143 131 100       449 return $_[0] if $self->check($_[0]);
144              
145 116         1287 return $coercion->coerce(@_);
146             }
147              
148             sub assert_coerce {
149 3     3 1 2438 my $self = shift;
150              
151 3         12 my $result = $self->coerce(@_);
152              
153 3         14 $self->assert_valid($result);
154              
155 2         32 return $result;
156             }
157              
158             sub check {
159 9451     9451 1 163393 my ($self, @args) = @_;
160 9451         356579 my $constraint_subref = $self->_compiled_type_constraint;
161 9451 100       138425 return $constraint_subref->(@args) ? 1 : undef;
162             }
163              
164             sub validate {
165 18     18 1 471 my ($self, $value) = @_;
166 18 100       750 if ($self->_compiled_type_constraint->($value)) {
167 6         59 return undef;
168             }
169             else {
170 12         103 $self->get_message($value);
171             }
172             }
173              
174             sub can_be_inlined {
175 47670     47670 1 71493 my $self = shift;
176              
177 47670 100 100     1451864 if ( $self->has_parent && $self->constraint == $null_constraint ) {
178 1085         31696 return $self->parent->can_be_inlined;
179             }
180              
181 46585         1565602 return $self->_has_inlined_type_constraint;
182             }
183              
184             sub _inline_check {
185 24433     24433   41156 my $self = shift;
186              
187 24433 100       45827 unless ( $self->can_be_inlined ) {
188 2         60 throw_exception( CannotInlineTypeConstraintCheck => type_name => $self->name );
189             }
190              
191 24431 100 100     745403 if ( $self->has_parent && $self->constraint == $null_constraint ) {
192 511         15997 return $self->parent->_inline_check(@_);
193             }
194              
195 23920         660492 return '( do { ' . $self->inlined->( $self, @_ ) . ' } )';
196             }
197              
198             sub inline_environment {
199 21515     21515 1 40802 my $self = shift;
200              
201 21515 100 100     666328 if ( $self->has_parent && $self->constraint == $null_constraint ) {
202 495         15226 return $self->parent->inline_environment;
203             }
204              
205 21020         721513 return $self->_inline_environment;
206             }
207              
208             sub assert_valid {
209 8     8 1 733 my ( $self, $value ) = @_;
210              
211 8 100       31 return 1 if $self->check($value);
212              
213 3         69 throw_exception(
214             'ValidationFailedForTypeConstraint',
215             type => $self,
216             value => $value
217             );
218             }
219              
220             sub get_message {
221 926     926 1 2415 my ($self, $value) = @_;
222 926 100       28785 my $msg = $self->has_message
223             ? $self->message
224             : $self->_default_message;
225 926         2017 local $_ = $value;
226 926         2386 return $msg->($value);
227             }
228              
229             ## type predicates ...
230              
231             sub equals {
232 1765     1765 1 3985 my ( $self, $type_or_name ) = @_;
233              
234 1765         3793 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
235 1765 100       3625 return if not $other;
236              
237 1764 100       4213 return 1 if $self == $other;
238              
239 1357 100       39471 return unless $self->constraint == $other->constraint;
240              
241 1 50       36 if ( $self->has_parent ) {
242 0 0       0 return unless $other->has_parent;
243 0 0       0 return unless $self->parent->equals( $other->parent );
244             } else {
245 1 50       31 return if $other->has_parent;
246             }
247              
248 1         6 return;
249             }
250              
251             sub is_a_type_of {
252 265     265 1 1215 my ($self, $type_or_name) = @_;
253              
254 265         816 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
255 265 100       1108 return if not $type;
256              
257 261 100       1364 ($self->equals($type) || $self->is_subtype_of($type));
258             }
259              
260             sub is_subtype_of {
261 579     579 1 2588 my ($self, $type_or_name) = @_;
262              
263 579         1740 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
264 579 100       1789 return if not $type;
265              
266 575         1172 my $current = $self;
267              
268 575         16481 while (my $parent = $current->parent) {
269 1602 100       3504 return 1 if $parent->equals($type);
270 1285         35217 $current = $parent;
271             }
272              
273 258         1377 return 0;
274             }
275              
276             ## compiling the type constraint
277              
278             sub compile_type_constraint {
279 14648     14648 0 24947 my $self = shift;
280 14648         35380 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
281             }
282              
283             ## type compilers ...
284              
285             sub _actually_compile_type_constraint {
286 14575     14575   21989 my $self = shift;
287              
288 14575 100       34349 if ( $self->can_be_inlined ) {
289 14458         41115 return eval_closure(
290             source => 'sub { ' . $self->_inline_check('$_[0]') . ' }',
291             environment => $self->inline_environment,
292             );
293             }
294              
295 117         3436 my $check = $self->constraint;
296 117 100       533 unless ( defined $check ) {
297 1         28 throw_exception( NoConstraintCheckForTypeConstraint => type_name => $self->name );
298             }
299              
300 116 100       3628 return $self->_compile_subtype($check)
301             if $self->has_parent;
302              
303 20         115 return $self->_compile_type($check);
304             }
305              
306             sub _compile_subtype {
307 125     125   442 my ($self, $check) = @_;
308              
309             # gather all the parent constraints in order
310 125         265 my @parents;
311 125         505 foreach my $parent ($self->_collect_all_parents) {
312 627         16980 push @parents => $parent->constraint;
313             }
314              
315 125         591 @parents = grep { $_ != $null_constraint } reverse @parents;
  627         1557  
316              
317 125 100       554 unless ( @parents ) {
318 2         22 return $self->_compile_type($check);
319             } else {
320             # general case, check all the constraints, from the first parent to ourselves
321 123         409 my @checks = @parents;
322 123 100       527 push @checks, $check if $check != $null_constraint;
323             return set_subname(
324             $self->name => sub {
325 1772     1772   231054 my (@args) = @_;
326 1772         3180 local $_ = $args[0];
327 1772         3723 foreach my $check (@checks) {
328 8098 100       18836 return undef unless $check->(@args);
329             }
330 1029         6788 return 1;
331             }
332 123         3682 );
333             }
334             }
335              
336             sub _compile_type {
337 48     48   177 my ($self, $check) = @_;
338              
339 48 100       548 return $check if $check == $null_constraint; # Item, Any
340              
341             return set_subname(
342             $self->name => sub {
343 756     756   8342 my (@args) = @_;
344 756         1498 local $_ = $args[0];
345 756         2615 $check->(@args);
346             }
347 39         1104 );
348             }
349              
350             ## other utils ...
351              
352             sub _collect_all_parents {
353 138     138   331 my $self = shift;
354 138         275 my @parents;
355 138         3938 my $current = $self->parent;
356 138         579 while (defined $current) {
357 683         1331 push @parents => $current;
358 683         17610 $current = $current->parent;
359             }
360 138         651 return @parents;
361             }
362              
363             sub create_child_type {
364 6313     6313 1 22596 my ($self, %opts) = @_;
365 6313         13267 my $class = ref $self;
366 6313         21540 return $class->new(%opts, parent => $self);
367             }
368              
369             1;
370              
371             # ABSTRACT: The Moose Type Constraint metaclass
372              
373             __END__
374              
375             =pod
376              
377             =encoding UTF-8
378              
379             =head1 NAME
380              
381             Moose::Meta::TypeConstraint - The Moose Type Constraint metaclass
382              
383             =head1 VERSION
384              
385             version 2.2205
386              
387             =head1 DESCRIPTION
388              
389             This class represents a single type constraint. Moose's built-in type
390             constraints, as well as constraints you define, are all stored in a
391             L<Moose::Meta::TypeConstraint::Registry> object as objects of this
392             class.
393              
394             =head1 INHERITANCE
395              
396             C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>.
397              
398             =head1 METHODS
399              
400             =head2 Moose::Meta::TypeConstraint->new(%options)
401              
402             This creates a new type constraint based on the provided C<%options>:
403              
404             =over 4
405              
406             =item * name
407              
408             The constraint name. If a name is not provided, it will be set to
409             "__ANON__".
410              
411             =item * parent
412              
413             A C<Moose::Meta::TypeConstraint> object which is the parent type for
414             the type being created. This is optional.
415              
416             =item * constraint
417              
418             This is the subroutine reference that implements the actual constraint
419             check. This defaults to a subroutine which always returns true.
420              
421             =item * message
422              
423             A subroutine reference which is used to generate an error message when
424             the constraint fails. This is optional.
425              
426             =item * coercion
427              
428             A L<Moose::Meta::TypeCoercion> object representing the coercions to
429             the type. This is optional.
430              
431             =item * inlined
432              
433             A subroutine which returns a string suitable for inlining this type
434             constraint. It will be called as a method on the type constraint object, and
435             will receive a single additional parameter, a variable name to be tested
436             (usually C<"$_"> or C<"$_[0]">.
437              
438             This is optional.
439              
440             =item * inline_environment
441              
442             A hash reference of variables to close over. The keys are variables names, and
443             the values are I<references> to the variables.
444              
445             =back
446              
447             =head2 $constraint->equals($type_name_or_object)
448              
449             Returns true if the supplied name or type object is the same as the
450             current type.
451              
452             =head2 $constraint->is_subtype_of($type_name_or_object)
453              
454             Returns true if the supplied name or type object is a parent of the
455             current type.
456              
457             =head2 $constraint->is_a_type_of($type_name_or_object)
458              
459             Returns true if the given type is the same as the current type, or is
460             a parent of the current type. This is a shortcut for checking
461             C<equals> and C<is_subtype_of>.
462              
463             =head2 $constraint->coerce($value)
464              
465             This will attempt to coerce the value to the type. If the type does not
466             have any defined coercions this will throw an error.
467              
468             If no coercion can produce a value matching C<$constraint>, the original
469             value is returned.
470              
471             =head2 $constraint->assert_coerce($value)
472              
473             This method behaves just like C<coerce>, but if the result is not valid
474             according to C<$constraint>, an error is thrown.
475              
476             =head2 $constraint->check($value)
477              
478             Returns true if the given value passes the constraint for the type.
479              
480             =head2 $constraint->validate($value)
481              
482             This is similar to C<check>. However, if the type I<is valid> then the
483             method returns an explicit C<undef>. If the type is not valid, we call
484             C<< $self->get_message($value) >> internally to generate an error
485             message.
486              
487             =head2 $constraint->assert_valid($value)
488              
489             Like C<check> and C<validate>, this method checks whether C<$value> is
490             valid under the constraint. If it is, it will return true. If it is not,
491             an exception will be thrown with the results of
492             C<< $self->get_message($value) >>.
493              
494             =head2 $constraint->name
495              
496             Returns the type's name, as provided to the constructor.
497              
498             =head2 $constraint->parent
499              
500             Returns the type's parent, as provided to the constructor, if any.
501              
502             =head2 $constraint->has_parent
503              
504             Returns true if the type has a parent type.
505              
506             =head2 $constraint->parents
507              
508             Returns all of the types parents as an list of type constraint objects.
509              
510             =head2 $constraint->constraint
511              
512             Returns the type's constraint, as provided to the constructor.
513              
514             =head2 $constraint->get_message($value)
515              
516             This generates a method for the given value. If the type does not have
517             an explicit message, we generate a default message.
518              
519             =head2 $constraint->has_message
520              
521             Returns true if the type has a message.
522              
523             =head2 $constraint->message
524              
525             Returns the type's message as a subroutine reference.
526              
527             =head2 $constraint->coercion
528              
529             Returns the type's L<Moose::Meta::TypeCoercion> object, if one
530             exists.
531              
532             =head2 $constraint->has_coercion
533              
534             Returns true if the type has a coercion.
535              
536             =head2 $constraint->can_be_inlined
537              
538             Returns true if this type constraint can be inlined. A type constraint which
539             subtypes an inlinable constraint and does not add an additional constraint
540             "inherits" its parent type's inlining.
541              
542             =head2 $constraint->create_child_type(%options)
543              
544             This returns a new type constraint of the same class using the
545             provided C<%options>. The C<parent> option will be the current type.
546              
547             This method exists so that subclasses of this class can override this
548             behavior and change how child types are created.
549              
550             =head1 BUGS
551              
552             See L<Moose/BUGS> for details on reporting bugs.
553              
554             =head1 AUTHORS
555              
556             =over 4
557              
558             =item *
559              
560             Stevan Little <stevan@cpan.org>
561              
562             =item *
563              
564             Dave Rolsky <autarch@urth.org>
565              
566             =item *
567              
568             Jesse Luehrs <doy@cpan.org>
569              
570             =item *
571              
572             Shawn M Moore <sartak@cpan.org>
573              
574             =item *
575              
576             יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
577              
578             =item *
579              
580             Karen Etheridge <ether@cpan.org>
581              
582             =item *
583              
584             Florian Ragwitz <rafl@debian.org>
585              
586             =item *
587              
588             Hans Dieter Pearcey <hdp@cpan.org>
589              
590             =item *
591              
592             Chris Prather <chris@prather.org>
593              
594             =item *
595              
596             Matt S Trout <mstrout@cpan.org>
597              
598             =back
599              
600             =head1 COPYRIGHT AND LICENSE
601              
602             This software is copyright (c) 2006 by Infinity Interactive, Inc.
603              
604             This is free software; you can redistribute it and/or modify it under
605             the same terms as the Perl 5 programming language system itself.
606              
607             =cut