File Coverage

blib/lib/Sub/Parameters.pm
Criterion Covered Total %
statement 56 71 78.8
branch 6 26 23.0
condition 4 16 25.0
subroutine 15 16 93.7
pod 0 3 0.0
total 81 132 61.3


line stmt bran cond sub pod time code
1             package Sub::Parameters;
2 2     2   53670 use strict;
  2         5  
  2         121  
3 2     2   10 use warnings;
  2         3  
  2         59  
4 2     2   4839 use Hook::LexWrap;
  2         11372  
  2         13  
5 2     2   2128 use Devel::Caller qw(caller_cv called_with);
  2         9574  
  2         178  
6 2     2   2936 use Devel::LexAlias qw(lexalias);
  2         3557  
  2         154  
7 2     2   16 use Carp qw(croak);
  2         3  
  2         93  
8 2     2   13134 use Attribute::Handlers;
  2         17524  
  2         217  
9              
10             require Exporter;
11 2     2   495 use base 'Exporter';
  2         5  
  2         573  
12             our @EXPORT_OK = qw( Param );
13             our $VERSION = '0.03';
14              
15             my @stack;
16              
17             sub UNIVERSAL::WantParam : ATTR(CODE) {
18 12     12 0 16285 my ($symbol, $sub, $data) = @_[1, 2, 4];
19              
20 12   100     45 $data ||= 'positional';
21             wrap $symbol,
22             pre => sub {
23 2     2   137 my %order;
24 2 50       14 if ($data eq 'named') {
25             # prechew the ordering information
26 0         0 for (my $i = 0; $i < $#_; $i += 2) {
27 0         0 $order{ $_[$i] } = $i + 1;
28             }
29             }
30 2         20 push @stack, { data => $data,
31             sub => $sub,
32             order => \%order,
33             args => \@_ };
34             },
35 12     0   91 post => sub { pop @stack };
  0         0  
36 2     2   12 }
  2         4  
  2         9  
37              
38              
39             # you know, this would be a lot tidier if we could use ourselves
40             # already...
41              
42             sub Param {
43 1     1 0 11 local $Carp::CarpLevel = 3;
44 1         6 _Parameter(caller_cv(1), called_with(0), called_with(0,1), $_[0]);
45             }
46              
47             sub UNIVERSAL::Parameter : ATTR(VAR) {
48             # 4 is a magic number dependant on Attribute::Handlers
49 1     1 0 1711 local $Carp::CarpLevel = 4;
50 1 50       5 croak "your perl is not new enough to use the :Parameter form"
51             if $] < 5.007002;
52              
53 1         6 my $sub = caller_cv($Carp::CarpLevel);
54 1         12 my $referent = $_[2];
55              
56 1         9 require PadWalker;
57 1         2 my %names = reverse %{ PadWalker::peek_sub( $sub ) };
  1         11  
58 1 50       6 my $fullname = $names{$referent}
59             or croak "couldn't find the name of $referent";
60              
61 1         1 ++$Carp::CarpLevel;
62 1         5 _Parameter($sub, $referent, $fullname, $_[4]);
63 2     2   1963 }
  2         5  
  2         11  
64              
65             sub _Parameter {
66 2     2   316 my ($sub, $referent, $fullname, $data) = @_;
67 2   50     23 $data ||= 'copy'; # valid values: qw(copy rw)
68              
69 2         4 my $frame = $stack[-1];
70 2 50 33     18 croak "attempt to use a Parameter in an undecorated subroutine"
71             unless $frame->{sub} && $sub == $frame->{sub};
72              
73 2         13 my ($sigil, $name) = ($fullname =~ /^([\$@%])(.*)$/);
74              
75             # set the offset based on the scheme
76 2         4 my $offset;
77 2 50       15 if ($frame->{data} eq 'positional') {
    50          
78 0         0 $offset = $frame->{index}++;
79             }
80             elsif ($frame->{data} eq 'named') {
81 0 0       0 $offset = $frame->{order}{$name}
82             or croak "can't find a parameter for '$sigil$name'";
83             }
84             else {
85 2         56 croak "don't know what kind of processing to do!";
86             }
87              
88 0 0 0       if ( $sigil eq '@' || $sigil eq '%' ) { # expect refs
89 0           my $value = $frame->{args}[ $offset ];
90 0 0 0       ref $value eq 'ARRAY' || croak "can't assign non-arrayref to '$sigil$name'"
91             if $sigil eq '@';
92 0 0 0       ref $value eq 'HASH' || croak "can't assign non-hashref to '$sigil$name'"
93             if $sigil eq '%';
94              
95 0 0         $value = (ref $value eq 'ARRAY' ? [ @$value ] : { %$value })
    0          
96             if $data ne 'rw';
97              
98 0           lexalias($sub, $sigil.$name, $value);
99 0           return;
100             }
101              
102             # simple scalars
103 0 0         if ($data eq 'rw') {
104 0           lexalias($sub, $sigil.$name, \$frame->{args}[ $offset ]);
105             }
106             else {
107 0           $$referent = $frame->{args}[ $offset ];
108             }
109             }
110              
111             1;
112             __END__