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 18     18   91093 use strict;
  18         39  
  18         653  
2 18     18   104 use warnings;
  18         48  
  18         1045  
3             package MooseX::Types::TypeDecorator;
4             # ABSTRACT: Wraps Moose::Meta::TypeConstraint objects with added features
5             $MooseX::Types::TypeDecorator::VERSION = '0.45';
6 18     18   15321 use Carp::Clan '^MooseX::Types';
  18         46902  
  18         135  
7 18     18   4449 use Moose::Util::TypeConstraints ();
  18         434436  
  18         376  
8 18     18   128 use Moose::Meta::TypeConstraint::Union;
  18         104  
  18         747  
9 18     18   114 use Scalar::Util qw(blessed);
  18         33  
  18         1289  
10 18     18   13428 use namespace::autoclean 0.16;
  18         22391  
  18         198  
11              
12             use overload(
13             '0+' => sub {
14 4     4   7 my $self = shift @_;
15 4         9 my $tc = $self->{__type_constraint};
16 4         12 return 0+$tc;
17             },
18             # workaround for perl 5.8.5 bug
19 4     4   26 '==' => sub { 0+$_[0] == 0+$_[1] },
20             '""' => sub {
21 187     187   10911 my $self = shift @_;
22 187 50       692 if(blessed $self) {
23 187         458 return $self->__type_constraint->name;
24             } else {
25 0         0 return "$self";
26             }
27             },
28 133     133   2588 bool => sub { 1 },
29             '|' => sub {
30              
31             ## It's kind of ugly that we need to know about Union Types, but this
32             ## is needed for syntax compatibility. Maybe someday we'll all just do
33             ## Or[Str,Str,Int]
34              
35 17     17   74 my @args = @_[0,1]; ## arg 3 is special, see the overload docs.
36 32 100 66     16357 my @tc = grep {blessed $_} map {
  34         246  
37 17         46 blessed $_ ? $_ :
38             Moose::Util::TypeConstraints::find_or_parse_type_constraint($_)
39             || __PACKAGE__->_throw_error( "$_ is not a type constraint")
40             } @args;
41              
42 16 50       57 ( scalar @tc == scalar @args)
43             || __PACKAGE__->_throw_error(
44             "one of your type constraints is bad. Passed: ". join(', ', @args) ." Got: ". join(', ', @tc));
45              
46 16 50       52 ( scalar @tc >= 2 )
47             || __PACKAGE__->_throw_error("You must pass in at least 2 type names to make a union");
48              
49 16         147 my $union = Moose::Meta::TypeConstraint::Union->new(type_constraints=>\@tc);
50 16         11220 return Moose::Util::TypeConstraints::register_type_constraint($union);
51             },
52 18         375 fallback => 1,
53 18     18   7581 );
  18         39  
54              
55             #pod =head1 DESCRIPTION
56             #pod
57             #pod This is a decorator object that contains an underlying type constraint. We use
58             #pod this to control access to the type constraint and to add some features.
59             #pod
60             #pod =head1 METHODS
61             #pod
62             #pod This class defines the following methods.
63             #pod
64             #pod =head2 new
65             #pod
66             #pod Old school instantiation
67             #pod
68             #pod =cut
69              
70             sub new {
71 253     253 1 470 my $proto = shift;
72 253 100       680 if (ref($proto)) {
73 3         16 return $proto->_try_delegate('new', @_);
74             }
75 250         341 my $class = $proto;
76 250 50       3929 if(my $arg = shift @_) {
77 250 100 66     3854 if(blessed $arg && $arg->isa('Moose::Meta::TypeConstraint')) {
    50 33        
    0          
78 198         1339 return bless {'__type_constraint'=>$arg}, $class;
79             } elsif(
80             blessed $arg &&
81             $arg->isa('MooseX::Types::UndefinedType')
82             ) {
83             ## stub in case we'll need to handle these types differently
84 52         311 return bless {'__type_constraint'=>$arg}, $class;
85             } elsif(blessed $arg) {
86 0         0 __PACKAGE__->_throw_error("Argument must be ->isa('Moose::Meta::TypeConstraint') or ->isa('MooseX::Types::UndefinedType'), not ". blessed $arg);
87             } else {
88 0         0 __PACKAGE__->_throw_error("Argument cannot be '$arg'");
89             }
90             } else {
91 0         0 __PACKAGE__->_throw_error("This method [new] requires a single argument.");
92             }
93             }
94              
95             #pod =head2 __type_constraint ($type_constraint)
96             #pod
97             #pod Set/Get the type_constraint.
98             #pod
99             #pod =cut
100              
101             sub __type_constraint {
102 931     931   1531 my $self = shift @_;
103 931 50       3068 if(blessed $self) {
104 931 50       2238 if(defined(my $tc = shift @_)) {
105 0         0 $self->{__type_constraint} = $tc;
106             }
107 931         5229 return $self->{__type_constraint};
108             } else {
109 0         0 __PACKAGE__->_throw_error('cannot call __type_constraint as a class method');
110             }
111             }
112              
113             #pod =head2 C<isa>
114             #pod
115             #pod handle C<< $self->isa >> since C<AUTOLOAD> can't - this tries both the type constraint,
116             #pod and for a class type, the class.
117             #pod
118             #pod =cut
119              
120             sub isa {
121 166     166 1 195748 my $self = shift;
122             return
123 166 100 66     1408 blessed $self
124             ? $self->__type_constraint->isa(@_)
125             || $self->_try_delegate( 'isa', @_ )
126             : $self->SUPER::isa(@_);
127             }
128              
129             #pod =head2 can
130             #pod
131             #pod handle $self->can since AUTOLOAD can't.
132             #pod
133             #pod =cut
134              
135             sub can {
136 39     39 1 87737 my $self = shift;
137              
138 39 100       494 return blessed $self
139             ? $self->_try_delegate( 'can', @_ )
140             : $self->SUPER::can(@_);
141             }
142              
143             #pod =head2 _throw_error
144             #pod
145             #pod properly delegate error messages
146             #pod
147             #pod =cut
148              
149             sub _throw_error {
150 1     1   115 shift;
151 1         9 require Moose;
152 1         5 unshift @_, 'Moose';
153 1         8 goto &Moose::throw_error;
154             }
155              
156             #pod =head2 DESTROY
157             #pod
158             #pod We might need it later
159             #pod
160             #pod =cut
161              
162             sub DESTROY {
163 0     0   0 return;
164             }
165              
166             #pod =head2 AUTOLOAD
167             #pod
168             #pod Delegate to the decorator target, unless this is a class type, in which
169             #pod case it will try to delegate to the type object, then if that fails try
170             #pod the class. The method 'new' is special cased to only be permitted on
171             #pod the class; if there is no class, or it does not provide a new method,
172             #pod an exception will be thrown.
173             #pod
174             #pod =cut
175              
176             sub AUTOLOAD {
177 662     662   547776 my ($self, @args) = @_;
178 662         4907 my ($method) = (our $AUTOLOAD =~ /([^:]+)$/);
179              
180             ## We delegate with this method in an attempt to support a value of
181             ## __type_constraint which is also AUTOLOADing, in particular the class
182             ## MooseX::Types::UndefinedType which AUTOLOADs during autovivication.
183              
184 662         1824 $self->_try_delegate($method, @args);
185             }
186              
187             sub _try_delegate {
188 669     669   1252 my ($self, $method, @args) = @_;
189 669         1597 my $tc = $self->__type_constraint;
190 669         1466 my $class;
191 669 100       2978 if ($tc->can('is_subtype_of')) { # Union can't
192 659         822 my $search_tc = $tc;
193 659         767 while (1) {
194 672 100       7526 if ($search_tc->isa('Moose::Meta::TypeConstraint::Class')) {
195 13         502 $class = $search_tc->class;
196 13         80 last;
197             }
198 659         25683 $search_tc = $search_tc->parent;
199 659 100 100     5852 last unless $search_tc && $search_tc->is_subtype_of('Object');
200             }
201             }
202              
203 669         428047 my $inv = do {
204 669 100 66     2646 if ($method eq 'new') {
    50          
205 3 100       42 die "new called on type decorator for non-class-type ".$tc->name
206             unless $class;
207 2 100       63 die "new called on class type decorator ".$tc->name."\n"
208             ." for class ${class}\n"
209             ." which does not provide a new method - did you forget to load it?"
210             unless $class->can('new');
211 1         4 $class
212             } elsif ($class && !$tc->can($method)) {
213 0         0 $class
214             } else {
215 666         1215 $tc
216             }
217             };
218              
219 667         9606 $inv->$method(@args);
220             }
221              
222             1;
223              
224             __END__
225              
226             =pod
227              
228             =encoding UTF-8
229              
230             =head1 NAME
231              
232             MooseX::Types::TypeDecorator - Wraps Moose::Meta::TypeConstraint objects with added features
233              
234             =head1 VERSION
235              
236             version 0.45
237              
238             =head1 DESCRIPTION
239              
240             This is a decorator object that contains an underlying type constraint. We use
241             this to control access to the type constraint and to add some features.
242              
243             =head1 METHODS
244              
245             This class defines the following methods.
246              
247             =head2 new
248              
249             Old school instantiation
250              
251             =head2 __type_constraint ($type_constraint)
252              
253             Set/Get the type_constraint.
254              
255             =head2 C<isa>
256              
257             handle C<< $self->isa >> since C<AUTOLOAD> can't - this tries both the type constraint,
258             and for a class type, the class.
259              
260             =head2 can
261              
262             handle $self->can since AUTOLOAD can't.
263              
264             =head2 _throw_error
265              
266             properly delegate error messages
267              
268             =head2 DESTROY
269              
270             We might need it later
271              
272             =head2 AUTOLOAD
273              
274             Delegate to the decorator target, unless this is a class type, in which
275             case it will try to delegate to the type object, then if that fails try
276             the class. The method 'new' is special cased to only be permitted on
277             the class; if there is no class, or it does not provide a new method,
278             an exception will be thrown.
279              
280             =head1 AUTHOR
281              
282             Robert "phaylon" Sedlacek <rs@474.at>
283              
284             =head1 COPYRIGHT AND LICENSE
285              
286             This software is copyright (c) 2007 by Robert "phaylon" Sedlacek.
287              
288             This is free software; you can redistribute it and/or modify it under
289             the same terms as the Perl 5 programming language system itself.
290              
291             =cut