line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package String::Interpolate::RE; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ABSTRACT: interpolate variables into strings using regular expressions |
4
|
|
|
|
|
|
|
|
5
|
6
|
|
|
6
|
|
1343678
|
use strict; |
|
6
|
|
|
|
|
45
|
|
|
6
|
|
|
|
|
176
|
|
6
|
6
|
|
|
6
|
|
31
|
use warnings; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
137
|
|
7
|
6
|
|
|
6
|
|
29
|
use Carp; |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
323
|
|
8
|
|
|
|
|
|
|
|
9
|
6
|
|
|
6
|
|
2571
|
use Exporter::Shiny qw[ strinterp ]; |
|
6
|
|
|
|
|
24884
|
|
|
6
|
|
|
|
|
38
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = '0.10'; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
## no critic (ProhibitAccessOfPrivateData) |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my %Opt = ( |
16
|
|
|
|
|
|
|
variable_re => qr/\w+/, |
17
|
|
|
|
|
|
|
raiseundef => 0, |
18
|
|
|
|
|
|
|
emptyundef => 0, |
19
|
|
|
|
|
|
|
useenv => 1, |
20
|
|
|
|
|
|
|
format => 0, |
21
|
|
|
|
|
|
|
recurse => 0, |
22
|
|
|
|
|
|
|
recurse_limit => 0, |
23
|
|
|
|
|
|
|
recurse_fail_limit => 100, |
24
|
|
|
|
|
|
|
); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
*strinterp = _mk_strinterp( \%Opt ); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub _generate_strinterp { |
29
|
|
|
|
|
|
|
|
30
|
6
|
|
|
6
|
|
707
|
my ( $me, $name, $args ) = @_; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
return \&strinterp |
33
|
6
|
100
|
100
|
|
|
59
|
if ! defined $args || ! defined $args->{opts}; |
34
|
|
|
|
|
|
|
|
35
|
1
|
|
|
|
|
7
|
my %opt = %Opt; |
36
|
1
|
|
|
|
|
3
|
$opt{lc $_} = $args->{opts}{$_} foreach keys %{$args->{opts}}; |
|
1
|
|
|
|
|
7
|
|
37
|
1
|
|
|
|
|
3
|
return _mk_strinterp( \%opt ); |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub _mk_strinterp { |
41
|
|
|
|
|
|
|
|
42
|
7
|
|
|
7
|
|
17
|
my $default_opt = shift; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
return sub { |
45
|
|
|
|
|
|
|
|
46
|
49
|
|
|
49
|
|
27890
|
my ( $text, $var, $opts ) = @_; |
47
|
|
|
|
|
|
|
|
48
|
49
|
100
|
|
|
|
141
|
$var = {} unless defined $var; |
49
|
|
|
|
|
|
|
|
50
|
49
|
|
|
|
|
262
|
my %opt = %$default_opt; |
51
|
|
|
|
|
|
|
|
52
|
49
|
100
|
|
|
|
136
|
if ( defined $opts ) { |
53
|
26
|
|
|
|
|
127
|
$opt{ lc $_ } = $opts->{$_} foreach keys %$opts; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
## use critic |
56
|
|
|
|
|
|
|
|
57
|
49
|
100
|
|
|
|
137
|
my $fmt = $opt{format} ? ':([^}]+)' : '()'; |
58
|
|
|
|
|
|
|
|
59
|
49
|
|
|
|
|
96
|
$opt{track} = {}; |
60
|
49
|
|
|
|
|
94
|
$opt{loop} = 0; |
61
|
49
|
|
|
|
|
83
|
$opt{fmt} = $fmt; |
62
|
|
|
|
|
|
|
|
63
|
49
|
|
|
|
|
147
|
_strinterp( $text, $var, \%opt ); |
64
|
|
|
|
|
|
|
|
65
|
39
|
|
|
|
|
259
|
return $text; |
66
|
|
|
|
|
|
|
} |
67
|
7
|
|
|
|
|
44
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub _strinterp { |
70
|
|
|
|
|
|
|
|
71
|
94
|
|
|
94
|
|
137
|
my $var = $_[1]; |
72
|
94
|
|
|
|
|
128
|
my $opt = $_[2]; |
73
|
94
|
|
|
|
|
160
|
my $fmt = $opt->{fmt}; |
74
|
94
|
|
|
|
|
137
|
my $re = $opt->{variable_re}; |
75
|
|
|
|
|
|
|
|
76
|
94
|
|
|
|
|
962
|
$_[0] =~ s{ |
77
|
|
|
|
|
|
|
\$ # find a literal dollar sign |
78
|
|
|
|
|
|
|
( # followed by either |
79
|
|
|
|
|
|
|
\{ ($re)(?:$fmt)? \} # a variable name in curly brackets ($2) |
80
|
|
|
|
|
|
|
# and an optional sprintf format |
81
|
|
|
|
|
|
|
| # or |
82
|
|
|
|
|
|
|
(\w+) # a bareword ($3) |
83
|
|
|
|
|
|
|
) |
84
|
|
|
|
|
|
|
}{ |
85
|
100
|
100
|
|
|
|
356
|
my $t = defined $4 ? $4 : $2; |
86
|
|
|
|
|
|
|
|
87
|
100
|
100
|
|
|
|
274
|
my $user_value = 'CODE' eq ref $var ? $var->($t) : $var->{$t}; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
my $v = |
90
|
|
|
|
|
|
|
# user provided? |
91
|
|
|
|
|
|
|
defined $user_value ? $user_value |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# maybe in the environment |
94
|
|
|
|
|
|
|
: $opt->{useenv} && exists $ENV{$t} ? $ENV{$t} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# undefined: throw an error? |
97
|
|
|
|
|
|
|
: $opt->{raiseundef} ? croak( "undefined variable: $t\n" ) |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# undefined: replace with ''? |
100
|
100
|
100
|
100
|
|
|
978
|
: $opt->{emptyundef} ? '' |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# undefined |
103
|
|
|
|
|
|
|
: undef |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
; |
106
|
|
|
|
|
|
|
|
107
|
97
|
100
|
66
|
|
|
358
|
if ( $opt->{recurse} && defined $v ) { |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
RECURSE: |
111
|
|
|
|
|
|
|
{ |
112
|
|
|
|
|
|
|
|
113
|
55
|
|
|
|
|
79
|
croak( |
114
|
|
|
|
|
|
|
"circular interpolation loop detected with repeated interpolation of <\$$t>\n" |
115
|
55
|
100
|
|
|
|
728
|
) if $opt->{track}{$t}++; |
116
|
|
|
|
|
|
|
|
117
|
51
|
|
|
|
|
73
|
++$opt->{loop}; |
118
|
|
|
|
|
|
|
|
119
|
51
|
100
|
100
|
|
|
111
|
last RECURSE if $opt->{recurse_limit} && $opt->{loop} > $opt->{recurse_limit}; |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
croak( |
122
|
|
|
|
|
|
|
"recursion fail-safe limit ($opt->{recurse_fail_limit}) reached at interpolation of <\$$t>\n" |
123
|
48
|
100
|
100
|
|
|
660
|
) if $opt->{recurse_fail_limit} && $opt->{loop} > $opt->{recurse_fail_limit}; |
124
|
|
|
|
|
|
|
|
125
|
45
|
|
|
|
|
99
|
_strinterp( $v, $_[1], $_[2] ); |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
32
|
|
|
|
|
65
|
delete $opt->{track}{$t}; |
130
|
32
|
|
|
|
|
47
|
--$opt->{loop}; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# if not defined, just put it back into the string |
134
|
74
|
100
|
100
|
|
|
405
|
! defined $v ? '$' . $1 |
|
|
100
|
|
|
|
|
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# no format? return as is |
137
|
|
|
|
|
|
|
: ! defined $3 || $3 eq '' ? $v |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# format it |
140
|
|
|
|
|
|
|
: sprintf( $3, $v) |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
}egx; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
1; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# |
150
|
|
|
|
|
|
|
# This file is part of String-Interpolate-RE |
151
|
|
|
|
|
|
|
# |
152
|
|
|
|
|
|
|
# This software is Copyright (c) 2017 by Smithsonian Astrophysical Observatory. |
153
|
|
|
|
|
|
|
# |
154
|
|
|
|
|
|
|
# This is free software, licensed under: |
155
|
|
|
|
|
|
|
# |
156
|
|
|
|
|
|
|
# The GNU General Public License, Version 3, June 2007 |
157
|
|
|
|
|
|
|
# |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=pod |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head1 NAME |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
String::Interpolate::RE - interpolate variables into strings using regular expressions |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head1 VERSION |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
version 0.10 |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head1 SYNOPSIS |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# default formulation |
172
|
|
|
|
|
|
|
use String::Interpolate::RE qw( strinterp ); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
$str = strinterp( "${Var1} $Var2", $vars, \%opts ); |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# import with different default options. |
177
|
|
|
|
|
|
|
use String::Interpolate::RE strinterp => { opts => { useENV => 0 } }; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 DESCRIPTION |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
This module interpolates variables into strings using regular |
182
|
|
|
|
|
|
|
expression matching rather than Perl's built-in interpolation |
183
|
|
|
|
|
|
|
mechanism and thus hopefully does not suffer from the security |
184
|
|
|
|
|
|
|
problems inherent in using B to interpolate into strings of |
185
|
|
|
|
|
|
|
suspect ancestry. |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head2 Changing the default option values |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
The default values for L's options were not all well |
190
|
|
|
|
|
|
|
thought out. B uses L, |
191
|
|
|
|
|
|
|
allowing a version of L with saner defaults to be |
192
|
|
|
|
|
|
|
exported. Simply specify them when importing: |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
use String::Interpolate::RE strinterp => { opts => { useENV => 0 } }; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
The subroutine may be renamed using the C<-as> option: |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
use String::Interpolate::RE strinterp => { -as => strinterp_noenv, |
199
|
|
|
|
|
|
|
opts => { useENV => 0 } }; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
strinterp_noenv( ... ); |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=head1 INTERFACE |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=over |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=item strinterp |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
$str = strinterp( $template ); |
210
|
|
|
|
|
|
|
$str = strinterp( $template, $vars ); |
211
|
|
|
|
|
|
|
$str = strinterp( $template, $vars, \%opts ); |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
Interpolate variables into a template string, returning the |
214
|
|
|
|
|
|
|
resultant string. The template string is scanned for tokens of the |
215
|
|
|
|
|
|
|
form |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
$VAR |
218
|
|
|
|
|
|
|
${VAR} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
where C is composed of one or more word characters (as defined by |
221
|
|
|
|
|
|
|
the C<\w> Perl regular expression pattern). C is resolved using |
222
|
|
|
|
|
|
|
the optional C<$vars> argument, which may either by a hashref (in |
223
|
|
|
|
|
|
|
which case C must be a key), or a function reference (which is |
224
|
|
|
|
|
|
|
passed C as its only argument and must return the value). |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
If the value returned for C is defined, it will be interpolated |
227
|
|
|
|
|
|
|
into the string at that point. By default, variables which are not |
228
|
|
|
|
|
|
|
defined are by default left as is in the string. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
The C<%opts> parameter may be used to modify the behavior of this |
231
|
|
|
|
|
|
|
function. The following (case insensitive) keys are recognized: |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=over |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=item format I |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
If this flag is true, the template string may provide a C |
238
|
|
|
|
|
|
|
compatible format which will be used to generate the interpolated |
239
|
|
|
|
|
|
|
value. The format should be appended to the variable name with |
240
|
|
|
|
|
|
|
an intervening C<:> character, e.g. |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
${VAR:fmt} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
For example, |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
%var = ( foo => 3 ); |
247
|
|
|
|
|
|
|
print strinterp( '${foo:%03d}', \%var, { format => 1 } ); |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
would result in |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
003 |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=item raiseundef I |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
If true, a variable which has not been defined will result in an |
256
|
|
|
|
|
|
|
exception being raised. This defaults to false. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=item emptyundef I |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
If true, a variable which has not been defined will be replaced with |
261
|
|
|
|
|
|
|
the empty string. This defaults to false. |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=item useENV I |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
If true, the C<%ENV> hash will be searched for variables which are not |
266
|
|
|
|
|
|
|
defined in the passed C<%var> hash. This defaults to true. |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=item recurse I |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
If true, derived values are themselves scanned for variables to |
271
|
|
|
|
|
|
|
interpolate. To specify a limit to the number of levels of recursions |
272
|
|
|
|
|
|
|
to attempt, set the C option. Circular dependencies |
273
|
|
|
|
|
|
|
are caught, but just to be safe there's a limit of recursion levels |
274
|
|
|
|
|
|
|
specified by C, beyond which an exception is |
275
|
|
|
|
|
|
|
thrown. |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
For example, |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
my %var = ( a => '$b', b => '$c', c => 'd' ); |
280
|
|
|
|
|
|
|
strinterp( '$a', \%var ) => '$b' |
281
|
|
|
|
|
|
|
strinterp( '$a', \%var, { recurse => 1 } ) => 'd' |
282
|
|
|
|
|
|
|
strinterp( '$a', \%var, { recurse => 1, recurse_limit => 1 } ) => '$c' |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
strinterp( '$a', { a => '$b', b => '$a' } , { recurse => 1 } |
285
|
|
|
|
|
|
|
recursive interpolation loop detected with repeated |
286
|
|
|
|
|
|
|
interpolation of $a |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=item recurse_limit I |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
The number of recursion levels to descend when recursing into a |
291
|
|
|
|
|
|
|
variable's value before stopping. The default is C<0>, which means no |
292
|
|
|
|
|
|
|
limit. |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=item recurse_fail_limit I |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
The number of recursion levels to descend when recursing into a |
297
|
|
|
|
|
|
|
variable's value before giving up and croaking. The default is C<100>. |
298
|
|
|
|
|
|
|
Setting this to C<0> means no limit. |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=item variable_re I |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
This specifies the regular expression (created with the C |
303
|
|
|
|
|
|
|
operator) which will match a variable name. It defaults to |
304
|
|
|
|
|
|
|
C. Don't use C<:>, C<{>, or C<}> in the regex, or things may |
305
|
|
|
|
|
|
|
break. |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=back |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=back |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
=head1 DIAGNOSTICS |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=over |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=item C<< undefined variable: %s >> |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
This string is thrown if the C option is set and the |
318
|
|
|
|
|
|
|
variable C<%s> is not defined. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=item C<< recursive interpolation loop detected with repeated interpolation of <%s> >> |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
When resolving nested interpolated values (with the C option |
323
|
|
|
|
|
|
|
true ) a circular loop was found. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=item C<< recursion fail-safe limit (%d) reached at interpolation of <%s> >> |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
The recursion fail safe limit (C) was reached while |
328
|
|
|
|
|
|
|
interpolating nested variable values (with the C option true ). |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=back |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=head1 BUGS AND LIMITATIONS |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
You can make new bug reports, and view existing ones, through the |
335
|
|
|
|
|
|
|
web interface at L. |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=head1 AUTHOR |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Diab Jerius |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
This software is Copyright (c) 2017 by Smithsonian Astrophysical Observatory. |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
This is free software, licensed under: |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
The GNU General Public License, Version 3, June 2007 |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=cut |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
__END__ |