File Coverage

lib/Variable/Eject.pm
Criterion Covered Total %
statement 88 97 90.7
branch 11 18 61.1
condition 1 3 33.3
subroutine 13 15 86.6
pod 0 7 0.0
total 113 140 80.7


line stmt bran cond sub pod time code
1             package Variable::Eject;
2              
3             =head1 NAME
4              
5             Variable::Eject - Eject variables from hash to current namespace
6              
7             =head1 VERSION
8              
9             Version 0.04
10              
11             =cut
12              
13             our $VERSION = '0.04';
14              
15             =head1 SYNOPSIS
16              
17             use Variable::Eject;
18              
19             my $hash = {
20             scalar => 'scalar value',
21             array => [1..3],
22             hash => { my => 'value' },
23             };
24              
25             # Now, eject vars from hash
26             eject(
27             $hash => $scalar, @array, %hash,
28             );
29              
30             # Let's look
31             say $scalar;
32             say @array;
33             say keys %hash;
34              
35             # Let's modify (source will be modified)
36             $scalar .= ' modified';
37             shift @array;
38             $hash{another} = 1;
39              
40             =head1 EXPORT
41              
42             A list of functions that can be exported. You can delete this section
43             if you don't export anything, such as for a purely object-oriented module.
44              
45             =head1 FUNCTIONS
46              
47             =head2 eject ( $source_hash => $scalar, @array, %hash ... );
48              
49             =cut
50              
51 6     6   578389 use uni::perl;
  6         1480  
  6         42  
52             m{
53             use strict;
54             use warnings;
55             }x;
56 6     6   25164 use Devel::Declare;
  6         29322  
  6         29  
57 6     6   4156 use Lexical::Alias ();
  6         2360  
  6         122  
58 6     6   34 use Carp ();
  6         11  
  6         913  
59              
60             our $SUBNAME = 'eject';
61             our @CARP_NOT = qw(Variable::Eject Devel::Declare);
62              
63             BEGIN {
64 6 50   6   70 if (!defined &Variable::Eject::DEBUG) {
65 6 50       37 if ($ENV{ PERL_VARIABLE_EJECT_DEBUG }) {
66 0         0 *DEBUG = sub () { 1 };
67             } else {
68 6         472 *DEBUG = sub () { 0 };
69             }
70             }
71             }
72              
73             sub import{
74 6     6   58 my $class = shift;
75 6         15 my $caller = caller;
76 6         56 Devel::Declare->setup_for(
77             $caller,
78             { $SUBNAME => { const => \&parse } }
79             );
80             {
81 6     6   38 no strict 'refs';
  6         12  
  6         7798  
  6         161  
82 6     0   39 *{$caller.'::'.$SUBNAME } = sub (@) { Carp::carp( (0+@_)." <@_> this shouldn't be called - report your case to author\n" ) };
  6         227  
  0         0  
83             }
84             }
85              
86             sub parse {
87 5     5 0 179 my $parser = Variable::Eject->new($_[1]);
88 5         14 $parser->process();
89             }
90              
91             sub new {
92 5     5 0 15 my ($class, $offset) = @_;
93 5         16 bless \$offset, $class;
94             }
95              
96             sub whereami {
97 0     0 0 0 my $self = shift;
98 0         0 my $line = Devel::Declare::get_linestr();
99 0         0 warn "..>".substr($line,$$self);
100             }
101              
102             sub process {
103 5     5 0 8 my $self = shift;
104            
105 5         8 $self->whereami if DEBUG;
106            
107 5         60 $$self += Devel::Declare::toke_skipspace($$self);
108            
109 5 100       50 if (my $len = Devel::Declare::toke_scan_word($$self, 1)) {
110 2         8 my $subname = substr(Devel::Declare::get_linestr(), $$self, $len);
111 2         4 warn "Skip subname $subname" if DEBUG;
112 2 50       5 return if $subname ne $SUBNAME;
113             }
114            
115 5         17 my $move = Devel::Declare::toke_move_past_token($$self);
116 5         8 warn "Move past token +$move" if DEBUG;
117 5         11 $$self += $move;
118            
119 5         12 $$self += Devel::Declare::toke_skipspace($$self);
120            
121 5         9 $self->whereami if DEBUG;
122 5         16 $self->skip_spaces();
123            
124 5         11 my $args = $self->extract_args();
125            
126 5         61 $args =~ s/(\r|\n)//go;
127 5         46 my @args = split /\s*(?:,|=>)\s*/, $args;
128 5 50       16 @args > 1 or croak( 'Usage: '.$Variable::Eject::SUBNAME.'( $source_hash => $scalar, @array, %hash, ... )' );
129 5         64 my $from = shift @args;
130 5         11 warn "Have args $args: $from => [ @args ]" if DEBUG;
131 5         5 my $inj;
132 5         12 for (@args) {
133 9         33 s{(?:^\s+|\s+$)}{}sg; # ' $var ' => '$var'
134 9         18 my $type = substr($_,0,1,'');
135 9         23 s{(?:^\s+|\s+$)}{}sg; # ' { var } ' => '{ var }'
136             #s{^\s+}{}s; # ' { var } ' => '{ var }'
137 9         47 s{^\s*\{?\s*|\s*\}?\s*$}{}sg;
138 9         13 warn "arg = <$type : $_>\n" if DEBUG;
139             #$_ = '{'.$_.'}' unless m/^\{.+\}$/;
140 9 100       20 if ($type eq '$') {
141 5         19 $inj .= 'Lexical::Alias::alias( '.$from.'->{'.$_.'} => my $'.$_.' );';
142             } else {
143 4         12 $inj .= 'Lexical::Alias::alias( '.$type.'{'.$from.'->{'.$_.'}} => my '.$type.$_.' );';
144             }
145             }
146 5         7 warn "$inj" if DEBUG;
147 5         7 $self->whereami if DEBUG;
148 5         25 $self->inject($inj);
149 5         69 return;
150             }
151              
152             sub skip_spaces {
153 5     5 0 8 my $self = shift;
154 5         12 $$self += Devel::Declare::toke_skipspace($$self);
155             }
156              
157             sub extract_args {
158 5     5 0 8 my $self = shift;
159 5         7 warn "extract_args called at $$self\n" if DEBUG;
160 5         17 my $linestr = Devel::Declare::get_linestr();
161 5 50       18 if (substr($linestr, $$self, 1) eq '(') {
162 5         43 my $length = Devel::Declare::toke_scan_str($$self);
163 5         19 my $proto = Devel::Declare::get_lex_stuff();
164 5         13 Devel::Declare::clear_lex_stuff();
165 5         13 $linestr = Devel::Declare::get_linestr();
166 5 50 33     44 if (
167             $length < 0
168             ||
169             $$self + $length > length($linestr)
170             ){
171 0         0 Carp::croak("Unbalanced text supplied");
172             }
173 5         11 warn "<<< '$linestr'\n" if DEBUG;
174 5         9 my $hide = '(42) if 0;';
175 5         15 substr($linestr, $$self, $length) = $hide;
176 5         7 warn ">>> '$linestr'\n" if DEBUG;
177 5         10 $$self += length $hide;
178 5         13 Devel::Declare::set_linestr($linestr);
179            
180 5         13 return $proto;
181             } else {
182 0         0 Carp::croak "Can't use ".$SUBNAME.' without brackets. Use '.$SUBNAME.'(...)';
183             }
184 0         0 return '';
185             }
186              
187             sub inject{
188 5     5 0 11 my ($self, $inject) = @_;
189            
190 5         8 warn "inject called at $$self for '$inject'\n" if DEBUG;
191            
192 5         15 my $linestr = Devel::Declare::get_linestr();
193            
194 5         16 warn "<<< '$linestr'\n" if DEBUG;
195            
196 5 50       23 if ($$self > length($linestr)) {
197 0         0 croak("Parser tried to inject data outside program source, stopping");
198             }
199 5         14 substr($linestr, $$self, 0) = $inject;
200 5         7 warn ">>> '$linestr'\n" if DEBUG;
201            
202 5         16 Devel::Declare::set_linestr($linestr);
203 5         7 $$self += length($inject);
204             }
205              
206              
207             =head1 AUTHOR
208              
209             Mons Anderson, C<< >>
210              
211             =head1 BUGS
212              
213             Please report any bugs or feature requests to C, or through
214             the web interface at L. I will be notified, and then you'll
215             automatically be notified of progress on your bug as I make changes.
216              
217             =head1 COPYRIGHT & LICENSE
218              
219             Copyright 2009-2020 Mons Anderson
220              
221             This program is free software; you can redistribute it and/or modify it
222             under the same terms as Perl itself.
223              
224             =cut
225              
226             1; # End of Variable::Eject