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   28214 use strict;
  19         30  
  19         633  
2 19     19   100 use warnings;
  19         28  
  19         1097  
3             package MooseX::Types::TypeDecorator;
4             # ABSTRACT: Wraps Moose::Meta::TypeConstraint objects with added features
5              
6             our $VERSION = '0.50';
7              
8 19     19   9782 use Carp::Clan '^MooseX::Types';
  19         37823  
  19         135  
9 19     19   3794 use Moose::Util::TypeConstraints ();
  19         244824  
  19         400  
10 19     19   95 use Moose::Meta::TypeConstraint::Union;
  19         94  
  19         836  
11 19     19   104 use Scalar::Util qw(blessed);
  19         32  
  19         1692  
12 19     19   8318 use namespace::autoclean 0.16;
  19         125011  
  19         171  
13              
14             use overload(
15             '0+' => sub {
16 4     4   6 my $self = shift @_;
17 4         7 my $tc = $self->{__type_constraint};
18 4         9 return 0+$tc;
19             },
20             # workaround for perl 5.8.5 bug
21 4     4   18 '==' => sub { 0+$_[0] == 0+$_[1] },
22             '""' => sub {
23 208     208   9968 my $self = shift @_;
24 208 50       683 if(blessed $self) {
25 208         416 return $self->__type_constraint->name;
26             } else {
27 0         0 return "$self";
28             }
29             },
30 153     153   2627 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   73 my @args = @_[0,1]; ## arg 3 is special, see the overload docs.
38 32         6653 my @tc = grep {blessed $_} map {
39 17 100 66     42 blessed $_ ? $_ :
  34         153  
40             Moose::Util::TypeConstraints::find_or_parse_type_constraint($_)
41             || __PACKAGE__->_throw_error( "$_ is not a type constraint")
42             } @args;
43              
44 16 50       79 ( 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       55 ( scalar @tc >= 2 )
49             || __PACKAGE__->_throw_error("You must pass in at least 2 type names to make a union");
50              
51 16         148 my $union = Moose::Meta::TypeConstraint::Union->new(type_constraints=>\@tc);
52 16         9449 return Moose::Util::TypeConstraints::register_type_constraint($union);
53             },
54 19         396 fallback => 1,
55 19     19   8043 );
  19         43  
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 276     276 1 389 my $proto = shift;
74 276 100       611 if (ref($proto)) {
75 3         12 return $proto->_try_delegate('new', @_);
76             }
77 273         315 my $class = $proto;
78 273 50       2696 if(my $arg = shift @_) {
79 273 100 66     3488 if(blessed $arg && $arg->isa('Moose::Meta::TypeConstraint')) {
    50 33        
    0          
80 215         1322 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         296 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 1033     1033   1285 my $self = shift @_;
105 1033 50       2838 if(blessed $self) {
106 1033 50       2124 if(defined(my $tc = shift @_)) {
107 0         0 $self->{__type_constraint} = $tc;
108             }
109 1033         16613 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 170     170 1 45895 my $self = shift;
124             return
125 170 100 66     1015 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 56     56 1 749967 my $self = shift;
139              
140 56 100       546 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   128 shift;
153 1         9 require Moose;
154 1         4 unshift @_, 'Moose';
155 1         8 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 728     728   391332 my ($self, @args) = @_;
180 728         5022 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 728         1776 $self->_try_delegate($method, @args);
187             }
188              
189             sub _try_delegate {
190 751     751   1194 my ($self, $method, @args) = @_;
191 751         1259 my $tc = $self->__type_constraint;
192 751         732 my $class;
193 751 100       2933 if ($tc->can('is_subtype_of')) { # Union can't
194 741         704 my $search_tc = $tc;
195 741         631 while (1) {
196 757 100       7650 if ($search_tc->isa('Moose::Meta::TypeConstraint::Class')) {
197 16         726 $class = $search_tc->class;
198 16         111 last;
199             }
200 741         25201 $search_tc = $search_tc->parent;
201 741 100 100     5006 last unless $search_tc && $search_tc->is_subtype_of('Object');
202             }
203             }
204              
205 751         370380 my $inv = do {
206 751 100 66     2430 if ($method eq 'new') {
    50          
207 3 100       49 die "new called on type decorator for non-class-type ".$tc->name
208             unless $class;
209 2 100       85 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         4 $class
214             } elsif ($class && !$tc->can($method)) {
215 0         0 $class
216             } else {
217 748         883 $tc
218             }
219             };
220              
221 749         9296 $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.50
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