File Coverage

blib/lib/String/Substitution.pm
Criterion Covered Total %
statement 40 40 100.0
branch 10 10 100.0
condition 2 3 66.6
subroutine 16 16 100.0
pod 8 8 100.0
total 76 77 98.7


line stmt bran cond sub pod time code
1             # vim: set ts=2 sts=2 sw=2 expandtab smarttab:
2             #
3             # This file is part of String-Substitution
4             #
5             # This software is copyright (c) 2010 by Randy Stauner.
6             #
7             # This is free software; you can redistribute it and/or modify it under
8             # the same terms as the Perl 5 programming language system itself.
9             #
10 2     2   35538 use strict;
  2         4  
  2         100  
11 2     2   12 use warnings;
  2         4  
  2         106  
12              
13             package String::Substitution;
14             BEGIN {
15 2     2   46 $String::Substitution::VERSION = '1.001';
16             }
17             BEGIN {
18 2     2   44 $String::Substitution::AUTHORITY = 'cpan:RWSTAUNER';
19             }
20             # ABSTRACT: Simple runtime string substitution functions
21              
22 2     2   2110 use Sub::Exporter 0.982;
  2         72910  
  2         13  
23             {
24             my $exports = {
25             exports => [qw(interpolate_match_vars last_match_vars)],
26             groups => {}
27             };
28             my @funcs = qw(sub gsub);
29             foreach my $suffix ( qw(copy modify context) ){
30             push(@{ $exports->{exports} }, map { "${_}_${suffix}" } @funcs);
31             $exports->{groups}->{$suffix} = [
32             map { ("${_}_${suffix}" => { -as => $_ }) } @funcs
33             ];
34             }
35             Sub::Exporter::setup_exporter($exports);
36             }
37              
38              
39             sub gsub_copy {
40 170     170 1 143343 my ($string, $pattern, $replacement) = @_;
41 170         1802 $string =~ s/$pattern/
42 162         445 _replacement_sub($replacement)->(last_match_vars());/ge;
43 170         1407 return $string;
44             }
45              
46              
47             sub gsub_modify {
48 170     170 1 135847 my ( undef, $pattern, $replacement ) = @_;
49 170         1427 return $_[0] =~ s/$pattern/
50 162         480 _replacement_sub($replacement)->(last_match_vars());/ge;
51             }
52              
53              
54             sub gsub_context {
55             return defined wantarray
56 170 100   170 1 298908 ? gsub_copy(@_)
57             : gsub_modify(@_);
58             }
59              
60              
61             sub interpolate_match_vars {
62 512     512 1 1443 my ($replacement, @matched) = @_;
63 512         1766 my $string = $replacement;
64             # Handling backslash-escapes and variable interpolations
65             # in the same substitution (alternation) keeps track of the position
66             # in the string so that we don't have to count backslashes.
67 512         5505 $string =~
68             s/
69             (?:
70             \\(.) # grab escaped characters (including $)
71             |
72             (?:
73             \$\{([1-9]\d*)\} # match "${1}" (not unrelated '${0}')
74             |
75             \$ ([1-9]\d*) # match "$1" (not unrelated '$0')
76             )
77             )
78             /
79 824 100 66     6600 defined $1
80             ? $1 # if something was escaped drop the \\
81             : $matched[$2 || $3]; # else use braced or unbraced number
82             # ($2 will never contain '0')
83             /xge;
84 512         3672 return $string;
85             }
86              
87              
88             sub last_match_vars {
89 2     2   1516 no strict 'refs'; ## no critic
  2         5  
  2         5175  
90             return (
91             # fake $& with a substr to avoid performance penalty (see perlvar)
92             #(@_ ? substr($_[0], $-[0], $+[0] - $-[0]) : undef),
93             undef,
94             # $1, $2 ..
95 648 100   648 1 2717 map { ($$_) || '' } ( 1 .. $#- )
  824         6948  
96             );
97             }
98              
99             # Return a sub that will get matched vars array passed to it
100              
101             sub _replacement_sub {
102 648     648   968 my ($rep) = @_;
103             # if $rep is not a sub, assume it's a string to be interpolated
104             ref $rep
105             ? $rep
106 648 100   512   5685 : sub { interpolate_match_vars($rep, @_); };
  512         1217  
107             }
108              
109              
110             sub sub_copy {
111 192     192 1 5410 my ($string, $pattern, $replacement) = @_;
112 192         1717 $string =~ s/$pattern/
113 162         371 _replacement_sub($replacement)->(last_match_vars());/e;
114 192         1623 return $string;
115             }
116              
117              
118             sub sub_modify {
119 192     192 1 130437 my ( undef, $pattern, $replacement ) = @_;
120 192         8907 return $_[0] =~ s/$pattern/
121 162         414 _replacement_sub($replacement)->(last_match_vars());/e;
122             }
123              
124              
125             sub sub_context {
126             return defined wantarray
127 192 100   192 1 190094 ? sub_copy(@_)
128             : sub_modify(@_);
129             }
130              
131             1;
132              
133              
134              
135             __END__