File Coverage

blib/lib/Type/Params.pm
Criterion Covered Total %
statement 169 171 98.8
branch 43 54 79.6
condition 31 50 62.0
subroutine 42 43 97.6
pod 12 12 100.0
total 297 330 90.0


line stmt bran cond sub pod time code
1             package Type::Params;
2              
3 54     54   233713 use 5.008001;
  54         230  
4 54     54   313 use strict;
  54         157  
  54         2360  
5 54     54   306 use warnings;
  54         113  
  54         2772  
6              
7             BEGIN {
8 54     54   205 $Type::Params::AUTHORITY = 'cpan:TOBYINK';
9 54         2198 $Type::Params::VERSION = '2.002001';
10             }
11              
12             $Type::Params::VERSION =~ tr/_//d;
13              
14 54     54   363 use B qw();
  54         121  
  54         1339  
15 54     54   12816 use Eval::TypeTiny qw( eval_closure set_subname );
  54         155  
  54         430  
16 54     54   28263 use Scalar::Util qw( refaddr );
  54         149  
  54         3058  
17 54     54   21099 use Error::TypeTiny;
  54         161  
  54         1805  
18 54     54   24863 use Error::TypeTiny::Assertion;
  54         180  
  54         1758  
19 54     54   22049 use Error::TypeTiny::WrongNumberOfParameters;
  54         166  
  54         1575  
20 54     54   15354 use Types::Standard ();
  54         666  
  54         1527  
21 54     54   323 use Types::TypeTiny ();
  54         124  
  54         44548  
22              
23             require Exporter::Tiny;
24             our @ISA = 'Exporter::Tiny';
25              
26             our @EXPORT = qw(
27             compile compile_named
28             );
29              
30             our @EXPORT_OK = qw(
31             compile_named_oo
32             validate validate_named
33             multisig
34             Invocant ArgsObject
35             wrap_subs wrap_methods
36             signature signature_for
37             );
38              
39             our %EXPORT_TAGS = (
40             compile => [ qw( compile compile_named compile_named_oo ) ],
41             wrap => [ qw( wrap_subs wrap_methods ) ],
42             sigs => [ qw( signature signature_for ) ],
43             validate => [ qw( validate validate_named ) ],
44            
45             v1 => [ qw( compile compile_named ) ], # Old default
46             v2 => [ qw( signature signature_for ) ], # New recommendation
47             );
48              
49             {
50             my $Invocant;
51            
52             sub Invocant () {
53 1   33 1 1 735 $Invocant ||= do {
54 1         463 require Type::Tiny::Union;
55 1         5 'Type::Tiny::Union'->new(
56             name => 'Invocant',
57             type_constraints => [
58             Types::Standard::Object(),
59             Types::Standard::ClassName(),
60             ],
61             );
62             };
63             } #/ sub Invocant
64            
65             my $ArgsObject;
66            
67             sub ArgsObject (;@) {
68 5   66 5 1 910 $ArgsObject ||= do {
69             'Type::Tiny'->new(
70             name => 'ArgsObject',
71             parent => Types::Standard::Object(),
72             constraint => q{ ref($_) =~ qr/^Type::Params::OO::/ },
73             constraint_generator => sub {
74 3     3   13 my $param = Types::Standard::assert_Str( shift );
75 3 0       34 sub { defined( $_->{'~~caller'} ) and $_->{'~~caller'} eq $param };
  0         0  
76             },
77             inline_generator => sub {
78 3     3   7 my $param = shift;
79 3         13 my $quoted = B::perlstring( $param );
80             sub {
81 3         7 my $var = pop;
82             return (
83 3         10 Types::Standard::Object()->inline_check( $var ),
84             sprintf( q{ ref(%s) =~ qr/^Type::Params::OO::/ }, $var ),
85             sprintf(
86             q{ do { use Scalar::Util (); Scalar::Util::reftype(%s) eq 'HASH' } }, $var
87             ),
88             sprintf(
89             q{ defined((%s)->{'~~caller'}) && ((%s)->{'~~caller'} eq %s) }, $var, $var,
90             $quoted
91             ),
92             );
93 3         18 };
94             },
95 2         14 );
96             };
97            
98 5 50       33 @_ ? $ArgsObject->parameterize( @{ $_[0] } ) : $ArgsObject;
  0         0  
99             } #/ sub ArgsObject (;@)
100            
101             &Scalar::Util::set_prototype( \&ArgsObject, ';$' )
102             if Eval::TypeTiny::NICE_PROTOTYPES;
103             }
104              
105             sub signature {
106 257 100   257 1 11133 if ( @_ % 2 ) {
107 1         20 require Error::TypeTiny;
108 1         7 Error::TypeTiny::croak( "Expected even-sized list of arguments" );
109             }
110 256         1005 my ( %opts ) = @_;
111              
112 256   66     3617 my $for = [ caller( 1 + ( $opts{caller_level} || 0 ) ) ]->[3] || ( ( $opts{package} || '__ANON__' ) . '::__ANON__' );
113 256         2518 my ( $pkg, $sub ) = ( $for =~ /^(.+)::(\w+)$/ );
114 256   66     1614 $opts{package} ||= $pkg;
115 256   66     1310 $opts{subname} ||= $sub;
116              
117 256         25530 require Type::Params::Signature;
118 256         1760 'Type::Params::Signature'->new_from_v2api( \%opts )->return_wanted;
119             }
120              
121             sub signature_for {
122 15 100   15 1 4962 if ( not @_ % 2 ) {
123 1         8 require Error::TypeTiny;
124 1         5 Error::TypeTiny::croak( "Expected odd-sized list of arguments; did you forget the function name?" );
125             }
126 14         68 my ( $function, %opts ) = @_;
127 14   66     111 my $package = $opts{package} || caller( $opts{caller_level} || 0 );
128              
129 14 100       55 if ( ref($function) eq 'ARRAY' ) {
130 2         5 $opts{package} = $package;
131 2         15 signature_for( $_, %opts ) for @$function;
132 2         7 return;
133             }
134              
135 12 50       74 my $fullname = ( $function =~ /::/ ) ? $function : "$package\::$function";
136 12   66     74 $opts{package} ||= $package;
137 12 50 33     86 $opts{subname} ||= ( $function =~ /::(\w+)$/ ) ? $1 : $function;
138 54 100 100 54   442 $opts{goto_next} ||= do { no strict 'refs'; exists(&$fullname) ? \&$fullname : undef; };
  54         144  
  54         11443  
  12         58  
  11         80  
139 12 100       50 if ( $opts{method} ) {
140 6   66     21 $opts{goto_next} ||= eval { $package->can( $opts{subname} ) };
  1         14  
141             }
142 12 100 100     116 if ( $opts{fallback} and not $opts{goto_next} ) {
143 1 50   0   5 $opts{goto_next} = ref( $opts{fallback} ) ? $opts{fallback} : sub {};
144             }
145 12 100       48 if ( not $opts{goto_next} ) {
146 1         7 require Error::TypeTiny;
147 1         7 return Error::TypeTiny::croak( "Function '$function' not found to wrap!" );
148             }
149              
150 11         3719 require Type::Params::Signature;
151 11         110 my $sig = 'Type::Params::Signature'->new_from_v2api( \%opts );
152             # Delay compilation
153 9         22 my $compiled;
154             my $coderef = sub {
155 9   33 9   2471 $compiled ||= $sig->coderef->compile;
        10      
156            
157 54     54   431 no strict 'refs';
  54         141  
  54         2042  
158 54     54   348 no warnings 'redefine';
  54         121  
  54         4616  
159 9         50 *$fullname = set_subname( $fullname, $compiled );
160            
161 9         195 goto( $compiled );
162 9         77 };
163              
164 54     54   400 no strict 'refs';
  54         137  
  54         1980  
165 54     54   334 no warnings 'redefine';
  54         133  
  54         51556  
166 9         75 *$fullname = set_subname( $fullname, $coderef );
167              
168 9         4521 return;
169             }
170              
171             sub compile {
172 83     83 1 38052 my @args = @_;
173 83         272 @_ = ( positional => \@args );
174 83         353 goto \&signature;
175             }
176              
177             sub compile_named {
178 85     85 1 89950 my @args = @_;
179 85         332 @_ = ( bless => 0, named => \@args );
180 85         408 goto \&signature;
181             }
182              
183             sub compile_named_oo {
184 20     20 1 17960 my @args = @_;
185 20         83 @_ = ( bless => 1, named => \@args );
186 20         102 goto \&signature;
187             }
188              
189             # Would be faster to inline this into validate and validate_named, but
190             # that would complicate them. :/
191             sub _mk_key {
192 933     933   1398 local $_;
193             join ':', map {
194 933         1653 Types::Standard::is_HashRef( $_ ) ? do {
195 488         1451 my %h = %$_;
196 488         1332 sprintf( '{%s}', _mk_key( map { ; $_ => $h{$_} } sort keys %h ) );
  610         1785  
197             } :
198 4623 50       100283 Types::TypeTiny::is_TypeTiny( $_ ) ? sprintf( 'TYPE=%s', $_->{uniq} ) :
    100          
    100          
    100          
199             Types::Standard::is_Ref( $_ ) ? sprintf( 'REF=%s', refaddr( $_ ) ) :
200             Types::Standard::is_Undef( $_ ) ? sprintf( 'UNDEF' ) :
201             B::perlstring( $_ )
202             } @_;
203             } #/ sub _mk_key
204              
205             {
206             my %compiled;
207             sub validate {
208 15     15 1 61 my $arg = shift;
209             my $sub = (
210             $compiled{ _mk_key( @_ ) } ||= signature(
211             caller_level => 1,
212 15 50 66     62 %{ ref( $_[0] ) eq 'HASH' ? shift( @_ ) : +{} },
  9         90  
213             positional => [ @_ ],
214             )
215             );
216 15         149 @_ = @$arg;
217 15         55 goto $sub;
218             } #/ sub validate
219             }
220              
221             {
222             my %compiled;
223             sub validate_named {
224 430     430 1 317151 my $arg = shift;
225             my $sub = (
226             $compiled{ _mk_key( @_ ) } ||= signature(
227             caller_level => 1,
228             bless => 0,
229 430 100 66     1105 %{ ref( $_[0] ) eq 'HASH' ? shift( @_ ) : +{} },
  28         267  
230             named => [ @_ ],
231             )
232             );
233 430         1762 @_ = @$arg;
234 430         1586 goto $sub;
235             } #/ sub validate_named
236             }
237              
238             sub multisig {
239 7 100   7 1 69 my %options = ( ref( $_[0] ) eq "HASH" ) ? %{ +shift } : ();
  3         15  
240 7         29 signature(
241             %options,
242             multi => \@_,
243             );
244             } #/ sub multisig
245              
246             sub wrap_methods {
247 2 50   2 1 18 my $opts = ref( $_[0] ) eq 'HASH' ? shift : {};
248 2   33     15 $opts->{caller} ||= caller;
249 2         4 $opts->{skip_invocant} = 1;
250 2         3 $opts->{use_can} = 1;
251 2         7 unshift @_, $opts;
252 2         7 goto \&_wrap_subs;
253             }
254              
255             sub wrap_subs {
256 1 50   1 1 5 my $opts = ref( $_[0] ) eq 'HASH' ? shift : {};
257 1   33     9 $opts->{caller} ||= caller;
258 1         4 $opts->{skip_invocant} = 0;
259 1         3 $opts->{use_can} = 0;
260 1         3 unshift @_, $opts;
261 1         4 goto \&_wrap_subs;
262             }
263              
264             sub _wrap_subs {
265 3     3   5 my $opts = shift;
266 3         11 while ( @_ ) {
267 8         26 my ( $name, $proto ) = splice @_, 0, 2;
268 8 50       50 my $fullname = ( $name =~ /::/ ) ? $name : sprintf( '%s::%s', $opts->{caller}, $name );
269 8         12 my $orig = do {
270 54     54   491 no strict 'refs';
  54         177  
  54         12691  
271             exists &$fullname ? \&$fullname
272       2     : $opts->{use_can} ? ( $opts->{caller}->can( $name ) || sub { } )
273       1     : sub { }
274 8 100 100     78 };
    100          
275 8         16 my $new;
276 8 100       19 if ( ref $proto eq 'CODE' ) {
277             $new = $opts->{skip_invocant}
278             ? sub {
279 4     4   19 my $s = shift;
280 4         11 @_ = ( $s, &$proto );
281 2         94 goto $orig;
282             }
283             : sub {
284 2     2   11 @_ = &$proto;
285 1         48 goto $orig;
286 2 100       23 };
287             }
288             else {
289             $new = compile(
290             {
291             'package' => $opts->{caller},
292             'subname' => $name,
293             'goto_next' => $orig,
294 6 100       39 'head' => $opts->{skip_invocant} ? 1 : 0,
295             },
296             @$proto,
297             );
298             }
299 54     54   458 no strict 'refs';
  54         147  
  54         1857  
300 54     54   335 no warnings 'redefine';
  54         128  
  54         6075  
301 8         83 *$fullname = set_subname( $fullname, $new );
302             } #/ while ( @_ )
303 3         12 1;
304             } #/ sub _wrap_subs
305              
306             1;
307              
308             __END__