File Coverage

blib/lib/vars/i.pm
Criterion Covered Total %
statement 61 61 100.0
branch 38 38 100.0
condition 3 3 100.0
subroutine 5 5 100.0
pod n/a
total 107 107 100.0


line stmt bran cond sub pod time code
1             package vars::i;
2 5     5   526366 use 5.006001;
  5         51  
3              
4             our $VERSION = '2.000000'; # Prerelease leading to v2.0.0
5              
6 5     5   24 use strict qw(vars subs);
  5         6  
  5         112  
7 5     5   19 use warnings;
  5         8  
  5         3681  
8              
9             # Turn a scalar, arrayref, or hashref into a list
10             sub _unpack {
11 11 100   11   30 if( ref $_[0] eq 'ARRAY' ){
    100          
12 7         10 return @{$_[0]};
  7         14  
13             }
14             elsif( ref $_[0] eq 'HASH' ){
15 3         3 return %{$_[0]};
  3         11  
16             }
17             else {
18 1         2 return ($_[0]);
19             }
20             } #_unpack
21              
22             sub import {
23 42 100   42   40707 return if @_ < 2;
24 37         89 my( $pack, $first_var, @value ) = @_;
25 37         60 my $callpack = caller;
26              
27 37         47 my %definitions;
28              
29 37 100       95 if( not @value ){
    100          
30 9 100       24 if( ref $first_var eq 'ARRAY' ){ # E.g., use vars [ foo=>, bar=>... ];
    100          
31 6         18 %definitions = @$first_var;
32             }
33             elsif( ref $first_var eq 'HASH' ){ # E.g., use vars { foo=>, bar=>... };
34 2         7 %definitions = %$first_var;
35             }
36             else {
37 1         30 return; # No value given --- no-op; not an error.
38             }
39             }
40             elsif(@value == 1) { # E.g., use vars foo => <str/hashref/arrayref>
41 26         62 %definitions = ( $first_var => $value[0] );
42             }
43             else {
44 2         6 %definitions = ( $first_var => [@value] );
45             }
46              
47             #require Data::Dumper; # For debugging
48             #print Data::Dumper->Dump([\%definitions], ['definitions']);
49              
50 36         116 while( my ($var, $val) = each %definitions ){
51              
52 40 100       203 if( my( $ch, $sym ) = $var =~ /^([-\$\@\%\*\&])(.+)$/ ){
53 38 100 100     247 if( $ch eq '-' ){ # An option
    100          
54 2         9 require Carp;
55 2         237 Carp::croak('vars::i does not yet support any options!');
56             }
57             elsif( $sym !~ /^(\w+(::|'))+\w+$/ && $sym =~ /\W|(^\d+$)/ ){
58             # ^^ Skip fully-qualified names ^^ Check special names
59              
60             # A variable name we can't or won't handle
61 9         37 require Carp;
62              
63 9 100       31 if( $sym =~ /^\w+[[{].*[]}]$/ ){
    100          
64 2         200 Carp::croak("Can't declare individual elements of hash or array");
65             }
66             elsif( $sym =~ /^(\d+|\W|\^[\[\]A-Z\^_\?]|\{\^[a-zA-Z0-9]+\})$/ ){
67 5         463 Carp::croak("Refusing to initialize special variable $ch$sym");
68             }
69             else {
70 2         192 Carp::croak("I can't recognize $ch$sym as a variable name");
71             }
72             }
73              
74 27 100       82 $sym = "${callpack}::$sym" unless $sym =~ /::/;
75              
76 27 100       64 if( $ch eq '$' ){
    100          
    100          
    100          
77 12         36 *{$sym} = \$$sym;
  12         29  
78 12         17 ${$sym} = $val;
  12         225  
79             }
80             elsif( $ch eq '@' ){
81 7         27 *{$sym} = \@$sym;
  7         18  
82 7         26 @{$sym} = _unpack $val;
  7         713  
83             }
84             elsif( $ch eq '%' ){
85 4         54 *{$sym} = \%$sym;
  4         21  
86 4         12 %{$sym} = _unpack $val;
  4         123  
87             }
88             elsif( $ch eq '*' ){
89 1         3 *{$sym} = \*$sym;
  1         2  
90 1         2 (*{$sym}) = $val;
  1         50  
91             }
92             else { # $ch eq '&'; guaranteed by the regex above.
93 3         6 my ($param) = $val;
94 3 100       5 if(ref $param) {
95             # NOTE: for now, permit any ref, since we can't determine
96             # refs overload &{}. If necessary, we can later use
97             # Scalar::Util 1.25+'s blessed(), and allow CODE refs
98             # or blessed refs.
99 1         2 *{$sym} = $param;
  1         25  
100             }
101             else {
102 2         8 require Carp;
103 2 100       204 Carp::croak("Can't assign non-reference " .
104             (defined($param) ? $param : '<undef>') .
105             " to $sym");
106             }
107             }
108             # There is no else, because the regex above guarantees
109             # that $ch has one of the values we tested.
110              
111             }
112             else { # Name didn't match the regex above
113 2         8 require Carp;
114 2         270 Carp::croak("'$var' is not a valid variable or option name");
115             }
116             }
117             } #import()
118              
119             1;
120             __END__
121              
122             =head1 NAME
123              
124             vars::i - Perl pragma to declare and simultaneously initialize global variables.
125              
126             =head1 SYNOPSIS
127              
128             use Data::Dumper;
129             $Data::Dumper::Deparse = 1;
130              
131             use vars::i '$VERSION' => 3.44;
132             use vars::i '@BORG' => 6 .. 6;
133             use vars::i '%BORD' => 1 .. 10;
134             use vars::i '&VERSION' => sub(){rand 20};
135             use vars::i '*SOUTH' => *STDOUT;
136              
137             BEGIN {
138             print SOUTH Dumper [
139             $VERSION, \@BORG, \%BORD, \&VERSION
140             ];
141             }
142              
143             use vars::i [ # has the same effect as the 5 use statements above
144             '$VERSION' => 3.66,
145             '@BORG' => [6 .. 6],
146             '%BORD' => {1 .. 10},
147             '&VERSION' => sub(){rand 20},
148             '*SOUTH' => *STDOUT,
149             ];
150              
151             print SOUTH Dumper [ $VERSION, \@BORG, \%BORD, \&VERSION ];
152              
153             =head1 DESCRIPTION
154              
155             For whatever reason, I once had to write something like
156              
157             BEGIN {
158             use vars '$VERSION';
159             $VERSION = 3;
160             }
161              
162             or
163              
164             our $VERSION;
165             BEGIN { $VERSION = 3; }
166              
167             and I really didn't like typing that much. With this package, I can say:
168              
169             use vars::i '$VERSION' => 3;
170              
171             and get the same effect.
172              
173             Also, I like being able to say
174              
175             use vars::i '$VERSION' => sprintf("%d.%02d", q$Revision: 1.3 $ =~ /: (\d+)\.(\d+)/);
176              
177             use vars::i [
178             '$VERSION' => sprintf("%d.%02d", q$Revision: 1.3 $ =~ /: (\d+)\.(\d+)/),
179             '$REVISION'=> '$Id: GENERIC.pm,v 1.3 2002/06/02 11:12:38 _ Exp $',
180             ];
181              
182             Like with C<use vars;>, there is no need to fully qualify the variable name.
183             However, you may if you wish.
184              
185             =head1 NOTES
186              
187             =over
188              
189             =item *
190              
191             Specifying a variable but not a value will succeed silently, and will B<not>
192             create the variable. E.g., C<use vars::i '$foo';> is a no-op.
193              
194             Now, you might expect that C<< use vars::i '$foo'; >> would behave the same
195             way as C<< use vars '$foo'; >>. That would not be an unreasonable expectation.
196             However, C<< use vars::i qw($foo $bar); >> has a very different
197             effect than does C<< use vars qw($foo $bar); >>! In order to avoid
198             subtle errors in the two-parameter case, C<vars::i> also rejects the
199             one-parameter case.
200              
201             =item *
202              
203             Trying to create a special variable is fatal. E.g., C<use vars::i '$@', 1;>
204             will die at compile time.
205              
206             =item *
207              
208             The sigil is taken into account (context sensitivity!) So:
209              
210             use vars::i '$foo' => [1,2,3]; # now $foo is an arrayref
211             use vars::i '@bar' => [1,2,3]; # now @bar is a three-element list
212              
213             =back
214              
215             =head1 SEE ALSO
216              
217             See L<vars>, L<perldoc/"our">, L<perlmodlib/Pragmatic Modules>.
218              
219             =head1 VERSIONING
220              
221             Since version 1.900000, this module is numbered using
222             L<Semantic Versioning 2.0.0|https://semver.org>,
223             packed in the compatibility format of C<< vX.Y.Z -> X.00Y00Z >>.
224              
225             This version supports Perl 5.6.1+. If you are running an earlier Perl:
226              
227             =over
228              
229             =item Perl 5.6:
230              
231             Use version 1.10 of this module
232             (L<CXW/vars-i-1.10|https://metacpan.org/pod/release/CXW/vars-i-1.10/lib/vars/i.pm>).
233              
234             =item Pre-5.6:
235              
236             Use version 1.01 of this module
237             (L<PODMASTER/vars-i-1.01|https://metacpan.org/pod/release/PODMASTER/vars-i-1.01/lib/vars/i.pm>).
238              
239             =back
240              
241             =head1 DEVELOPMENT
242              
243             This module uses L<Minilla> for release management. When developing, you
244             can use normal C<prove -l> for testing based on the files in C<lib/>. Before
245             submitting a pull request, please:
246              
247             =over
248              
249             =item *
250              
251             make sure all tests pass under C<minil test>
252              
253             =item *
254              
255             add brief descriptions to the C<Changes> file, under the C<{{$NEXT}}> line.
256              
257             =item *
258              
259             update the C<.mailmap> file to list your PAUSE user ID if you have one, and
260             if your git commits are not under your C<@cpan.org> email. That way you will
261             be properly listed as a contributor in MetaCPAN.
262              
263             =back
264              
265             =head1 AUTHORS
266              
267             D.H. <podmaster@cpan.org>
268              
269             Christopher White <cxw@cpan.org>
270              
271             =head2 Thanks
272              
273             Thanks to everyone who has worked on L<vars>, which served as the basis for
274             this module.
275              
276             =head1 SUPPORT
277              
278             Please report any bugs at L<https://github.com/cxw42/Perl-vars-i/issues>.
279              
280             You can also see the old bugtracker at
281             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=vars-i> for older bugs.
282              
283             =head1 LICENSE
284              
285             Copyright (c) 2003--2019 by D.H. aka PodMaster, and contributors.
286             All rights reserved.
287              
288             This module is free software; you can redistribute it and/or modify it
289             under the same terms as Perl itself.
290              
291             =cut