File Coverage

blib/lib/List/Filter/Transform/Internal.pm
Criterion Covered Total %
statement 69 80 86.2
branch 8 14 57.1
condition 2 6 33.3
subroutine 11 12 91.6
pod 5 5 100.0
total 95 117 81.2


line stmt bran cond sub pod time code
1             package List::Filter::Transform::Internal;
2 3     3   58416 use base qw( Class::Base );
  3         7  
  3         1617  
3              
4             =head1 NAME
5              
6             List::Filter::Transform::Internal - common operations used by transform methods
7              
8             =head1 SYNOPSIS
9              
10             # using as a utility object
11             use List::Filter::Transform::Internal;
12             my $lftu = List::Filter::Transform::Internal->new();
13             $term = [ qr{ slimey \s+ boss }x, 'g', 'professional management' ];
14             $changed_item = $lftu->substitute( $item, $term );
15              
16              
17             # one way of setting override_modifiers attribute (case insensitve, "i")
18             my $lftu = List::Filter::Transform::Internal->new( {override_modifiers => 'i' } );
19              
20             # another way of setting override_modifiers (extended regexps, "x"):
21             $lftu->set_override_modifiers( 'x' );
22              
23              
24             # this can be inherited from (deprecated):
25             use base ("List::Filter::Transform::Internal");
26             my $changed = $self->substitute( $item, $term );
27              
28              
29             =head1 DESCRIPTION
30              
31             List::Filter::Transform::Internal is at present a class of utility
32             object, used by the List::Filter::Transforms::* modules,
33             which contain "methods" that are exported to the Dispatcher
34             namespace ultimately.
35              
36             At present, there is only one object attribute that's important:
37             "override_modifiers"
38             which is used by the "substitute" method.
39              
40             =head2 METHODS
41              
42             =over
43              
44             =cut
45              
46 3     3   1960 use 5.8.0;
  3         13  
  3         148  
47 3     3   15 use strict;
  3         6  
  3         87  
48 3     3   17 use warnings;
  3         8  
  3         121  
49             my $DEBUG = 0;
50 3     3   15 use Carp;
  3         7  
  3         282  
51 3     3   15 use Data::Dumper;
  3         6  
  3         269  
52 3     3   2257 use Hash::Util qw(lock_keys unlock_keys);
  3         3913  
  3         127  
53              
54             our $VERSION = '0.01';
55              
56             =item new
57              
58             Instantiates a new List::Filter::Transforms::* object.
59              
60             Takes an optional hashref as an argument, with named fields
61             identical to the names of the object attributes.
62              
63             With no arguments, the newly created filter will be empty.
64              
65             =cut
66              
67             # Note:
68             # "new" is inherited from Class::Base.
69             # It calls the following "init" routine automatically.
70              
71             =item init
72              
73             Initialize object attributes and then lock them down to prevent
74             accidental creation of new ones.
75              
76             Note: there is no leading underscore on name "init", though it's
77             arguably an "internal" routine (i.e. not likely to be of use to
78             client code).
79              
80             =cut
81              
82             sub init {
83 2     2 1 1595 my $self = shift;
84 2         5 my $args = shift;
85 2         3 unlock_keys( %{ $self } );
  2         13  
86              
87             # define new attributes
88             my $attributes = {
89             override_modifiers => $args->{ override_modifiers },
90 2         17 };
91              
92             # add attributes to object
93 2         4 my @fields = (keys %{ $attributes });
  2         8  
94 2         15 @{ $self }{ @fields } = @{ $attributes }{ @fields }; # hash slice
  2         3  
  2         4  
95              
96 2         3 lock_keys( %{ $self } );
  2         7  
97 2         21 return $self;
98             }
99              
100              
101             =back
102              
103             =head2 methods internally used by transforms
104              
105             =over
106              
107             =item substitute
108              
109             Performs a perl s/// on the given string, building up the the
110             substitution from three parts supplied in a an array ref:
111              
112             (1) a perl regular expression, qr{}; (2) any external match
113             modifiers (e.g. "g", "e"); (3) the replacement string (or
114             expression, if the 'e' modifier is in use).
115              
116             Some attempt has been made to avoid re-compiling the regular
117             expressions if there's no need to. To take advantage of this, if
118             at all possible, the "ismx" modifiers should be applied when
119             creating the regexp. The "g" and "e" modififiers are the only ones
120             that need to be applied externally. The "o" modifier is silently ignored.
121              
122             Inputs:
123             (1) the string to be modified
124             (2) a "transform term" (aref, three parts),
125              
126             Returns: the modified string
127              
128             Example:
129             $term = [ qr{ slimey \s+ boss }x, 'g', 'professional management' ];
130             $self->set_override_modifiers( 'x' );
131             $fixed_item = $self->substitute( $item, $term );
132              
133             =cut
134              
135             sub substitute {
136 2     2 1 1185 my $self = shift;
137 2         3 my $item = shift;
138 2         4 my $term = shift;
139              
140 2         6 my $override_modifiers = $self->override_modifiers;
141              
142 2         5 my $regexp = $term->[0];
143 2         2 my $replace = $term->[2];
144 2   33     6 my $mods = $term->[1] || $override_modifiers;
145              
146 2 50       5 if ($mods) { # just skip this stuff if there aren't any
147              
148             # Note: perl s/// mods are "egimosx", but only "imsx" are regexp attributes
149              
150             # extract modifiers that can be applied internally to the regexp
151 2         6 my @internal = qw( i m s x );
152 2         3 my $re_mods = '';
153 2         13 foreach my $c (@internal) {
154 8 100       77 if ( $mods =~ m/$c/ ) {
155 4         10 $re_mods .= $c;
156             }
157             }
158             # prepend internal mods to regexp in (?imsx) form
159 2 50       8 if ($re_mods) { # don't mess with precompiled regexp if we don't need to
160 2         6 $regexp = $self->mod_regexp( $regexp, $re_mods );
161             }
162              
163             # silently ignore 'o' if present
164 2         4 $mods =~ s/o//;
165              
166             # two valid posibilites remain: g and e, so we cover all 4 permutations:
167 2         4 my $g_flag = ($mods =~ m/g/);
168 2         3 my $e_flag = ($mods =~ m/e/);
169              
170 2 50 33     16 if ($g_flag && $e_flag) {
    50          
    50          
171 0         0 $item =~ s{$regexp}{$replace}ge;
  0         0  
172             } elsif ($g_flag) {
173 0         0 $item =~ s{$regexp}{$replace}g;
174             } elsif ($e_flag) {
175 0         0 $item =~ s{$regexp}{$replace}e;
  0         0  
176             } else {
177 2         12 $item =~ s{$regexp}{$replace};
178             }
179             } else { # no late modifiers, so do the simplest (fastest) thing
180 0         0 $item =~ s{$regexp}{$replace};
181             }
182 2         8 return $item;
183             }
184              
185             =item mod_regexp
186              
187             Given a qr{} value and a set of modifiers (any of xism),
188             returns a qr{} value with those modifiers applied.
189              
190             Inputs:
191             (1) qr{}
192             (2) string: some sub-set of "xism"
193              
194             Return: qr{}
195              
196             (This is an inheritable "method", though it makes no use of
197             object or class data.)
198              
199             =cut
200              
201             sub mod_regexp {
202 2     2 1 3 my $self = shift;
203 2         3 my $regexp = shift;
204 2         3 my $mods = shift;
205              
206 2         30 $self->debug("mod_regexp in Transforms.pm:\n");
207              
208             # Strip the "(?-xism:" and ")" from a qr{} value. They look like:
209             # qr/(?-xism:bush-league of whirled crime)/;
210              
211 2         19 $self->debug("regexp:>>>", $regexp, "<<<\n");
212              
213 2         9 my $intermed;
214 2 50       11 if (
215             ($intermed = $regexp) =~ s{ ^ \( \? [-xism]*? : }{}x
216             ) {
217 0         0 $intermed =~ s/\)$//; # do the closing paren only if the leading one was stripped
218             }
219              
220 2         5 $self->debug("mods:>>>", $mods, "<<<\n");
221 2         12 $self->debug("intermed:>>>", $intermed, "<<<\n");
222              
223             # generate new regexp with modifiers applied internally
224 2         29 my $new_regexp = qr{(?$mods:$intermed)};
225 2         4 return $new_regexp;
226             }
227              
228             =back
229              
230             =head2 basic setters and getters
231              
232             =over
233              
234             =item override_modifiers
235              
236             Getter for object attribute override_modifiers
237              
238             =cut
239              
240             sub override_modifiers {
241 2     2 1 2 my $self = shift;
242 2         4 my $override_modifiers = $self->{ override_modifiers };
243 2         3 return $override_modifiers;
244             }
245              
246             =item set_override_modifiers
247              
248             Setter for object attribute set_override_modifiers
249              
250             =cut
251              
252             sub set_override_modifiers {
253 0     0 1   my $self = shift;
254 0           my $override_modifiers = shift;
255 0           $self->{ override_modifiers } = $override_modifiers;
256 0           return $override_modifiers;
257             }
258              
259              
260              
261              
262             1;
263              
264             =back
265              
266             =head1 SEE ALSO
267              
268             L
269              
270             =head1 AUTHOR
271              
272             Joseph Brenner, Edoom@kzsu.stanford.eduE
273              
274             =head1 COPYRIGHT AND LICENSE
275              
276             Copyright (C) 2007 by Joseph Brenner
277              
278             This library is free software; you can redistribute it and/or modify
279             it under the same terms as Perl itself, either Perl version 5.8.2 or,
280             at your option, any later version of Perl 5 you may have available.
281              
282             =head1 BUGS
283              
284             None reported... yet.
285              
286             =cut