File Coverage

blib/lib/Parse/Tokens.pm
Criterion Covered Total %
statement 152 178 85.3
branch 20 42 47.6
condition 1 3 33.3
subroutine 29 32 90.6
pod 17 19 89.4
total 219 274 79.9


line stmt bran cond sub pod time code
1             package Parse::Tokens;
2              
3             # $Id: Tokens.pm,v 1.5 2001/11/28 01:14:55 steve Exp $
4              
5             # Copyright 2000-2001 by Steve McKay. All rights reserved.
6             # This library is free software; you can redistribute it and/or
7             # modify it under the same terms as Perl itself.
8              
9 1     1   571 use strict;
  1         2  
  1         27  
10 1     1   5 use vars qw( $VERSION );
  1         2  
  1         156  
11              
12             $VERSION = 0.27;
13              
14             sub new
15             {
16 1     1 1 65 my ( $proto, $params ) = @_;
17 1   33     6 my $class = ref($proto) || $proto;
18 1         12 my $self = {
19             debug => undef,
20             text => undef,
21             autoflush => undef,
22             loose_paring => undef,
23             pre_callback => undef,
24             post_callback => undef,
25             token_callback => undef,
26             ether_callback => undef,
27             delimiters => [],
28             delim_index => {},
29             };
30 1         3 bless( $self, $class );
31 1         4 $self->init( $params );
32 1         3 $self;
33             }
34              
35             sub init
36             {
37 2     2 0 5 my( $self, @args ) = @_;
38 1     1   5 no strict 'refs';
  1         11  
  1         66  
39 2         6 $self->_msg( "Processing initialization arguments." );
40 2         1 for ( keys %{$args[0]} )
  2         9  
41             {
42 0         0 my $ref = lc $_;
43 0         0 $self->$ref( $args[0]->{$_} );
44             }
45 1     1   4 use strict;
  1         1  
  1         1124  
46             }
47              
48             sub debug
49             {
50 0     0 1 0 my( $self, @args ) = @_;
51 0         0 $self->_msg( "Storing 'debug' prefs." );
52 0 0       0 $self->{'debug'} = $args[0] if defined $args[0];
53 0         0 return $self->{'debug'};
54             }
55              
56             sub token_callback
57             {
58 1     1 1 2 my( $self, @args ) = @_;
59 1         3 $self->_msg( "Storing 'token_callback' prefs." );
60 1 50       3 $self->{'token_callback'} = $args[0] if defined $args[0];
61 1         3 return $self->{'token_callback'};
62             }
63              
64             sub ether_callback
65             {
66 1     1 1 2 my( $self, @args ) = @_;
67 1         3 $self->_msg( "Storing 'ether_callback' prefs." );
68 1 50       8 $self->{'ether_callback'} = $args[0] if defined $args[0];
69 1         4 return $self->{'ether_callback'};
70             }
71              
72             sub pre_callback
73             {
74 1     1 1 2 my( $self, @args ) = @_;
75 1         4 $self->_msg( "Storing 'pre_callback' prefs." );
76 1 50       4 $self->{'pre_callback'} = $args[0] if defined $args[0];
77 1         2 return $self->{'pre_callback'};
78             }
79              
80             sub post_callback
81             {
82 1     1 1 2 my( $self, @args ) = @_;
83 1         3 $self->_msg( "Storing 'post_callback' prefs." );
84 1 50       3 $self->{'post_callback'} = $args[0] if defined $args[0];
85 1         3 return $self->{'post_callback'};
86             }
87              
88             sub loose_paring
89             {
90 0     0 1 0 my( $self, @args ) = @_;
91 0         0 $self->_msg( "Storing 'loose_paring' prefs." );
92 0 0       0 $self->{'loose_paring'} = $args[0] if defined $args[0];
93 0         0 return $self->{'loose_paring'};
94             }
95              
96             sub autoflush
97             {
98 0     0 1 0 my( $self, @args ) = @_;
99 0         0 $self->_msg( "Storing 'autoflush' prefs." );
100 0 0       0 $self->{'autoflush'} = $args[0] if defined $args[0];
101 0         0 return $self->{'autoflush'};
102             }
103              
104             sub text
105             {
106 1     1 1 3 my( $self, @args ) = @_;
107 1         2 $self->_msg( "Storing 'text'." );
108 1         3 $self->flush();
109 1 50       5 $self->{'text'} = $args[0] if defined $args[0];
110 1         3 return $self->{'text'};
111             }
112              
113             sub delimiters
114             {
115 2     2 1 22 my( $self, @args ) = @_;
116             # we currently support both a ref to an array of delims
117             # as well as an ref to an array of array refs with delims
118 2 100       6 if ( ref($args[0]) eq 'ARRAY' )
119             {
120             # wipe our existing delimiters
121 1         3 $self->{'delimiters'} = [];
122             # we have multiple arrays
123 1 50       6 if( ref($args[0]->[0]) eq 'ARRAY' )
124             {
125 1         2 for( @{$args[0]} )
  1         6  
126             {
127 1         4 $self->push_delimiters( $_ );
128             }
129             }
130             # we have only this array ref
131             else
132             {
133 0         0 $self->push_delimiters( $args[0] );
134             }
135             }
136 2         26 return @{$self->{'delimiters'}};
  2         9  
137             }
138              
139             *add_delimiters = \&push_delimiters;
140             sub push_delimiters
141             {
142             # add a delim pair (real and quoted) to the delimiters array
143 1     1 1 4 my( $self, @args ) = @_;
144 1         2 $self->_msg( "Adding delimiter pair." );
145 1 50       4 if( ref($args[0]) eq 'ARRAY' )
146             {
147 1         7 push(
148 1         2 @{$self->{'delimiters'}}, {
149             real => $args[0],
150             quoted => [
151             quotemeta($args[0]->[0]),
152             quotemeta($args[0]->[1])
153             ]
154             }
155             );
156 1         1 $self->{'delim_index'}->{$args[0]->[0]} = $#{$self->{delimiters}};
  1         3  
157 1         2 $self->{'delim_index'}->{$args[0]->[1]} = $#{$self->{delimiters}};
  1         4  
158             }
159             else
160             {
161 0         0 warn "Args to push_delimiter not an array reference";
162             }
163 1         4 return 1;
164             }
165              
166             sub flush
167             {
168 1     1 1 2 my( $self ) = @_;
169 1         2 $self->_msg( "Flushing cached parts." );
170 1         2 delete $self->{'cache'};
171 1         1 return 1;
172             }
173              
174             sub parse
175             {
176 1     1 1 3 my( $self, @args ) = @_;
177 1         3 $self->pre_parse();
178 1         8 $self->init( $args[0] );
179 1 50       4 return unless defined $self->{'text'};
180 1 50       3 $self->flush() if $self->{'autoflush'};
181              
182 1         2 my @delim = $self->delimiters();
183 1         4 my $match_rex = $self->match_expression( \@delim );
184              
185 1 50       7 unless( $self->{'cache'} )
186             {
187             # parse the text
188 1         3 $self->_msg( "Data not cached. Parsing text." );
189 1         27 my @chunk = split( m/$match_rex/s, $self->{'text'} );
190 1         3 @{$self->{'cache'}} = @chunk;
  1         4  
191             }
192              
193 1         3 $self->_msg( "Processing parsed text parts." );
194 1         1 my $n = 0;
195 1         3 while ($n <= $#{$self->{'cache'}})
  4         10  
196             {
197             # find opening delimiter
198            
199             # if the first element of the token is the element of a token
200             #if ( $self->{cache}->[$n] eq $delim[0]->{real}->[0] || $self->{cache}->[$n] eq $delim[1]->{real}->[0] )
201 3 100       14 if ( $self->{'cache'}->[$n] eq $delim[$self->{'delim_index'}->{$self->{'cache'}->[$n]}]->{'real'}->[0] )
202             {
203 1         3 $self->_msg( "Dispatching token." );
204 1         6 $self->token([
205             $self->{'cache'}->[$n],
206             $self->{'cache'}->[++$n],
207             $self->{'cache'}->[++$n]
208             ]);
209             }
210              
211             # or it's just text
212             else
213             {
214 2         4 $self->_msg( "Dispatching text." );
215 2         17 $self->ether( $self->{'cache'}->[$n] );
216             }
217 3         6 $n++
218             }
219 1         5 $self->post_parse();
220             }
221              
222             sub match_expression
223             {
224             # construct our token finding regular expression
225 1     1 0 1 my( $self, $delim ) = @_;
226 1         2 my $rex;
227 1 50       3 if( $self->{'loose_paring'} )
228             {
229 0         0 my( @left, @right );
230 0         0 for( @$delim )
231             {
232 0         0 push( @left, $_->{'quoted'}->[0] );
233 0         0 push( @right, $_->{'quoted'}->[1] );
234             }
235 0         0 $rex = '('.join('|', @left).')(.*?)('.join('|', @right).')';
236             }
237             else
238             {
239 1         1 my( @sets );
240 1         3 for( @$delim )
241             {
242 1         5 push( @sets, qq{($_->{'quoted'}->[0])(.*?)($_->{'quoted'}->[1])} );
243             }
244 1         4 $rex = join( '|', @sets );
245             }
246 1         4 $self->_msg( "Constructed '$rex' pattern matching expression." );
247 1         3 $self->{'match_expression'} = $rex;
248 1         3 return $rex;
249             }
250              
251             # a token consists of a left-delimiter, the contents, and a right-delimiter
252             *atom = \&token;
253             sub token
254             {
255 1     1 1 2 my( $self, $token ) = @_;
256 1         5 $self->_msg( "Found token ", join( ', ', @$token ) );
257 1 50       10 if( $self->{'token_callback'} )
258             {
259 1         10 $self->_msg( "Dispatching token to callback handler '$self->{'token_callback'}'." );
260 1     1   6 no strict 'refs';
  1         1  
  1         40  
261 1         1 &{$self->{'token_callback'}}( $token );
  1         4  
262 1     1   4 use strict;
  1         1  
  1         104  
263             }
264             else
265             {
266 0         0 $self->_msg( "Consider overriding my 'token' method." );
267             }
268 1         5 return 1;
269             }
270              
271             # ether is anything not contained in an atom
272             sub ether
273             {
274 2     2 1 4 my( $self, $text ) = @_;
275 2         4 $self->_msg( "Found text ", $text );
276 2 50       6 if( $self->{'ether_callback'} )
277             {
278 2         8 $self->_msg( "Dispatching text to callback handler '$self->{'ether_callback'}'." );
279 1     1   4 no strict 'refs';
  1         2  
  1         46  
280 2         3 &{$self->{'ether_callback'}}( $text );
  2         7  
281 1     1   4 use strict;
  1         7  
  1         82  
282             }
283             else {
284 0         0 $self->_msg( "Consider overriding my 'ether' method." );
285             }
286 2         45 return 1;
287             }
288              
289             # this is called just before parsing begins
290             sub pre_parse
291             {
292 1     1 1 2 my( $self ) = @_;
293 1 50       3 if( $self->{'pre_callback'} )
294             {
295 1         5 $self->_msg( "Dispatching pre_parse event to callback handler '$self->{'pre_callback'}'." );
296 1     1   4 no strict 'refs';
  1         1  
  1         30  
297 1         1 &{$self->{'pre_callback'}}();
  1         4  
298 1     1   4 use strict;
  1         1  
  1         85  
299             }
300             else
301             {
302 0         0 $self->_msg( "Consider overriding my 'pre_parse' method." );
303             }
304 1         8 return 1;
305             }
306              
307              
308             # this is called just after parsing ends
309             sub post_parse
310             {
311 1     1 1 2 my( $self ) = @_;
312 1 50       3 if( $self->{'post_callback'} )
313             {
314 1         4 $self->_msg( "Dispatching post_parse event to callback handler '$self->{'post_callback'}'." );
315 1     1   4 no strict 'refs';
  1         1  
  1         28  
316 1         2 &{$self->{'post_callback'}}();
  1         12  
317 1     1   4 use strict;
  1         2  
  1         90  
318             }
319             else
320             {
321 0         0 $self->_msg( "Consider overriding my 'post_parse' method." );
322             }
323 1         5 return 1;
324             }
325              
326             sub _msg
327             {
328 23     23   35 my( $self, @msg ) = @_;
329 23 50       59 if( $self->{'debug'} )
330             {
331 0         0 warn __PACKAGE__, ' - ', @msg;
332             }
333 23         30 return 1;
334             }
335              
336             1;
337              
338             __END__