File Coverage

blib/lib/String/Expand.pm
Criterion Covered Total %
statement 40 41 97.5
branch 15 16 93.7
condition n/a
subroutine 9 9 100.0
pod 2 5 40.0
total 66 71 92.9


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2006,2007,2009 -- leonerd@leonerd.org.uk
5              
6             package String::Expand;
7              
8 3     3   77806 use strict;
  3         7  
  3         112  
9 3     3   18 use warnings;
  3         5  
  3         100  
10              
11 3     3   26 use Exporter;
  3         13  
  3         287  
12             our @ISA = qw( Exporter );
13             our @EXPORT = qw(
14             expand_string
15             expand_strings
16             );
17              
18 3     3   19 use Carp;
  3         7  
  3         2290  
19              
20             our $VERSION = '0.04';
21              
22             my $VARNAME_MATCH = qr/\$([A-Z_][A-Z0-9_]*|\{.*?\})/;
23              
24             =head1 NAME
25              
26             C - string utility functions for expanding variables in
27             self-referential sets
28              
29             =head1 SYNOPSIS
30              
31             use String::Expand qw( expand_strings );
32              
33             my %vars = ( MESSAGE => 'My home is $HOME',
34             TEXT => 'Message is "$MESSAGE"' );
35              
36             expand_strings( \%vars, \%ENV );
37              
38             # %vars now contains something like:
39             # MESSAGE => 'My home is /home/user',
40             # TEXT => 'Message is "My home is /home/user"'
41              
42             =head1 DESCRIPTION
43              
44             This module implements utility functions for expanding embedded variables in a
45             string. Variable references are embedded in strings in a similar form to the
46             Bourne shell, namely, in the form C<$NAME> or C<${NAME}>. In the former case,
47             the C must consist of a capital letter or underscore, and may be
48             followed by zero or more capital letters, digits or underscores. In the latter
49             case, the name can consist of any characters, but will be terminated by the
50             first close brace character C<'}'>.
51              
52             The string may also contain literal dollar marks, escaped by C<\$>, and
53             literal escape marks, escaped by C<\\>. These will be converted to C<$> and
54             C<\> respectively on return.
55              
56             While there are many other modules that also provide expansion such as this,
57             this module provides the function C, which will perform
58             variable expansions in all the values in a given hash, where values can refer
59             to other values within the same hash.
60              
61             =cut
62              
63             =head1 FUNCTIONS
64              
65             =cut
66              
67             sub expand_one_var($$)
68             {
69 5     5 0 12 my ( $var, $vars ) = @_;
70              
71             # Chop off delimiting {braces} if present
72 5         19 $var =~ s/^\{(.*)\}$/$1/;
73              
74 5 100       19 unless( defined $vars->{$var} ) {
75 1         29 croak "Unknown variable '$var'";
76             }
77              
78 4         21 return $vars->{$var};
79             }
80              
81             =head2 $expanded = expand_string( $str, \%vars )
82              
83             This function expands embedded variable references in the passed string, and
84             returns the expanded copy.
85              
86             =over 8
87              
88             =item $str
89              
90             A string possibly containing variable expansions
91              
92             =item \%vars
93              
94             Reference to a hash containing variable values
95              
96             =item Returns
97              
98             A string with variables expanded
99              
100             =back
101              
102             =cut
103              
104             sub expand_string($$)
105             {
106 7     7 1 4252 my ( $str, $vars ) = @_;
107              
108 7         120 $str =~ s{\\([\\\$])|$VARNAME_MATCH}
109 8 100       49 { $1 or expand_one_var( $2, $vars )}eg;
110              
111 6         24 return $str;
112             }
113              
114             sub expand_strings_inner($$$$);
115              
116             sub expand_strings_one_var($$$$)
117             {
118 8     8 0 18 my ( $var, $strs, $overlay, $done ) = @_;
119              
120             # Chop off delimiting {braces} if present
121 8         31 $var =~ s/^\{(.*)\}$/$1/;
122              
123 8 100       26 if( exists $strs->{$var} ) {
124 5 100       20 return $strs->{$var} if( $done->{$var} );
125             # Detect loops
126 4 100       10 if( exists $done->{$var} ) {
127 1         29 croak "Variable loop trying to expand '$var'";
128             }
129 3         5 $done->{$var} = 0;
130 3         8 expand_strings_inner( $strs, $overlay, $var, $done );
131 2         10 return $strs->{$var};
132             }
133              
134 3 50       24 return $overlay->{$var} if( exists $overlay->{$var} );
135            
136 0         0 croak "Unknown variable '$var'";
137             }
138              
139             sub expand_strings_inner($$$$)
140             {
141 17     17 0 31 my ( $strs, $overlay, $v, $done ) = @_;
142            
143 17 100       63 if( $strs->{$v} =~ m/[\\\$]/ ) {
144 11         145 $strs->{$v} =~ s{\\([\\\$])|$VARNAME_MATCH}
145 12 100       58 { $1 or expand_strings_one_var( $2, $strs, $overlay, $done )}eg;
146             }
147              
148 15         58 $done->{$v} = 1;
149             }
150              
151             =head2 expand_strings( \%strs, \%overlay )
152              
153             This function takes a hash of strings, and expands variable names embedded in
154             any of them, in the same form as the string passed to C.
155             Expansions may refer to other strings, or to values in the C>
156             hash. Values in the main variables hash take precidence over values in the
157             overlay.
158              
159             Where values refer to other values, care must be taken to avoid cycles. If a
160             cycle is detected while attempting to expand the values, then an exception is
161             thrown.
162              
163             =over 8
164              
165             =item \%strs
166              
167             Reference to a hash containing variables to expand
168              
169             =item \%overlay
170              
171             Reference to a hash containing other variable values
172              
173             =item Returns
174              
175             Nothing
176              
177             =back
178              
179             =cut
180              
181             sub expand_strings($$)
182             {
183 7     7 1 4545 my ( $strs, $overlay ) = @_;
184              
185             # 0: a variable expansion is in progress
186             # 1: value has been correctly expanded
187 7         9 my %done;
188              
189 7         49 foreach my $v ( keys %$strs ) {
190 14         31 expand_strings_inner( $strs, $overlay, $v, \%done );
191             }
192             }
193              
194             # Keep perl happy; keep Britain tidy
195             1;
196              
197             __END__