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 57     57   234398 use 5.008001;
  57         262  
4 57     57   327 use strict;
  57         118  
  57         1251  
5 57     57   281 use warnings;
  57         118  
  57         2790  
6              
7             BEGIN {
8 57     57   194 $Type::Params::AUTHORITY = 'cpan:TOBYINK';
9 57         2253 $Type::Params::VERSION = '2.004000';
10             }
11              
12             $Type::Params::VERSION =~ tr/_//d;
13              
14 57     57   385 use B qw();
  57         130  
  57         1419  
15 57     57   12947 use Eval::TypeTiny qw( eval_closure set_subname );
  57         141  
  57         445  
16 57     57   28788 use Scalar::Util qw( refaddr );
  57         132  
  57         3146  
17 57     57   10608 use Error::TypeTiny;
  57         148  
  57         1645  
18 57     57   14631 use Error::TypeTiny::Assertion;
  57         152  
  57         1510  
19 57     57   21640 use Error::TypeTiny::WrongNumberOfParameters;
  57         166  
  57         1626  
20 57     57   14817 use Types::Standard ();
  57         214  
  57         1450  
21 57     57   317 use Types::TypeTiny ();
  57         109  
  57         43405  
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 878 $Invocant ||= do {
54 1         572 require Type::Tiny::Union;
55 1         9 '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 1136 $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       31 sub { defined( $_->{'~~caller'} ) and $_->{'~~caller'} eq $param };
  0         0  
76             },
77             inline_generator => sub {
78 3     3   7 my $param = shift;
79 3         11 my $quoted = B::perlstring( $param );
80             sub {
81 3         8 my $var = pop;
82             return (
83 3         29 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         13 );
96             };
97            
98 5 50       31 @_ ? $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 11918 if ( @_ % 2 ) {
107 1         7 require Error::TypeTiny;
108 1         6 Error::TypeTiny::croak( "Expected even-sized list of arguments" );
109             }
110 256         953 my ( %opts ) = @_;
111              
112 256   66     3486 my $for = [ caller( 1 + ( $opts{caller_level} || 0 ) ) ]->[3] || ( ( $opts{package} || '__ANON__' ) . '::__ANON__' );
113 256         2324 my ( $pkg, $sub ) = ( $for =~ /^(.+)::(\w+)$/ );
114 256   66     1547 $opts{package} ||= $pkg;
115 256   66     1301 $opts{subname} ||= $sub;
116              
117 256         24113 require Type::Params::Signature;
118 256         1779 'Type::Params::Signature'->new_from_v2api( \%opts )->return_wanted;
119             }
120              
121             sub signature_for {
122 16 100   16 1 4698 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 15         69 my ( $function, %opts ) = @_;
127 15   66     129 my $package = $opts{package} || caller( $opts{caller_level} || 0 );
128              
129 15 100       70 if ( ref($function) eq 'ARRAY' ) {
130 2         5 $opts{package} = $package;
131 2         15 signature_for( $_, %opts ) for @$function;
132 2         9 return;
133             }
134              
135 13 50       87 my $fullname = ( $function =~ /::/ ) ? $function : "$package\::$function";
136 13   66     162 $opts{package} ||= $package;
137 13 50 33     100 $opts{subname} ||= ( $function =~ /::(\w+)$/ ) ? $1 : $function;
138 57 100 100 57   473 $opts{goto_next} ||= do { no strict 'refs'; exists(&$fullname) ? \&$fullname : undef; };
  57         139  
  57         11183  
  13         55  
  12         90  
139 13 100       52 if ( $opts{method} ) {
140 7   66     23 $opts{goto_next} ||= eval { $package->can( $opts{subname} ) };
  1         12  
141             }
142 13 100 100     62 if ( $opts{fallback} and not $opts{goto_next} ) {
143 1 50   0   5 $opts{goto_next} = ref( $opts{fallback} ) ? $opts{fallback} : sub {};
144             }
145 13 100       59 if ( not $opts{goto_next} ) {
146 1         8 require Error::TypeTiny;
147 1         7 return Error::TypeTiny::croak( "Function '$function' not found to wrap!" );
148             }
149              
150 12         4025 require Type::Params::Signature;
151 12         115 my $sig = 'Type::Params::Signature'->new_from_v2api( \%opts );
152             # Delay compilation
153 10         30 my $compiled;
154             my $coderef = sub {
155 10   33 10   3057 $compiled ||= $sig->coderef->compile;
        11      
156            
157 57     57   445 no strict 'refs';
  57         136  
  57         2063  
158 57     57   338 no warnings 'redefine';
  57         122  
  57         5993  
159 10         58 *$fullname = set_subname( $fullname, $compiled );
160            
161 10         198 goto( $compiled );
162 10         77 };
163              
164 57     57   401 no strict 'refs';
  57         126  
  57         1822  
165 57     57   339 no warnings 'redefine';
  57         171  
  57         49815  
166 10         69 *$fullname = set_subname( $fullname, $coderef );
167              
168 10         6956 return;
169             }
170              
171             sub compile {
172 83     83 1 39930 my @args = @_;
173 83         292 @_ = ( positional => \@args );
174 83         379 goto \&signature;
175             }
176              
177             sub compile_named {
178 85     85 1 88914 my @args = @_;
179 85         346 @_ = ( bless => 0, named => \@args );
180 85         442 goto \&signature;
181             }
182              
183             sub compile_named_oo {
184 20     20 1 20763 my @args = @_;
185 20         76 @_ = ( bless => 1, named => \@args );
186 20         97 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   1421 local $_;
193             join ':', map {
194 933         1759 Types::Standard::is_HashRef( $_ ) ? do {
195 488         1442 my %h = %$_;
196 488         1429 sprintf( '{%s}', _mk_key( map { ; $_ => $h{$_} } sort keys %h ) );
  610         1837  
197             } :
198 4623 50       99174 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 67 my $arg = shift;
209             my $sub = (
210             $compiled{ _mk_key( @_ ) } ||= signature(
211             caller_level => 1,
212 15 50 66     47 %{ ref( $_[0] ) eq 'HASH' ? shift( @_ ) : +{} },
  9         78  
213             positional => [ @_ ],
214             )
215             );
216 15         159 @_ = @$arg;
217 15         60 goto $sub;
218             } #/ sub validate
219             }
220              
221             {
222             my %compiled;
223             sub validate_named {
224 430     430 1 323827 my $arg = shift;
225             my $sub = (
226             $compiled{ _mk_key( @_ ) } ||= signature(
227             caller_level => 1,
228             bless => 0,
229 430 100 66     1213 %{ ref( $_[0] ) eq 'HASH' ? shift( @_ ) : +{} },
  28         236  
230             named => [ @_ ],
231             )
232             );
233 430         1721 @_ = @$arg;
234 430         1533 goto $sub;
235             } #/ sub validate_named
236             }
237              
238             sub multisig {
239 7 100   7 1 65 my %options = ( ref( $_[0] ) eq "HASH" ) ? %{ +shift } : ();
  3         15  
240 7         31 signature(
241             %options,
242             multi => \@_,
243             );
244             } #/ sub multisig
245              
246             sub wrap_methods {
247 2 50   2 1 20 my $opts = ref( $_[0] ) eq 'HASH' ? shift : {};
248 2   33     18 $opts->{caller} ||= caller;
249 2         4 $opts->{skip_invocant} = 1;
250 2         5 $opts->{use_can} = 1;
251 2         9 unshift @_, $opts;
252 2         7 goto \&_wrap_subs;
253             }
254              
255             sub wrap_subs {
256 1 50   1 1 6 my $opts = ref( $_[0] ) eq 'HASH' ? shift : {};
257 1   33     9 $opts->{caller} ||= caller;
258 1         3 $opts->{skip_invocant} = 0;
259 1         2 $opts->{use_can} = 0;
260 1         4 unshift @_, $opts;
261 1         5 goto \&_wrap_subs;
262             }
263              
264             sub _wrap_subs {
265 3     3   7 my $opts = shift;
266 3         10 while ( @_ ) {
267 8         26 my ( $name, $proto ) = splice @_, 0, 2;
268 8 50       48 my $fullname = ( $name =~ /::/ ) ? $name : sprintf( '%s::%s', $opts->{caller}, $name );
269 8         14 my $orig = do {
270 57     57   531 no strict 'refs';
  57         173  
  57         11837  
271             exists &$fullname ? \&$fullname
272       2     : $opts->{use_can} ? ( $opts->{caller}->can( $name ) || sub { } )
273       1     : sub { }
274 8 100 100     85 };
    100          
275 8         12 my $new;
276 8 100       23 if ( ref $proto eq 'CODE' ) {
277             $new = $opts->{skip_invocant}
278             ? sub {
279 4     4   19 my $s = shift;
280 4         13 @_ = ( $s, &$proto );
281 2         98 goto $orig;
282             }
283             : sub {
284 2     2   19 @_ = &$proto;
285 1         60 goto $orig;
286 2 100       39 };
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 57     57   459 no strict 'refs';
  57         152  
  57         1879  
300 57     57   365 no warnings 'redefine';
  57         126  
  57         6172  
301 8         89 *$fullname = set_subname( $fullname, $new );
302             } #/ while ( @_ )
303 3         13 1;
304             } #/ sub _wrap_subs
305              
306             1;
307              
308             __END__