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   24189 use strict;
  18         36  
  18         468  
2 18     18   95 use warnings;
  18         32  
  18         872  
3             package MooseX::Types::TypeDecorator;
4             # ABSTRACT: Wraps Moose::Meta::TypeConstraint objects with added features
5              
6             our $VERSION = '0.46';
7              
8 18     18   12145 use Carp::Clan '^MooseX::Types';
  18         32347  
  18         127  
9 18     18   3499 use Moose::Util::TypeConstraints ();
  18         284763  
  18         440  
10 18     18   108 use Moose::Meta::TypeConstraint::Union;
  18         92  
  18         656  
11 18     18   87 use Scalar::Util qw(blessed);
  18         35  
  18         1187  
12 18     18   9614 use namespace::autoclean 0.16;
  18         110017  
  18         159  
13              
14             use overload(
15             '0+' => sub {
16 4     4   7 my $self = shift @_;
17 4         11 my $tc = $self->{__type_constraint};
18 4         12 return 0+$tc;
19             },
20             # workaround for perl 5.8.5 bug
21 4     4   23 '==' => sub { 0+$_[0] == 0+$_[1] },
22             '""' => sub {
23 187     187   6422 my $self = shift @_;
24 187 50       599 if(blessed $self) {
25 187         409 return $self->__type_constraint->name;
26             } else {
27 0         0 return "$self";
28             }
29             },
30 133     133   2339 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   65 my @args = @_[0,1]; ## arg 3 is special, see the overload docs.
38 32         7890 my @tc = grep {blessed $_} map {
39 17 100 66     33 blessed $_ ? $_ :
  34         147  
40             Moose::Util::TypeConstraints::find_or_parse_type_constraint($_)
41             || __PACKAGE__->_throw_error( "$_ is not a type constraint")
42             } @args;
43              
44 16 50       57 ( 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       47 ( scalar @tc >= 2 )
49             || __PACKAGE__->_throw_error("You must pass in at least 2 type names to make a union");
50              
51 16         130 my $union = Moose::Meta::TypeConstraint::Union->new(type_constraints=>\@tc);
52 16         8443 return Moose::Util::TypeConstraints::register_type_constraint($union);
53             },
54 18         366 fallback => 1,
55 18     18   6991 );
  18         37  
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 253     253 1 368 my $proto = shift;
74 253 100       569 if (ref($proto)) {
75 3         10 return $proto->_try_delegate('new', @_);
76             }
77 250         312 my $class = $proto;
78 250 50       2732 if(my $arg = shift @_) {
79 250 100 66     3034 if(blessed $arg && $arg->isa('Moose::Meta::TypeConstraint')) {
    50 33        
    0          
80 198         924 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 52         248 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 934     934   1263 my $self = shift @_;
105 934 50       2597 if(blessed $self) {
106 934 50       2025 if(defined(my $tc = shift @_)) {
107 0         0 $self->{__type_constraint} = $tc;
108             }
109 934         3804 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 167     167 1 87152 my $self = shift;
124             return
125 167 100 66     1051 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 39     39 1 80395 my $self = shift;
139              
140 39 100       422 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   90 shift;
153 1         10 require Moose;
154 1         2 unshift @_, 'Moose';
155 1         7 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 663     663   377409 my ($self, @args) = @_;
180 663         4250 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 663         1760 $self->_try_delegate($method, @args);
187             }
188              
189             sub _try_delegate {
190 671     671   1119 my ($self, $method, @args) = @_;
191 671         1258 my $tc = $self->__type_constraint;
192 671         953 my $class;
193 671 100       2548 if ($tc->can('is_subtype_of')) { # Union can't
194 661         741 my $search_tc = $tc;
195 661         730 while (1) {
196 676 100       5534 if ($search_tc->isa('Moose::Meta::TypeConstraint::Class')) {
197 15         520 $class = $search_tc->class;
198 15         86 last;
199             }
200 661         19537 $search_tc = $search_tc->parent;
201 661 100 100     4587 last unless $search_tc && $search_tc->is_subtype_of('Object');
202             }
203             }
204              
205 671         318786 my $inv = do {
206 671 100 66     2255 if ($method eq 'new') {
    50          
207 3 100       37 die "new called on type decorator for non-class-type ".$tc->name
208             unless $class;
209 2 100       48 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         3 $class
214             } elsif ($class && !$tc->can($method)) {
215 0         0 $class
216             } else {
217 668         1020 $tc
218             }
219             };
220              
221 669         7727 $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.46
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 AUTHOR
283              
284             Robert "phaylon" Sedlacek <rs@474.at>
285              
286             =head1 COPYRIGHT AND LICENSE
287              
288             This software is copyright (c) 2007 by Robert "phaylon" Sedlacek.
289              
290             This is free software; you can redistribute it and/or modify it under
291             the same terms as the Perl 5 programming language system itself.
292              
293             =cut