File Coverage

blib/lib/Perl6/Parameters.pm
Criterion Covered Total %
statement 81 158 51.2
branch 25 42 59.5
condition n/a
subroutine 9 9 100.0
pod 0 4 0.0
total 115 213 53.9


line stmt bran cond sub pod time code
1             package Perl6::Parameters;
2            
3 1     1   1686 use 5.006;
  1         4  
  1         50  
4 1     1   6 use strict;
  1         1  
  1         40  
5 1     1   6 use warnings;
  1         6  
  1         38  
6 1     1   5939 use Switch 'Perl6'; #given/when
  1         82598  
  1         8  
7            
8             our $VERSION = '0.03';
9            
10 1     1   117540 use Filter::Simple;
  1         3456  
  1         9  
11            
12             sub separate($);
13             sub makeproto(\@\@);
14             sub makepopstate(\@\@);
15            
16             FILTER_ONLY code => sub {
17             while(/(sub\s+([\w:]+)\s*\(([^)]*\w.*?)\)\s*\{)/) {
18             my($oldsubstate, $subname, $paramlist)=($1, $2, $3);
19             my($substate);
20            
21             die "'is rw' is not implemented but is used in subroutine $subname" if($oldsubstate =~ /is rw/);
22            
23             #build the new sub statement
24             do {
25             my($popstate, $proto);
26            
27             do {
28             #separate the parameter list into 3 arrays
29             my(@ret)=separate($paramlist);
30             my(@seps)=@{$ret[0]}; my(@params)=@{$ret[1]}; my(@names)=@{$ret[2]};
31            
32             #form the line-noise prototype
33             ($proto, my(@symbols))=makeproto(@params, @seps);
34            
35             #form the population statements
36             $popstate=makepopstate(@names, @symbols);
37             };
38            
39             #now assemble the new sub statement
40             $substate="sub $subname ($proto) {\n\t$popstate"; warn "subname" unless defined $subname; warn "proto" unless defined $proto; warn "popstate" unless defined $popstate;
41             };
42             #$substate: DONE--contains the new sub statement
43            
44             #replace the old sub statement with the new one
45             do {
46             s/\Q$oldsubstate/$substate/;
47             };
48             }
49            
50             if(@_) {
51             print STDERR $_ if($_[0] eq '-debug');
52             }
53             };
54            
55             sub separate($) {
56 5     5 0 12 my($paramlist, @seps, @names, @params)=shift;
57 5         7 my(@things);
58            
59             #split the param list on separators--but keep the separators around
60 5         23 @things=split /([,;])/, $paramlist;
61            
62             #separate the things into separators and parameters
63 5         13 for(0..$#things) {
64 9 100       23 if($_ % 2) {
65 2         5 push @seps, $things[$_];
66             }
67             else {
68 7         18 push @params, $things[$_];
69             }
70             }
71            
72             #form the names array
73 5         36 push @names, (/([\$\@\%]\w+)$/)[0] for @params;
74            
75 5         28 return \@seps, \@params, \@names;
76             }
77            
78             sub makeproto(\@\@) {
79 5     5 0 6 my($params, $seps)=@_;
80 5         7 my(@symbols, $proto);
81            
82             #first, we convert each parameter to the appropriate symbol
83 5         11 for(@$params) {
84 7         13 push @symbols, tosymbol($_);
85             }
86            
87             #then we get rid of commas since they don't appear in line-noise prototypes
88 5 50       12 @$seps=map {$_ eq ',' ? "" : $_} @$seps;
  2         12  
89 5         10 push @$seps, ''; #avoid warning
90            
91             #build the line-noise prototype
92 5         30 $proto.="$symbols[$_]$seps->[$_]" for(0..$#symbols);
93            
94 5         73 return $proto, @symbols;
95             }
96            
97             sub makepopstate(\@\@) {
98 5     5 0 5 my(@names)=@{shift()};
  5         15  
99 5         6 my(@symbols)=@{shift()};
  5         12  
100 5         6 my($popstate);
101            
102 5         11 for(0..$#names) {
103 7         9 given($symbols[$_]) {
  7         8  
  7         19  
  4         9  
104 7 100       94 when '\@' {
  2         27  
105 2 100       8 if($names[$_] =~ /\@/) {
106             #literal array--use it
107 1         4 $popstate .= "my($names[$_])=\@{shift()};\n";
108             }
109             else {
110             #array ref--just like a normal one
111 1         4 $popstate .= "my($names[$_])=shift;\n";
112             }
113 2         14 }
  0         0  
  0         0  
  0         0  
114            
115 5 50       66 when '\%' {
  0         0  
116 0 0       0 if($names[$_] =~ m'%') {
117             #literal hash--use it
118 0         0 $popstate .= "my($names[$_])=\%{shift()};\n";
119             }
120             else {
121             #hash ref--just like a normal one
122 0         0 $popstate .= "my($names[$_])=shift;\n";
123             }
124 0         0 }
  0         0  
  0         0  
  0         0  
125            
126 5 100       60 when '@' {
  1         12  
127 1 50       5 if($names[$_] ne '@_') {
128 1         3 $popstate .= "my($names[$_])=(\@_);\n";
129             }
130 1         7 }
  0         0  
  0         0  
  0         0  
131            
132 4 50       48 when '%' {
  0         0  
133 0 0       0 if($names[$_] eq '%_') {
134 0         0 $popstate .= '(%_)=(@_);'
135             }
136             else {
137 0         0 $popstate .= "my($names[$_])=(\@_);\n"
138             }
139 0         0 }
  0         0  
  0         0  
  0         0  
140            
141 4         62 $popstate .= "my($names[$_])=shift;\n";
142             }
143             }
144            
145 5         26 return $popstate;
146             }
147            
148            
149            
150             sub tosymbol {
151 7     7 0 10 my $term=shift;
152 7         32 $term =~ s/^\s+|\s+$//g; #strip whitespace
153            
154 7         12 given($term) {
  7         9  
  7         19  
  0            
155 7 0       124 when /^REF/ { return $^V gt 5.8.0 ? '\\[$@%]' : '$' }
  0 50       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
156 7 50       169 when /^GLOB/ { return '\*' }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
157 7 50       137 when /^CODE/ { return '&' }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
158 7 50       133 when /^HASH/ { return '\%' }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
159 7 100       134 when /^ARRAY/ { return '\@' }
  1         39  
  1         10  
  0         0  
  0         0  
  0         0  
  0         0  
160 6 50       121 when /^SCALAR/ { return '\$' }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
161 6 100       132 when /^\*\@/ { return '@' }
  1         17  
  1         9  
  0         0  
  0         0  
  0         0  
  0         0  
162 5 50       94 when /^\*\%/ { return '%' }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
163 5 100       91 when /^\@/ { return '\@' }
  1         17  
  1         8  
  0         0  
  0         0  
  0         0  
  0         0  
164 4 50       77 when /^\%/ { return '\%' }
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
165 4         65 { return '$' }
  4         30  
166             }
167             }
168            
169             1;
170            
171             =head1 NAME
172            
173             Perl6::Parameters – Perl 6-style prototypes with named parameters
174            
175             =head1 SYNOPSIS
176            
177             use Perl6::Parameters;
178            
179             sub mysub($foo, ARRAY $bar, *%rest) {
180             ...
181             }
182            
183             =head1 DETAILS
184            
185             Perl6::Parameters is a Perl module which simulates Perl 6's named parameters. (When I
186             talk about "named parameters" I mean something like the parameters you're used to from
187             C, Java and many other languages--not pass-a-hash-with-the-parameters-in-it things.)
188            
189             Like most other programming languages, Perl 6 will support subroutines with
190             pre-declared variables the parameters are put into. (Using this will be optional,
191             however.) This goes far beyond the "line-noise prototypes" available in Perl 5, which
192             only allow you to control context and automatically take references to some
193             parameters--lines like C will no longer be necessary.
194            
195             Although Perl 6 will have this, Perl 5 doesn't; this module makes it so that Perl 5
196             does. It uses some other Perl 6-isms too, notably the names for builtin types and the
197             unary-asterisk notation for flattening a list.
198            
199             =head2 Crafting Parameter Lists
200            
201             Crafting parameter lists is simple; just declare your subroutine and put the parameters
202             separated by commas or semicolons, in parenthesis. (Using a semicolon signifies that
203             all remaining parameters are optional; this may not be available this way in Perl 6,
204             but I'm assuming it is until I hear otherwise.)
205            
206             Most parameters are just variable names like C<$foo>; however, more sophisticated
207             behavior is possible. There are three ways to achieve this.
208            
209             The first way is by specifying a type for the variable. Certain types make the actual
210             parameters turn into references to themselves:
211            
212             =over 4
213            
214             =item *
215             C
216            
217             This turns an array into a reference to itself and stores the reference into C<$foo>.
218            
219             =item *
220             C
221            
222             This turns a hash into a reference to itself and stores the reference into C<$foo>.
223            
224             =item *
225             C
226            
227             This turns a subroutine into a reference to itself and stores the reference into
228             C<$foo>.
229            
230             =item *
231             C
232            
233             This turns a scalar into a reference to itself and stores the reference into C<$foo>.
234            
235             =item *
236             C
237            
238             This turns a typeglob into a reference to itself and stores the reference into C<$foo>. Typeglobs will be going away in Perl 6;
239             this type exists in this module so that it's useful for general use in Perl 5.
240            
241             =item *
242             C
243            
244             This turns any parameter into a reference to itself and stores it into C<$foo>.
245            
246             This only works in Perl 5.8. Otherwise, it's treated the same as any other
247             unrecognized type name.
248            
249             =item *
250             C
251            
252             This has no effect in this module; it's treated as though you'd typed C<$foo> without
253             the C.
254            
255             =back
256            
257             For example, if a subroutine had the parameters C<($foo, HASH $bar, CODE $baz)> and was
258             called with C<($scalar, %hash, &mysub)> the subroutine would get the contents of
259             C<$scalar>, a reference to C<%hash> and a reference to C<&mysub>.
260            
261             The second way is by supplying an actual array or hash as a parameter name. This
262             requires an array or hash to be passed in for that parameter; it preserves the length
263             of the array or hash.
264            
265             The final way is only available for the last parameter: if an array or hash is prefixed
266             with an asterisk, that array or hash will be filled with any additional parameters.
267            
268             =head1 CAVEATS
269            
270             =over 4
271            
272             =item *
273            
274             In Perl 6, parameters will be passed by constant reference; in this module parameters
275             are passed by value.
276            
277             =item *
278            
279             In Perl 6, putting an C at the end of a parameter will make it read-write;
280             trying to use C with this module will cause an error.
281            
282             =item *
283            
284             C<@_> and C<%_> may only be used for the last parameter, and then only when prefixed by
285             an asterisk; any other use causes undefined behavior.
286            
287             =item *
288            
289             In Perl 6 a definition like C will take either a literal hash (with a C<%>
290             sign in front of it) or a reference to a hash; this module requires a C<%> sign.
291             (Similar limitations apply for arrays.)
292            
293             =back
294            
295             =head1 BUGS
296            
297             None known--but if you find any, send them to and
298             CC .
299            
300             =head1 AUTHOR
301            
302             Brent Dax
303            
304             =head1 COPYRIGHT
305            
306             Copyright (C) 2001 Brent Dax.
307            
308             This module is free software and may be used, redistributed and modified under the same
309             terms as Perl itself.
310            
311             =cut