File Coverage

blib/lib/here/declare.pm
Criterion Covered Total %
statement 71 74 95.9
branch 24 38 63.1
condition 12 20 60.0
subroutine 13 13 100.0
pod 0 1 0.0
total 120 146 82.1


line stmt bran cond sub pod time code
1             package here::declare;
2 2     2   51603 use warnings;
  2         7  
  2         78  
3 2     2   10 use strict;
  2         4  
  2         74  
4 2     2   1996 use lib '..';
  2         1787  
  2         12  
5 2     2   1468 use here::install;
  2         7  
  2         13  
6 2     2   2673 BEGIN {*croak = *here::croak}
7            
8             our ($name, $value, $glob);
9            
10             sub process_pairs {
11 4     4 0 13 my %args = @_;
12 4   50     25 exists $args{$_} or croak "needs $_" for qw(validate transform);
13             sub (&@) {
14 10   33 10   46 my $to_source = $args{to_source} || shift;
        10      
15             my $run = sub {
16 15 100   15   41 if (@_ == 1) {
17 2 50       17 (local $value = $_[0])
18             =~ s/^ \s* (\(? [^)=]+ \)?) \s* = \s* (?=\S)//x
19             or croak 'argument must look like: ... = ...';
20 2         3 local $name = $1;
21 2         4 local $glob = my $error = 'here::declare::error::flag';
22 2 50       4 (my $perl = $to_source->())
23             =~ /$error/ and croak 'not supported with the single argument syntax';
24 2         8 return $perl
25             }
26 13 100       54 if ($_[0] =~ /^\s* \( ([^)=]+) \) \s*$/x) {
27 2         5 my $names = $1;
28 2 50       12 my $re = $names =~ /,/ ? qr/,/ : qr/\s+/;
29 2         10 splice @_, 0, 1, [grep {s/^\s+|\s+$//; 1} split $re => $names]
  6         16  
  6         15  
30             }
31 13 100 66     60 if (ref $_[0] eq 'ARRAY' and @_ > 2 || ref $_[1] ne 'ARRAY') {
      66        
32 3         13 @_ = ($_[0], [@_[1 .. $#_]])
33             }
34 13 100 100     71 if (@_ == 2 and ref $_[0] eq 'ARRAY'
      66        
35             and ref $_[1] eq 'ARRAY') {
36 22         68 @_ = map {
37 6         13 $_[0][$_] => $_[1][$_]
38 6         9 } 0 .. $#{$_[0]}
39             }
40 13 50       37 @_ % 2 and croak 'even length list expected';
41 34         143 map {
42 13         62 (local $name = $_[$_]) =~ s/^-?(\w)/\$$1/;
43 34         161 local ($value, $glob) = ($_[$_+1], substr $name, 1);
44 34         74 $args{validate}->();
45 34         65 $value = $args{transform}->();
46 34         549 $to_source->()
47             } map 2*$_ => 0 .. $#_/2
48 10         45 };
49 10 50       50 @_ ? &$run : $run
50             }
51 4         1050 }
52            
53             BEGIN {
54             my %valid = (
55 23         59 '$' => sub {},
56 3 50       11 '@' => sub {ref $value eq 'ARRAY' ? () : "an ARRAY ref"},
57 3 50       11 '%' => sub {ref $value eq 'HASH' ? () : "a HASH ref"},
58 2     2   28 );
59             *lexical = process_pairs
60             validate => sub {
61 29         54 $name =~ /^(.)/;
62             croak "$name must be set with $_"
63 29   33     94 for ($valid{$1} or croak "type not supported: $name")->()
64             },
65             transform => sub {
66 29         65 my $code = here::store($value);
67 29 100       104 $name =~ /^([\@\%])/ ? $1."{$code}" : $code
68 2         20 };
69            
70             *const = process_pairs
71             validate => sub {
72 5 50       22 $name =~ /^\$/ or croak "const sets scalar variables";
73 5 50       125 ref $value and croak "const values can be numbers or strings, not references";
74             },
75             transform => sub {
76 5         1963 require Data::Dumper;
77 5         15094 Data::Dumper->new([$value])->Terse(1)->Indent(0)->Dump
78 2         11 };
79             }
80            
81             my %can = (
82             const => const {"our $name; BEGIN {*$glob = \\$value}"},
83             const2 => const {"sub $glob () {$value} our $name; BEGIN {*$glob = \\$glob}"},
84             );
85             for my $type (qw(my our state)) {
86             $can{$type} = lexical {"$type $name; BEGIN {$name = $value}"}
87             }
88            
89             my %done;
90             sub import {
91 3     3   4133 shift;
92 3 50       22 for (@_ ? @_ : keys %can) {
93 15 50       46 $can{lc $_} or map {croak "pragma keys: $_; subroutine keys: \U$_"}
  0         0  
94             join ', ' => sort keys %can;
95 15 50       40 if (/[A-Z]/) {
96 2     2   21 no strict 'refs';
  2         5  
  2         614  
97 0         0 *{(caller).'::'.$_} = $can{lc $_};
  0         0  
98             }
99             else {
100 15 50       45 $done{$_}++ and next;
101 15         48 here::install::->import($_ => $can{$_})
102             }
103             }
104             }
105            
106             sub unimport {
107 1     1   7 shift;
108 1 50       7 for (@_ ? @_ : keys %done) {
109 5         7 delete $done{$_};
110 5         14 here::install::->unimport($_)
111             }
112             }
113            
114             our $VERSION = '0.03';
115            
116            
117             =head1 NAME
118            
119             here::declare - easily declare compile time variables
120            
121             =head1 VERSION
122            
123             version 0.03
124            
125             =head1 SYNOPSIS
126            
127             use here::declare;
128            
129             use const qw($ONE 1 $TWO 2);
130            
131             use my [qw(x y z)] => [$ONE + $TWO, 4, 5];
132            
133             use our '@foo' => [$x, $y, $z];
134            
135             is equivalent to:
136            
137             our ($ONE, $TWO);
138             BEGIN {
139             *ONE = \'1';
140             *TWO = \'2';
141             }
142            
143             my ($x, $y, $z);
144             BEGIN {
145             ($x, $y, $z) = ($ONE + $TWO, 4, 5);
146             }
147            
148             our @foo;
149             BEGIN {
150             @foo = ($x, $y, $z);
151             }
152            
153             without all that tedious typing.
154            
155             =head1 USE STATEMENTS
156            
157             all aspects of C< here::declare > must normally be imported using C< use ...; >
158             statements.
159            
160             without arguments, an initial C< use here::declare; > line creates all five
161             pseudo-modules (C< my our state const const2 >). if you only want some, pass a
162             list of those.
163            
164             in the following examples, the C< use my > declaration will be used. its usage
165             is equivalent to C< use our > and C< use state >.
166            
167             =head2 a single argument with C< = >
168            
169             =over 4
170            
171             use my '$x = 1';
172             use my '($y, $z) = (2, 3)';
173            
174             this is the simplest transform, which given an argument matching C< foo = bar >
175             gets rewritten as:
176            
177             my foo; BEGIN {foo = bar}
178            
179             so the above becomes:
180            
181             my $x; BEGIN {$x = 1}
182             my ($y, $z); BEGIN {($y, $z) = (2, 3)}
183            
184             while this version looks the closest to perl's native variable declarations, it
185             is unable to pass arguments that can not easily be written in a string.
186            
187             =back
188            
189             =head2 list of name/value pairs
190            
191             =over 4
192            
193             use my '$say' => sub {print @_, $/};
194            
195             use my '@array' => [1, 2, 3], '%hash' => {a => 1, b => 2};
196            
197             here an arbitrarily long list of name/value pairs is passed to the declarator.
198            
199             if the name is a C< $scalar > then the corresponding value will be copied into
200             the newly created variable at compile time. it is safe to pass any type of
201             scalar as a value, and it will not be stringified. C< bareword > and
202             C< -bareword > names will be interpreted as C< $bareword > which can cut down
203             on the number of quotes you need to write (C<< use my say => sub {...}; >>)
204            
205             if the name is an C< @array > or C< %hash > the corresponding values must be
206             C< ARRAY > or C< HASH > references, which will be dereferenced and copied into
207             the new variables.
208            
209             so the above becomes:
210            
211             my $say; BEGIN {$say = here::fetch(1)}
212             my @array; BEGIN {@array = @{here::fetch(2)}}
213             my %hash; BEGIN {%hash = %{here::fetch(3)}}
214            
215             where C< here::fetch > is a subroutine that returns the values passed into the
216             declarator, which gets around needing to serialize the values.
217            
218             =back
219            
220             =head2 [array of names] => list or array of values
221            
222             =over 4
223            
224             use my [qw($x $y $z)] => 1, 2, 3;
225            
226             use my [qw($foo @bar %baz)] => ['FOO', [qw(B A R)], {b => 'az'}];
227            
228             this usage is exactly like the list of name/value pairs usage except the names
229             and values are passed in separately. the names must be an array reference. the
230             values can be an array reference or a list.
231            
232             as a syntactic shortcut, the above two lines could also be written:
233            
234             use my '($x, $y, $z)' => 1, 2, 3;
235            
236             use my '($foo, @bar, %baz)' => 'FOO', [qw(B A R)], {b => 'az'};
237            
238             which of course expands to something equivalent to:
239            
240             my ($x, $y, $z);
241             BEGIN {$x = 1; $y = 2; $z = 3}
242            
243             my ($foo, @bar, %baz);
244             BEGIN {$foo = 'FOO'; @bar = qw(B A R); %baz = (b => 'az')}
245            
246             ignoring the complexities of C< here::fetch >
247            
248             =back
249            
250             =head2 const and const2
251            
252             =over 4
253            
254             use const '$FOO' => 'BAR';
255            
256             use const2 DEBUG => 1;
257            
258             which expands to:
259            
260             our $FOO; BEGIN {*FOO = \'BAR'}
261            
262             sub DEBUG () {1} our $DEBUG; BEGIN {*DEBUG = \DEBUG}
263            
264             these declarations only accept C< $scalar >, C< bareword > or C< -bareword >
265             names (interchangeably), but otherwise the usage is similar to C< use my ... >
266            
267             the single argument syntax is not supported with these two declarations.
268            
269             =back
270            
271             =head2 cleanup
272            
273             =over 4
274            
275             you can remove the pseudo-modules manually:
276            
277             no here::declare;
278            
279             or let the declaration fall out of scope if L is installed:
280            
281             {
282             use here::declare;
283             use my ...; # works
284             }
285             use my ...; # error
286            
287             =back
288            
289             =head1 EXPORT
290            
291             if you don't like the installation of pseudo-modules, you can pass
292             C< use here::declare > a list of any of the pseudo-module names each containing
293             at least one upper case character. this will cause that name to be exported
294             into your namespace as a subroutine.
295            
296             use here::declare 'MY';
297            
298             use here MY [qw($x $y)] => [0, 0];
299            
300             =head1 SEE ALSO
301            
302             C< here::declare > is built on top of the L< here > framework.
303            
304             in writing this module, I was pushed by p5p to make the interface a bit closer
305             to the native C< my > and C< our > keywords. I did this with L
306             in L. C is certainly closer in usage to the
307             keywords, but the dependency on C might prevent installation for
308             some people. in addition, this module (despite using C) is
309             a little safer to use than C since the C statement required
310             by this module more clearly delineates the scope of its actions.
311            
312             =head1 AUTHOR
313            
314             Eric Strom, C<< >>
315            
316             =head1 BUGS
317            
318             please report any bugs or feature requests to C, or
319             through the web interface at L.
320             I will be notified, and then you'll automatically be notified of progress on
321             your bug as I make changes.
322            
323             =head1 LICENSE AND COPYRIGHT
324            
325             copyright 2011 Eric Strom.
326            
327             this program is free software; you can redistribute it and/or modify it under
328             the terms of either: the GNU General Public License as published by the Free
329             Software Foundation; or the Artistic License.
330            
331             see http://dev.perl.org/licenses/ for more information.
332            
333             =cut
334            
335             1