File Coverage

blib/lib/String/Bash.pm
Criterion Covered Total %
statement 170 172 98.8
branch 70 86 81.4
condition 22 29 75.8
subroutine 18 18 100.0
pod 0 1 0.0
total 280 306 91.5


line stmt bran cond sub pod time code
1 1     1   27494 use strict;
  1         3  
  1         33  
2 1     1   6 use warnings;
  1         2  
  1         52  
3             package String::Bash;
4             BEGIN {
5 1     1   22 $String::Bash::AUTHORITY = 'cpan:AJGB';
6             }
7             BEGIN {
8 1     1   26 $String::Bash::VERSION = '1.110960';
9             }
10             #ABSTRACT: Parameter expansion in strings
11              
12 1         10 use Sub::Exporter -setup => {
13             exports => [qw( bash )],
14 1     1   1135 };
  1         15147  
15              
16 1     1   1464 use Regexp::Common qw( balanced );
  1         2728  
  1         5  
17 1     1   2873 use PadWalker qw( peek_my peek_our );
  1         2012  
  1         88  
18 1     1   8 use Scalar::Util qw( blessed );
  1         2  
  1         2375  
19              
20              
21              
22             sub bash($@) {
23 220     220 0 114877 my $format = shift;
24              
25 220         278 my $lookup;
26             my $setter;
27              
28 220 100       580 if ( defined $_[0] ) {
29 132 100       385 if ( blessed $_[0] ) {
30 44         58 my $obj = $_[0];
31 44     49   185 $lookup = sub { my $var = shift; return $obj->$var; };
  49         62  
  49         154  
32 44     1   134 $setter = sub { my $var = shift; $obj->$var(@_); };
  1         2  
  1         5  
33             } else {
34 88 100 66     347 if ( @_ == 1 && ref $_[0] eq 'HASH' ) {
35 44         52 my $href = $_[0];
36 44     49   169 $lookup = sub { return $href->{ $_[0] }; };
  49         106  
37 44     1   136 $setter = sub { $href->{ $_[0] } = $_[1]; };
  1         3  
38             } else {
39 44         169 my %vars = @_;
40 44     49   156 $lookup = sub { return $vars{ $_[0] }; };
  49         142  
41 44     1   130 $setter = sub { $vars{ $_[0] } = $_[1]; };
  1         4  
42             }
43             }
44             } else {
45              
46 88         1149 my $allmyvars = peek_my(1);
47 88         1086 my $allourvars = peek_our(1);
48              
49             $lookup = sub {
50 98     98   125 my $var = shift;
51 98         185 $var = "\$$var";
52 98 50       277 my $val = exists $allmyvars->{$var}
53             ? $allmyvars->{$var} : $allourvars->{$var};
54              
55 98 50       244 return unless ref $val eq 'SCALAR';
56              
57 98         100 return ${ $val };
  98         232  
58 88         406 };
59             $setter = sub {
60 2     2   4 my $var = shift;
61 2         3 my $val = shift;
62 2         5 $var = "\$$var";
63              
64 2 50       7 if ( exists $allmyvars->{$var} ) {
    0          
65 2         3 ${ $allmyvars->{$var} } = $val;
  2         6  
66             } elsif ( exists $allourvars->{$var} ) {
67 0         0 ${ $allourvars->{$var} } = $val;
  0         0  
68             }
69 88         406 };
70             };
71              
72 220         270 my $parser; $parser = sub {
73 235     235   320 my $format = shift;
74              
75 235 50       597 return $format unless index($format, '%{') >= 0;
76              
77 235         1118 my @ph = $format =~ /$RE{balanced}{-begin=>'%{'}{-end=>'}'}/gs;
78              
79 235         37390 for my $e ( @ph ) {
80 245         522 my $p = substr( $e, 2, -1);
81 245         244 my $rep;
82 245 100       1294 if ( substr($p,0,1) eq '#' ) {
    50          
83 15         25 my $name = substr($p, 1);
84 15   50     30 my $val = $lookup->($name) || '';
85              
86 15         39 $rep = length($val);
87             } elsif ( $p =~ /\A(\w+)(?:([:#%\/\^,])(.*))?\z/) {
88 230         693 my ($name, $op, $reminder) = ($1, $2, $3);
89 230         412 my $val = $lookup->($name);
90              
91             FINDREP: {
92 230 100       501 if ( ! $op ) { # %{param}
  230         423  
93 15   50     31 $rep = $val || '';
94 15         29 last FINDREP;
95             }
96             # expand reminder
97 215 100       598 $reminder = $parser->($reminder)
98             if index($reminder, '%{') >= 0;
99              
100 215 100       822 if ( $op eq ':' ) {
    100          
    100          
    100          
    100          
    50          
101 60         109 my $control = substr($reminder, 0, 1);
102 60 100       174 if ( $reminder =~ /^\d+/ ) {
103 20 50       52 if ( $val ) {
104 20         52 my ($offset, $limit) = split(':', $reminder, 2);
105 20 100       40 if ( $limit ) {
106 5         14 $rep = substr($val, $offset, $limit);
107             } else {
108 15         37 $rep = substr($val, $offset);
109             };
110              
111 20         49 last FINDREP;
112             };
113             };
114              
115 40 100       112 if ( $control eq '+' ) {
116 10 100       25 if ( defined $val ) {
117 5         11 $rep = substr($reminder, 1);
118             } else {
119 5         6 $rep = '';
120             };
121 10         25 last FINDREP;
122             };
123              
124              
125 30 100       61 if ( defined $val ) {
126 10   50     21 $rep = $val || '';
127 10         19 last FINDREP;
128             } else {
129 20 100       59 if ( $control eq '-' ) {
    50          
130 15         35 $rep = substr($reminder, 1);
131             } elsif ( $control eq '=' ) {
132 5         13 $rep = substr($reminder, 1);
133 5         11 $setter->( $name, $rep );
134             }
135             };
136             } elsif ( $op eq '#' ) {
137 25 50       51 if ( $val ) {
138 25         46 my $control = substr($reminder, 0, 1);
139 25         30 my $qr = "^";
140              
141 25 100       41 if ( $control eq '#' ) { # %{param##qr}
142 5         9 $reminder = substr( $reminder, 1);
143 5         21 $reminder =~ s/\*/\.*/g;
144 5         12 $reminder =~ s/\?/\./g;
145             } else {
146 20         42 $reminder =~ s/\?/\./g;
147 20         46 $reminder =~ s/\*/\.*?/g;
148             }
149              
150 25         37 $qr .= $reminder;
151 25         563 ($rep = $val) =~ s/$qr//;
152             }
153             } elsif ( $op eq '%' ) {
154 10 50       26 if ( $val ) {
155 10         18 my $control = substr($reminder, 0, 1);
156 10         11 my $qr;
157 10         15 my $replacement = '';
158              
159 10 100       20 if ( $control eq '%' ) { # %{param%%qr}
160 5         12 $qr = substr( $reminder, 1);
161 5         22 $qr =~ s/\*/\.*/g;
162             } else {
163 5         11 $replacement = substr($reminder, 0, index($reminder, '*'));
164 5         22 ($qr = $reminder) =~ s/\*/\.*?/g;
165             }
166 10         22 $qr =~ s/\?/\./g;
167              
168 10         11 $qr = "$qr\$";
169 10         179 ($rep = $val) =~ s/$qr/$replacement/;
170             }
171             } elsif ( $op eq '/' ) {
172 40 50       72 if ( $val ) {
173 40         80 my $control = substr($reminder, 0, 1);
174 40         45 my ($search, $replacement);
175 40 100       122 if ( $control eq '/' ) { # %{param//search/replacement}
    100          
    100          
176 5         19 ($search, $replacement) = split('/', substr($reminder, 1) );
177 5         13 $search =~ s/\*/\.*?/g;
178 5         10 $search =~ s/\?/\./g;
179 5   50     14 $replacement ||= '';
180              
181 5         41 ($rep = $val) =~ s/$search/$replacement/g;
182             } elsif ( $control eq '#' ) { # %{param/#search/replacement}
183 10         35 ($search, $replacement) = split('/', substr($reminder, 1) );
184 10         20 $search =~ s/\*/\.*?/g;
185 10         14 $search =~ s/\?/\./g;
186 10   50     22 $replacement ||= '';
187              
188 10         157 ($rep = $val) =~ s/^$search/$replacement/;
189             } elsif ( $control eq '%' ) { # %{param/%search/replacement}
190 10         35 ($search, $replacement) = split('/', substr($reminder, 1) );
191 10         24 $search =~ s/\*/\.*?/g;
192 10         15 $search =~ s/\?/\./g;
193 10   50     16 $replacement ||= '';
194              
195 10         151 ($rep = $val) =~ s/$search$/$replacement/;
196             } else {
197 15         40 ($search, $replacement) = split('/', $reminder);
198 15         32 $search =~ s/\*/\.*?/g;
199 15         23 $search =~ s/\?/\./g;
200 15   100     63 $replacement ||= '';
201              
202 15         95 ($rep = $val) =~ s/$search/$replacement/;
203             }
204             }
205             } elsif ( $op eq '^' ) {
206 40 50       83 if ( $val ) {
207 40         77 my $control = substr($reminder, 0, 1);
208              
209 40 100       69 if ( $control eq '^' ) { # %{param^^}
210 20 100 100     112 if ( $reminder eq '^' || $reminder eq '^?' ) {
211 10         27 $rep = uc $val;
212             } else {
213 10         24 my $matching = substr($reminder, 1);
214 10         227 ($rep = $val) =~ s/($matching)/\u$1/g;
215             }
216             } else {
217 20 100 100     92 if ( length $reminder && $reminder ne '?' ) {
218 10         252 ($rep = $val) =~ s/^($reminder)/\u$1/;
219             } else {
220 10         30 $rep = ucfirst $val;
221             }
222             }
223             }
224             } elsif ( $op eq ',' ) {
225 40 50       91 if ( $val ) {
226 40         83 my $control = substr($reminder, 0, 1);
227              
228 40 100       77 if ( $control eq ',' ) { # %{param,,}
229 20 100 100     91 if ( $reminder eq ',' || $reminder eq ',?' ) {
230 10         31 $rep = lc $val;
231             } else {
232 10         24 my $matching = substr($reminder, 1);
233 10         219 ($rep = $val) =~ s/($matching)/\l$1/g;
234             }
235             } else {
236 20 100 100     90 if ( length $reminder && $reminder ne '?' ) {
237 10         235 ($rep = $val) =~ s/^($reminder)/\l$1/;
238             } else {
239 10         35 $rep = lcfirst $val;
240             }
241             }
242             }
243             };
244             };
245             };
246              
247 245 50       573 $rep = '' unless defined $rep;
248 245         3636 $format =~ s/\Q$e\E/$rep/g;
249             };
250              
251 235         630 return $format;
252 220         1500 };
253              
254 220         432 my $result = $parser->( $format );
255              
256 220         574 return $result;
257             }
258              
259              
260             1;
261              
262             __END__