File Coverage

blib/lib/MooseX/Types/TypeDecorator.pm
Criterion Covered Total %
statement 81 89 91.0
branch 30 40 75.0
condition 12 18 66.6
subroutine 20 21 95.2
pod 3 3 100.0
total 146 171 85.3


line stmt bran cond sub pod time code
1 19     19   87859 use strict;
  19         46  
  19         754  
2 19     19   98 use warnings;
  19         39  
  19         1514  
3             package MooseX::Types::TypeDecorator;
4             # ABSTRACT: Wraps Moose::Meta::TypeConstraint objects with added features
5              
6             our $VERSION = '0.51';
7              
8 19     19   9406 use Carp::Clan '^MooseX::Types';
  19         42928  
  19         169  
9 19     19   2747 use Moose::Util::TypeConstraints ();
  19         257486  
  19         446  
10 19     19   97 use Moose::Meta::TypeConstraint::Union;
  19         41  
  19         907  
11 19     19   106 use Scalar::Util qw(blessed);
  19         35  
  19         2882  
12 19     19   7514 use namespace::autoclean 0.16;
  19         133574  
  19         173  
13              
14             use overload(
15             '0+' => sub {
16 4     4   9 my $self = shift @_;
17 4         8 my $tc = $self->{__type_constraint};
18 4         10 return 0+$tc;
19             },
20             # workaround for perl 5.8.5 bug
21 4     4   24 '==' => sub { 0+$_[0] == 0+$_[1] },
22             '""' => sub {
23 205     205   16669 my $self = shift @_;
24 205 50       462 if(blessed $self) {
25 205         547 return $self->__type_constraint->name;
26             } else {
27 0         0 return "$self";
28             }
29             },
30 147     147   3731 bool => sub { 1 },
31             '|' => sub {
32              
33             ## It's kind of ugly that we need to know about Union Types, but this
34             ## is needed for syntax compatibility. Maybe someday we'll all just do
35             ## Or[Str,Str,Int]
36              
37 17     17   95 my @args = @_[0,1]; ## arg 3 is special, see the overload docs.
38 32         4985 my @tc = grep {blessed $_} map {
39 17 100 66     70 blessed $_ ? $_ :
  34         107  
40             Moose::Util::TypeConstraints::find_or_parse_type_constraint($_)
41             || __PACKAGE__->_throw_error( "$_ is not a type constraint")
42             } @args;
43              
44 16 50       61 ( scalar @tc == scalar @args)
45             || __PACKAGE__->_throw_error(
46             "one of your type constraints is bad. Passed: ". join(', ', @args) ." Got: ". join(', ', @tc));
47              
48 16 50       99 ( scalar @tc >= 2 )
49             || __PACKAGE__->_throw_error("You must pass in at least 2 type names to make a union");
50              
51 16         162 my $union = Moose::Meta::TypeConstraint::Union->new(type_constraints=>\@tc);
52 16         10830 return Moose::Util::TypeConstraints::register_type_constraint($union);
53             },
54 19         478 fallback => 1,
55 19     19   8636 );
  19         73  
56              
57             #pod =head1 DESCRIPTION
58             #pod
59             #pod This is a decorator object that contains an underlying type constraint. We use
60             #pod this to control access to the type constraint and to add some features.
61             #pod
62             #pod =head1 METHODS
63             #pod
64             #pod This class defines the following methods.
65             #pod
66             #pod =head2 new
67             #pod
68             #pod Old school instantiation
69             #pod
70             #pod =cut
71              
72             sub new {
73 271     271 1 476 my $proto = shift;
74 271 100       720 if (ref($proto)) {
75 3         17 return $proto->_try_delegate('new', @_);
76             }
77 268         428 my $class = $proto;
78 268 50       2574 if(my $arg = shift @_) {
79 268 100 66     2900 if(blessed $arg && $arg->isa('Moose::Meta::TypeConstraint')) {
    50 33        
    0          
80 210         1053 return bless {'__type_constraint'=>$arg}, $class;
81             } elsif(
82             blessed $arg &&
83             $arg->isa('MooseX::Types::UndefinedType')
84             ) {
85             ## stub in case we'll need to handle these types differently
86 58         333 return bless {'__type_constraint'=>$arg}, $class;
87             } elsif(blessed $arg) {
88 0         0 __PACKAGE__->_throw_error("Argument must be ->isa('Moose::Meta::TypeConstraint') or ->isa('MooseX::Types::UndefinedType'), not ". blessed $arg);
89             } else {
90 0         0 __PACKAGE__->_throw_error("Argument cannot be '$arg'");
91             }
92             } else {
93 0         0 __PACKAGE__->_throw_error("This method [new] requires a single argument.");
94             }
95             }
96              
97             #pod =head2 __type_constraint ($type_constraint)
98             #pod
99             #pod Set/Get the type_constraint.
100             #pod
101             #pod =cut
102              
103             sub __type_constraint {
104 966     966   1698 my $self = shift @_;
105 966 50       1775 if(blessed $self) {
106 966 50       2106 if(defined(my $tc = shift @_)) {
107 0         0 $self->{__type_constraint} = $tc;
108             }
109 966         3845 return $self->{__type_constraint};
110             } else {
111 0         0 __PACKAGE__->_throw_error('cannot call __type_constraint as a class method');
112             }
113             }
114              
115             #pod =head2 C<isa>
116             #pod
117             #pod handle C<< $self->isa >> since C<AUTOLOAD> can't - this tries both the type constraint,
118             #pod and for a class type, the class.
119             #pod
120             #pod =cut
121              
122             sub isa {
123 161     161 1 519321 my $self = shift;
124             return
125 161 100 66     787 blessed $self
126             ? $self->__type_constraint->isa(@_)
127             || $self->_try_delegate( 'isa', @_ )
128             : $self->SUPER::isa(@_);
129             }
130              
131             #pod =head2 can
132             #pod
133             #pod handle $self->can since AUTOLOAD can't.
134             #pod
135             #pod =cut
136              
137             sub can {
138 54     54 1 149927 my $self = shift;
139              
140 54 100       514 return blessed $self
141             ? $self->_try_delegate( 'can', @_ )
142             : $self->SUPER::can(@_);
143             }
144              
145             #pod =head2 _throw_error
146             #pod
147             #pod properly delegate error messages
148             #pod
149             #pod =cut
150              
151             sub _throw_error {
152 1     1   82 shift;
153 1         493 require Moose;
154 1         144706 unshift @_, 'Moose';
155 1         5 goto &Moose::throw_error;
156             }
157              
158             #pod =head2 DESTROY
159             #pod
160             #pod We might need it later
161             #pod
162             #pod =cut
163              
164             sub DESTROY {
165 0     0   0 return;
166             }
167              
168             #pod =head2 AUTOLOAD
169             #pod
170             #pod Delegate to the decorator target, unless this is a class type, in which
171             #pod case it will try to delegate to the type object, then if that fails try
172             #pod the class. The method 'new' is special cased to only be permitted on
173             #pod the class; if there is no class, or it does not provide a new method,
174             #pod an exception will be thrown.
175             #pod
176             #pod =cut
177              
178             sub AUTOLOAD {
179 675     675   370999 my ($self, @args) = @_;
180 675         3900 my ($method) = (our $AUTOLOAD =~ /([^:]+)$/);
181              
182             ## We delegate with this method in an attempt to support a value of
183             ## __type_constraint which is also AUTOLOADing, in particular the class
184             ## MooseX::Types::UndefinedType which AUTOLOADs during autovivication.
185              
186 675         1546 $self->_try_delegate($method, @args);
187             }
188              
189             sub _try_delegate {
190 696     696   1363 my ($self, $method, @args) = @_;
191 696         1521 my $tc = $self->__type_constraint;
192 696         1075 my $class;
193 696 100       2666 if ($tc->can('is_subtype_of')) { # Union can't
194 686         950 my $search_tc = $tc;
195 686         835 while (1) {
196 702 100       5854 if ($search_tc->isa('Moose::Meta::TypeConstraint::Class')) {
197 16         505 $class = $search_tc->class;
198 16         104 last;
199             }
200 686         24321 $search_tc = $search_tc->parent;
201 686 100 100     4931 last unless $search_tc && $search_tc->is_subtype_of('Object');
202             }
203             }
204              
205 696         320860 my $inv = do {
206 696 100 66     2233 if ($method eq 'new') {
    50          
207 3 100       50 die "new called on type decorator for non-class-type ".$tc->name
208             unless $class;
209 2 100       75 die "new called on class type decorator ".$tc->name."\n"
210             ." for class ${class}\n"
211             ." which does not provide a new method - did you forget to load it?"
212             unless $class->can('new');
213 1         5 $class
214             } elsif ($class && !$tc->can($method)) {
215 0         0 $class
216             } else {
217 693         1051 $tc
218             }
219             };
220              
221 694         8270 $inv->$method(@args);
222             }
223              
224             1;
225              
226             __END__
227              
228             =pod
229              
230             =encoding UTF-8
231              
232             =head1 NAME
233              
234             MooseX::Types::TypeDecorator - Wraps Moose::Meta::TypeConstraint objects with added features
235              
236             =head1 VERSION
237              
238             version 0.51
239              
240             =head1 DESCRIPTION
241              
242             This is a decorator object that contains an underlying type constraint. We use
243             this to control access to the type constraint and to add some features.
244              
245             =head1 METHODS
246              
247             This class defines the following methods.
248              
249             =head2 new
250              
251             Old school instantiation
252              
253             =head2 __type_constraint ($type_constraint)
254              
255             Set/Get the type_constraint.
256              
257             =head2 C<isa>
258              
259             handle C<< $self->isa >> since C<AUTOLOAD> can't - this tries both the type constraint,
260             and for a class type, the class.
261              
262             =head2 can
263              
264             handle $self->can since AUTOLOAD can't.
265              
266             =head2 _throw_error
267              
268             properly delegate error messages
269              
270             =head2 DESTROY
271              
272             We might need it later
273              
274             =head2 AUTOLOAD
275              
276             Delegate to the decorator target, unless this is a class type, in which
277             case it will try to delegate to the type object, then if that fails try
278             the class. The method 'new' is special cased to only be permitted on
279             the class; if there is no class, or it does not provide a new method,
280             an exception will be thrown.
281              
282             =head1 SUPPORT
283              
284             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=MooseX-Types>
285             (or L<bug-MooseX-Types@rt.cpan.org|mailto:bug-MooseX-Types@rt.cpan.org>).
286              
287             There is also a mailing list available for users of this distribution, at
288             L<http://lists.perl.org/list/moose.html>.
289              
290             There is also an irc channel available for users of this distribution, at
291             L<C<#moose> on C<irc.perl.org>|irc://irc.perl.org/#moose>.
292              
293             =head1 AUTHOR
294              
295             Robert "phaylon" Sedlacek <rs@474.at>
296              
297             =head1 COPYRIGHT AND LICENCE
298              
299             This software is copyright (c) 2007 by Robert "phaylon" Sedlacek.
300              
301             This is free software; you can redistribute it and/or modify it under
302             the same terms as the Perl 5 programming language system itself.
303              
304             =cut