File Coverage

blib/lib/Acme/Signature/Arity.pm
Criterion Covered Total %
statement 35 35 100.0
branch 6 8 75.0
condition 2 3 66.6
subroutine 8 8 100.0
pod 3 3 100.0
total 54 57 94.7


line stmt bran cond sub pod time code
1             package Acme::Signature::Arity;
2             # ABSTRACT: find out how a piece of code expects to be called
3              
4 1     1   72862 use strict;
  1         10  
  1         29  
5 1     1   6 use warnings;
  1         2  
  1         53  
6              
7             our $VERSION = '0.001';
8             our $AUTHORITY;
9              
10 1     1   6 use B;
  1         2  
  1         40  
11 1     1   5 use experimental qw(signatures);
  1         2  
  1         5  
12              
13 1     1   560 use parent qw(Exporter);
  1         289  
  1         5  
14              
15             =head1 NAME
16              
17             Acme::Signature::Arity - provides reliable, production-ready signature introspection
18              
19             =head1 DESCRIPTION
20              
21             You'll know if you need this.
22              
23             If you're just curious, perhaps start with L.
24              
25             No part of this is expected to work in any way when given a sub that has a prototype.
26             There are other tools for those: L.
27              
28             For subs that don't have a prototype, this is I not expected to work. It might help
29             demonstrate where to look if you wanted to write something proper, though.
30              
31             =cut
32              
33             our @EXPORT_OK = qw(arity min_arity max_arity);
34             our @EXPORT = @EXPORT_OK;
35              
36             =head1 Exported functions
37              
38             =head2 arity
39              
40             Returns the C details for the first opcode for a coderef CV.
41             If that code uses signatures, this might give you some internal details
42             which mean something about the expected parameters.
43              
44             Expected return information, as a list:
45              
46             =over 4
47              
48             =item * number of required scalar parameters
49              
50             =item * number of optional scalar parameters (probably because there are defaults)
51              
52             =item * a character representing the slurping behaviour, might be '@' or '%', or nothing (undef?) if it's
53             just a fixed list of scalar parameters
54              
55             =back
56              
57             This can also throw exceptions. That should only happen if you give it something that isn't
58             a coderef, or if internals change enough that the entirely-unjustified assumptions made by
59             this module are somehow no longer valid. Maybe they never were in the first place.
60              
61             =cut
62              
63 16     16 1 24 sub arity ($code) {
  16         21  
  16         20  
64 16 50       48 die 'only works on coderefs' unless ref($code) eq 'CODE';
65 16         56 my $cv = B::svref_2object($code);
66 16 50       65 die 'probably not a coderef' unless $cv->isa('B::CV');
67 16         84 my $next = $cv->START->next;
68             # we pretend sub { } is sub (@) { }, for convenience
69 16 100 66     105 return (0, 0, '@') unless $next and $next->isa('B::UNOP_AUX');
70 14         76 return $next->aux_list($cv);
71             }
72              
73             =head2 max_arity
74              
75             Takes a coderef, returns a number or C.
76              
77             If the code uses signatures, this tells you how many parameters you could
78             pass when calling before it complains - C means unlimited.
79              
80             Should also work when there are no signatures, just gives C again.
81              
82             =cut
83              
84 8     8 1 4824 sub max_arity ($code) {
  8         17  
  8         18  
85 8         19 my ($minimum, $optional, $slurp) = arity($code);
86 8 100       25 return undef if $slurp;
87 3         9 return $minimum
88             }
89              
90             =head2 min_arity
91              
92             Takes a coderef, returns a number or C.
93              
94             If the code uses signatures, this tells you how many parameters you need to
95             pass when calling - 0 means that no parameters are required.
96              
97             Should also work when there are no signatures, returning 0 in that case.
98              
99             =cut
100              
101 8     8 1 20766 sub min_arity ($code) {
  8         16  
  8         13  
102 8         17 my ($minimum, $optional, $slurp) = arity($code);
103 8         24 return $minimum - $optional;
104             }
105              
106             1;
107              
108             __END__