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.2203';
3              
4 401     401   111890 use strict;
  401         848  
  401         11863  
5 401     401   1899 use warnings;
  401         774  
  401         9150  
6 401     401   136838 use metaclass;
  401         992  
  401         2071  
7              
8 3529     3529   13587 use overload '0+' => sub { refaddr(shift) }, # id an object
9 169     169   30532 '""' => sub { shift->name }, # stringify to tc name
10 91988     91988   265031 bool => sub { 1 },
11 401     401   2988 fallback => 1;
  401         886  
  401         5761  
12              
13 401     401   44657 use Eval::Closure;
  401         837  
  401         22892  
14 401     401   2641 use Scalar::Util qw(refaddr);
  401         1011  
  401         18156  
15 401     401   2815 use Sub::Util qw(set_subname);
  401         945  
  401         18032  
16 401     401   2561 use Try::Tiny;
  401         905  
  401         21154  
17              
18 401     401   2541 use parent 'Class::MOP::Object';
  401         890  
  401         2567  
19              
20 401     401   27647 use Moose::Util 'throw_exception';
  401         905  
  401         2748  
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 4 my $self = shift;
95 1         5 $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 11906     11906 1 23748 my $class = shift;
113 11906         30038 my ($first, @rest) = @_;
114 11906 100       53679 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
    100          
115 11906 100       41714 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
116              
117 11906 100 66     26751 if ( exists $args{message}
      66        
118             && (!ref($args{message}) || ref($args{message}) ne 'CODE') ) {
119 1         6 throw_exception( MessageParameterMustBeCodeRef => params => \%args,
120             class => $class
121             );
122             }
123              
124 11905         336696 my $self = $class->_new(%args);
125 11905 50       401333 $self->compile_type_constraint()
126             unless $self->_has_compiled_type_constraint;
127 11899 100       335205 $self->_default_message($_default_message_generator->($self->name))
128             unless $self->has_message;
129 11899         59675 return $self;
130             }
131              
132              
133              
134             sub coerce {
135 133     133 1 922 my $self = shift;
136              
137 133         3088 my $coercion = $self->coercion;
138              
139 133 100       355 unless ($coercion) {
140 2         46 throw_exception( CoercingWithoutCoercions => type_name => $self->name );
141             }
142              
143 131 100       339 return $_[0] if $self->check($_[0]);
144              
145 116         1064 return $coercion->coerce(@_);
146             }
147              
148             sub assert_coerce {
149 3     3 1 2562 my $self = shift;
150              
151 3         8 my $result = $self->coerce(@_);
152              
153 3         15 $self->assert_valid($result);
154              
155 2         22 return $result;
156             }
157              
158             sub check {
159 9440     9440 1 150209 my ($self, @args) = @_;
160 9440         289388 my $constraint_subref = $self->_compiled_type_constraint;
161 9440 100       110822 return $constraint_subref->(@args) ? 1 : undef;
162             }
163              
164             sub validate {
165 18     18 1 509 my ($self, $value) = @_;
166 18 100       671 if ($self->_compiled_type_constraint->($value)) {
167 6         47 return undef;
168             }
169             else {
170 12         84 $self->get_message($value);
171             }
172             }
173              
174             sub can_be_inlined {
175 48500     48500 1 63075 my $self = shift;
176              
177 48500 100 100     1265154 if ( $self->has_parent && $self->constraint == $null_constraint ) {
178 1107         27683 return $self->parent->can_be_inlined;
179             }
180              
181 47393         1363219 return $self->_has_inlined_type_constraint;
182             }
183              
184             sub _inline_check {
185 24886     24886   35545 my $self = shift;
186              
187 24886 100       39239 unless ( $self->can_be_inlined ) {
188 2         47 throw_exception( CannotInlineTypeConstraintCheck => type_name => $self->name );
189             }
190              
191 24884 100 100     638213 if ( $self->has_parent && $self->constraint == $null_constraint ) {
192 522         13543 return $self->parent->_inline_check(@_);
193             }
194              
195 24362         572513 return '( do { ' . $self->inlined->( $self, @_ ) . ' } )';
196             }
197              
198             sub inline_environment {
199 21879     21879 1 36187 my $self = shift;
200              
201 21879 100 100     575579 if ( $self->has_parent && $self->constraint == $null_constraint ) {
202 506         12935 return $self->parent->inline_environment;
203             }
204              
205 21373         625582 return $self->_inline_environment;
206             }
207              
208             sub assert_valid {
209 8     8 1 756 my ( $self, $value ) = @_;
210              
211 8 100       25 return 1 if $self->check($value);
212              
213 3         39 throw_exception(
214             'ValidationFailedForTypeConstraint',
215             type => $self,
216             value => $value
217             );
218             }
219              
220             sub get_message {
221 926     926 1 1866 my ($self, $value) = @_;
222 926 100       23456 my $msg = $self->has_message
223             ? $self->message
224             : $self->_default_message;
225 926         1625 local $_ = $value;
226 926         2037 return $msg->($value);
227             }
228              
229             ## type predicates ...
230              
231             sub equals {
232 1765     1765 1 3368 my ( $self, $type_or_name ) = @_;
233              
234 1765         3304 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
235 1765 100       3057 return if not $other;
236              
237 1764 100       3546 return 1 if $self == $other;
238              
239 1357 100       33052 return unless $self->constraint == $other->constraint;
240              
241 1 50       26 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       26 return if $other->has_parent;
246             }
247              
248 1         6 return;
249             }
250              
251             sub is_a_type_of {
252 265     265 1 949 my ($self, $type_or_name) = @_;
253              
254 265         793 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
255 265 100       771 return if not $type;
256              
257 261 100       1070 ($self->equals($type) || $self->is_subtype_of($type));
258             }
259              
260             sub is_subtype_of {
261 579     579 1 2043 my ($self, $type_or_name) = @_;
262              
263 579         1537 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
264 579 100       1484 return if not $type;
265              
266 575         1002 my $current = $self;
267              
268 575         13786 while (my $parent = $current->parent) {
269 1602 100       2926 return 1 if $parent->equals($type);
270 1285         29289 $current = $parent;
271             }
272              
273 258         1078 return 0;
274             }
275              
276             ## compiling the type constraint
277              
278             sub compile_type_constraint {
279 14981     14981 0 22413 my $self = shift;
280 14981         31363 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
281             }
282              
283             ## type compilers ...
284              
285             sub _actually_compile_type_constraint {
286 14908     14908   20348 my $self = shift;
287              
288 14908 100       30793 if ( $self->can_be_inlined ) {
289 14791         35012 return eval_closure(
290             source => 'sub { ' . $self->_inline_check('$_[0]') . ' }',
291             environment => $self->inline_environment,
292             );
293             }
294              
295 117         2896 my $check = $self->constraint;
296 117 100       406 unless ( defined $check ) {
297 1         23 throw_exception( NoConstraintCheckForTypeConstraint => type_name => $self->name );
298             }
299              
300 116 100       3148 return $self->_compile_subtype($check)
301             if $self->has_parent;
302              
303 20         86 return $self->_compile_type($check);
304             }
305              
306             sub _compile_subtype {
307 125     125   349 my ($self, $check) = @_;
308              
309             # gather all the parent constraints in order
310 125         263 my @parents;
311 125         434 foreach my $parent ($self->_collect_all_parents) {
312 627         14329 push @parents => $parent->constraint;
313             }
314              
315 125         372 @parents = grep { $_ != $null_constraint } reverse @parents;
  627         1262  
316              
317 125 100       388 unless ( @parents ) {
318 2         6 return $self->_compile_type($check);
319             } else {
320             # general case, check all the constraints, from the first parent to ourselves
321 123         322 my @checks = @parents;
322 123 100       468 push @checks, $check if $check != $null_constraint;
323             return set_subname(
324             $self->name => sub {
325 1772     1772   235085 my (@args) = @_;
326 1772         2886 local $_ = $args[0];
327 1772         3371 foreach my $check (@checks) {
328 8098 100       16754 return undef unless $check->(@args);
329             }
330 1029         5942 return 1;
331             }
332 123         3162 );
333             }
334             }
335              
336             sub _compile_type {
337 48     48   125 my ($self, $check) = @_;
338              
339 48 100       437 return $check if $check == $null_constraint; # Item, Any
340              
341             return set_subname(
342             $self->name => sub {
343 756     756   9633 my (@args) = @_;
344 756         1412 local $_ = $args[0];
345 756         2024 $check->(@args);
346             }
347 39         997 );
348             }
349              
350             ## other utils ...
351              
352             sub _collect_all_parents {
353 138     138   280 my $self = shift;
354 138         228 my @parents;
355 138         3710 my $current = $self->parent;
356 138         429 while (defined $current) {
357 683         1152 push @parents => $current;
358 683         15218 $current = $current->parent;
359             }
360 138         521 return @parents;
361             }
362              
363             sub create_child_type {
364 6489     6489 1 19687 my ($self, %opts) = @_;
365 6489         11619 my $class = ref $self;
366 6489         19266 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.2203
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