File Coverage

blib/lib/Params/Named.pm
Criterion Covered Total %
statement 25 25 100.0
branch 10 10 100.0
condition 13 18 72.2
subroutine 6 6 100.0
pod 1 2 50.0
total 55 61 90.1


line stmt bran cond sub pod time code
1             package Params::Named;
2              
3             $VERSION = '1.0.2';
4              
5             require Exporter;
6             @ISA = 'Exporter';
7             @EXPORT = 'MAPARGS';
8              
9 3     3   62669 use strict;
  3         8  
  3         139  
10              
11 3     3   19 use Carp qw/croak carp/;
  3         6  
  3         248  
12 3     3   2792 use PadWalker 'var_name';
  3         12006  
  3         1644  
13              
14 2     2 0 375 sub VAR { return {qw/SCALAR $ ARRAY @ HASH % REF $/}->{ref $_[0]}.$_[1]; }
15              
16             sub _set_param {
17 14     14   27 my($p, $v, $n) = @_; # param, value, name
18 14 100 66     169 return $$p = $v
      100        
      100        
19             if ref $p eq 'SCALAR'
20             && (ref $v || ref \$v) eq 'SCALAR' || (ref $v eq 'REF');
21 3 100 66     25 return @$p = @$v
22             if ref $p eq 'ARRAY' && ref $v eq 'ARRAY';
23 2 100 66     17 return %$p = %$v
24             if ref $p eq 'HASH' && ref $v eq 'HASH';
25              
26 1   33     6 croak sprintf "The parameter '%s' doesn't match argument type '%s'",
27             VAR($p,$n), ( ref $v || ref \$v );
28             }
29              
30             ## Map named arguments to variables of those names.
31             sub MAPARGS {
32 7     7 1 4335 my %args = do { package DB; () = caller 1; @DB::args };
  7         52  
  7         39  
33             ## Map the lexicals of the caller to the caller's arguments.
34 15 100       35 my %vmap = map {
35 7         15 my $arg = ref $_ ? $_ : \$_;
36 15         49 my $prm = substr(var_name(1, $arg), 1);
37 15 100       68 exists $args{$prm}
38             ? ($prm => $arg)
39 1         5 : (() = carp "Parameter '${\VAR($arg,$prm)}' not mapped to an argument")
40             } @_;
41              
42             ## Now assign the caller's arguments to the caller's lexicals.
43             _set_param $vmap{$_} => $args{$_}, $_
44 7         459 for keys %vmap;
45              
46 6         22 return \%vmap;
47             }
48              
49             1;
50              
51             =pod
52              
53             =head1 NAME
54              
55             Params::Named - Map incoming arguments to parameters of the same name.
56              
57             =head1 SYNOPSIS
58              
59             use Params::Named;
60             use IO::All;
61              
62             sub storeurl {
63             my $self = shift;
64             MAPARGS \my($src, $dest);
65             return io($src) > io($dest);
66             }
67             $obj->storeurl(src => $url, dest => $fh);
68              
69             =head1 DESCRIPTION
70              
71             This module does just one thing - it maps named arguments to a subroutine's
72             lexical parameter variables or, more specifically, any lexical variables
73             passed into C. Named parameters are exactly the same as a flattened
74             hash in that they provide a list of C<< key => value >> pairs. So for each
75             key that matches a lexical variable passed to C the corresponding
76             value will be mapped to that variable. Here is a short example to demonstrate
77             C in action:
78              
79             use Params::Named;
80             sub mapittome {
81             MAPARGS \my($this, @that, %other);
82             print "This is: '$this'\n";
83             print "That is: ", join(', ', @that), "\n";
84             print "The other: ", join(', ',
85             map "$_ => $other{$_}", keys %other), "\n";
86             }
87              
88             mapittome this => 'a simple string',
89             that => [qw/a list of items/],
90             other => {qw/a hash containing pairs/};
91             ## Or if you've got a hash.
92             my %args = (
93             this => 'using a hash',
94             that => [qw/is very cool/],
95             other => {qw/is it not cool?/},
96             );
97             mapittome %args;
98              
99             The example above illustrates the mapping of C's arguments to
100             its parameters. It will work on scalars, arrays and hashes, the 3 types
101             of lexical values.
102              
103             =head1 FUNCTIONS
104              
105             =over 4
106              
107             =item MAPARGS
108              
109             Given a list of variables map those variables to named arguments from the
110             caller's argument. Taking advantage of one of Perl's more under-utilized
111             features, passing in a list of references as created by applying the
112             reference operator to a list will allow the mapping of compound variables
113             (without the reference lexically declared arrays and hashes flatten to an
114             empty list). Argument types must match their corresponding parameter types
115             e.g C<< foo => \@things >> should map to a parameter declared as an array
116             e.g C.
117              
118             The arguments passed to C don't need to be referenced if they are
119             simple scalars, but do need to be referenced if either an array or hash is
120             used.
121              
122             =back
123              
124             =head1 EXPORTS
125              
126             C
127              
128             =head1 DIAGNOSTICS
129              
130             =over 4
131              
132             =item C
133              
134             This warning is issued because a parameter couldn't be mapped to an argument
135             i.e if C<< foo1 => 'bar' >> is accidentally passed to subroutine who's
136             parameter is C<$fool>.
137              
138             =item C
139              
140             A given parameter doesn't match it's corresponding argument's type e.g
141              
142             sub it'llbreak { MAPARGS \my($foo, @bar); ... }
143             ## This will croak() because @bar's argument isn't an array reference.
144             it'llbreak foo => 'this', bar => 'that';
145              
146             So either the parameter or the argument needs to be updated to reflect
147             the desired behaviour.
148              
149             =back
150              
151             =head1 SEE. ALSO
152              
153             L, L, L
154              
155             =head1 THANKS
156              
157             Robin Houston for bug spotting, code refactoring, idea bouncing and releasing
158             a new version of L (is there anything he can't do?).
159            
160             =head1 AUTHOR
161              
162             Dan Brook C<< >>
163              
164             =head1 COPYRIGHT
165              
166             Copyright (c) 2005, Dan Brook. All Rights Reserved. This module is free
167             software. It may be used, redistributed and/or modified under the same
168             terms as Perl itself.
169              
170             =cut