File Coverage

blib/lib/Template/Plugin/Subst.pm
Criterion Covered Total %
statement 47 47 100.0
branch 12 12 100.0
condition n/a
subroutine 8 8 100.0
pod 1 3 33.3
total 68 70 97.1


line stmt bran cond sub pod time code
1             package Template::Plugin::Subst;
2              
3             # Copyright (c) 2005 Nik Clayton
4             # All rights reserved.
5             #
6             # Redistribution and use in source and binary forms, with or without
7             # modification, are permitted provided that the following conditions
8             # are met:
9             # 1. Redistributions of source code must retain the above copyright
10             # notice, this list of conditions and the following disclaimer.
11             # 2. Redistributions in binary form must reproduce the above copyright
12             # notice, this list of conditions and the following disclaimer in the
13             # documentation and/or other materials provided with the distribution.
14             #
15             # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16             # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18             # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19             # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20             # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21             # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22             # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23             # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24             # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25             # SUCH DAMAGE.
26              
27 3     3   460884 use warnings;
  3         8  
  3         101  
28 3     3   15 use strict;
  3         7  
  3         173  
29              
30 3     3   2717 use Template::Plugin::Filter;
  3         10948  
  3         96  
31 3     3   21 use base qw(Template::Plugin::Filter);
  3         7  
  3         207  
32              
33 3     3   80172 use Template::Stash;
  3         111684  
  3         1529  
34              
35             $Template::Stash::SCALAR_OPS->{subst} = \&subst;
36              
37             =head1 NAME
38              
39             Template::Plugin::Subst - s/// functionality for Template Toolkit templates
40              
41             =head1 VERSION
42              
43             Version 0.02
44              
45             =cut
46              
47             our $VERSION = '0.02';
48              
49             sub init {
50 23     23 0 100230 my $self = shift;
51              
52 23         75 $self->{_DYNAMIC} = 1;
53              
54 23         61 return $self;
55             }
56              
57             sub filter {
58 12     12 1 1425 my($self, $text, $args, $config) = @_;
59              
60 12         44 $config = $self->merge_config($config);
61              
62 12         117 my $pattern = $config->{pattern};
63 12         20 my $replacement = $config->{replacement};
64 12 100       33 my $global = defined $config->{global} ? $config->{global} : 1;
65              
66             # warn "pattern: $pattern, replacement: $replacement\n";
67 12         44 $text = subst($text, $pattern, $replacement, $global);
68              
69 12         201 return $text;
70             }
71              
72             sub subst {
73 32     32 0 515 my($text, $pattern, $replacement, $global) = @_;
74              
75 32 100       82 $global = defined $global ? $global : 1;
76              
77             # warn "-> subst() ('$pattern', '$replacement')\n";
78 32 100       367 if($text !~ m/$pattern/) {
79             # warn "text does not match '$pattern', returning";
80 7         44 return $text;
81             }
82              
83             # If there are no subgroups then it's a simple search/replace
84 25 100       107 if($#- == 0) {
85             # warn "No subgroups found, doing simple search/replace\n";
86 14 100       36 if($global) {
87 12         111 $text =~ s/$pattern/$replacement/g;
88             } else {
89 2         31 $text =~ s/$pattern/$replacement/;
90             }
91 14         63 return $text;
92             }
93              
94             # First, save the original text, and what was matched
95 11         19 my $saved_text = $text;
96 11         44 my $PREMATCH = substr($saved_text, 0, $-[0]);
97 11         61 my $MATCHED = substr($saved_text, $-[0], $+[0] - $-[0]);
98 11         35 my $POSTMATCH = substr($saved_text, $+[0]);
99              
100             # Save the positions where we matched
101 11         46 my @saved_match_start = @-;
102 11         40 my @saved_match_end = @+;
103            
104             # warn "PREMATCH : <<$PREMATCH>>";
105             # warn "MATCHED : <<$MATCHED>>";
106             # warn "POSTMATCH: <<$POSTMATCH>>";
107              
108             # Now do the s///. This will leave placeholders (literally, '$1', '$2',
109             # etc, in the replaced text.
110             # warn "Doing s///";
111 11         121 $MATCHED =~ s/$pattern/$replacement/;
112             # warn "MATCHED: <<$MATCHED>>";
113              
114 11         40 foreach my $i (1..$#saved_match_start) {
115 16         42 my $backref = substr($saved_text,
116             $saved_match_start[$i],
117             $saved_match_end[$i] - $saved_match_start[$i]);
118 16         199 $MATCHED =~ s/\$$i/$backref/g;
119             }
120              
121             # warn "Fixed up backrefs";
122             # warn "MATCHED: <<$MATCHED>>";
123              
124 11 100       33 if($global) {
125 9         44 return $PREMATCH . $MATCHED . subst($POSTMATCH, $pattern, $replacement);
126             } else {
127 2         13 return $PREMATCH . $MATCHED . $POSTMATCH;
128             }
129             }
130              
131             =head1 SYNOPSIS
132              
133             =head2 As a vemthod
134              
135             [% USE Subst %]
136              
137             [% str = 'foobar' %]
138              
139             [% str.subst('(foo)(bar)', '$2$1', 1) %]
140              
141             =head2 As a filter
142              
143             [% USE filt = Subst
144             pattern = '(foo)(bar)'
145             replacement = '$2$1'
146             global = 1 %]
147              
148             Then
149              
150             [% text | $filt %]
151              
152             or
153              
154             [% FILTER $filt %]
155             foobar
156             [% END %]
157              
158             =head1 DESCRIPTION
159              
160             Template::Plugin::Subst acts as a filter and a virtual method to carry
161             out regular expression substitutions with back references on text and
162             variables in the Template Toolkit.
163              
164             That's the advantage of this approach over the built-in C
165             method. C doesn't deal with backrefs, so code like this:
166              
167             [% str = 'foobar' %]
168             [% str.replace('(foo)(bar)', '$2$1') %]
169              
170             inserts a literal C<$2$1> in to your document.
171              
172             But with Template::Plugin::Subst;
173              
174             [% USE Subst %]
175             [% str = 'foobar' %]
176             [% str.subst('(foo)(bar)', '$2$1') %]
177              
178             you get the expected C.
179              
180             It can also be used as a filter, in which case it's very useful for finding
181             information in text and augmenting it in a useful fashion.
182              
183             For example, suppose you want all strings of the form C, which
184             reference RT ticket numbers, to be converted to links to your local
185             RT installation.
186              
187             First, instatiate the filter:
188              
189             [% USE rt = Subst
190             pattern = 'rt#(\d+)'
191             replacement = 'rt#$1' %]
192              
193             and then use it to filter arbitrary text:
194              
195             [% text_variable | $rt %]
196              
197             =head1 OPTIONS
198              
199             =head2 vmethod
200              
201             .subst($pattern, $replacement[, $global])
202              
203             As a vmethod the first two arguments are the pattern to search for and
204             the string to replace it with. These arguments are mandatory.
205              
206             The third argument is a boolean that specifies whether or the
207             search/replace should be global, and behaves in the same way as the C
208             modifier on a C operation. The default value is '1'. Note that
209             this differs from the default setting on the C operator.
210              
211             =head2 Filter
212              
213             [% USE filt = Subst
214             pattern = '...'
215             replacement = '...'
216             global = 1 %]
217              
218             These three named arguments have the same semantics as the arguments to
219             the vmethod. C is optional, and defaults to 1.
220              
221             =head1 AUTHOR
222              
223             Nik Clayton, C<< >>
224              
225             =head1 BUGS
226              
227             Please report any bugs or feature requests to
228             C, or through the web interface at
229             L.
230             I will be notified, and then you'll automatically be notified of progress on
231             your bug as I make changes.
232              
233             =head1 COPYRIGHT & LICENSE
234              
235             Copyright (c) 2005 Nik Clayton
236             All rights reserved.
237              
238             Redistribution and use in source and binary forms, with or without
239             modification, are permitted provided that the following conditions
240             are met:
241              
242             1. Redistributions of source code must retain the above copyright
243             notice, this list of conditions and the following disclaimer.
244             2. Redistributions in binary form must reproduce the above copyright
245             notice, this list of conditions and the following disclaimer in the
246             documentation and/or other materials provided with the distribution.
247              
248             THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
249             ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
250             IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251             ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
252             FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
253             DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
254             OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
255             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
256             LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257             OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
258             SUCH DAMAGE.
259              
260             =cut
261              
262             1; # End of Template::Plugin::Subst