File Coverage

blib/lib/Text/Same/ChunkedSource.pm
Criterion Covered Total %
statement 95 98 96.9
branch 17 20 85.0
condition 1 3 33.3
subroutine 18 19 94.7
pod 9 9 100.0
total 140 149 93.9


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Text::Same::ChunkedSource
4              
5             =head1 DESCRIPTION
6              
7             Objects of this class represent a source of chunks (generally lines)
8             in a source (generally a file). The "chunks" could potentially be
9             paragraphs or sentences.
10              
11             =head1 SYNOPSIS
12              
13             my $source = new Text::Same::ChunkedSource(chunks->\@chunks)
14              
15             =head1 METHODS
16              
17             See below. Methods private to this module are prefixed by an
18             underscore.
19              
20             =cut
21              
22             package Text::Same::ChunkedSource;
23              
24 4     4   22399 use warnings;
  4         8  
  4         207  
25 4     4   24 use strict;
  4         8  
  4         110  
26 4     4   22 use Carp;
  4         9  
  4         268  
27              
28 4     4   32 use vars qw($VERSION);
  4         8  
  4         379  
29             $VERSION = '0.07';
30              
31 4     4   35 use Digest::MD5 qw(md5);
  4         8  
  4         179  
32              
33 4     4   560 use Text::Same::Util;
  4         8  
  4         4941  
34              
35             =head2 new
36              
37             Title : new
38             Usage : $source = new Text::Same::ChunkedSource(chunks->\@chunks)
39             Function: Creates a new ChunkedSource object from an array
40             Returns : A Text::Same::ChunkedSource object
41             Args : chunks - an array of strings
42              
43             =cut
44              
45             sub new
46             {
47 3     3 1 95 my $arg = shift;
48 3   33     22 my $class = ref($arg) || $arg;
49              
50 3         6 my $self = {};
51              
52 3         12 my %params = @_;
53              
54 3         10 $self->{name} = $params{name};
55 3         7 $self->{all_chunks} = $params{chunks};
56 3         5 $self->{all_chunks_count} = scalar(@{$params{chunks}});
  3         7  
57              
58 3         14 return bless $self, $class;
59             }
60              
61             =head2 name
62              
63             Title : name
64             Usage : my $name = $source->name();
65             Function: return the name of this source - generally the filename
66              
67             =cut
68              
69             sub name
70             {
71 0     0 1 0 my $self = shift;
72 0         0 return $self->{name};
73             }
74              
75             =head2 get_all_chunks
76              
77             Title : get_all_chunks
78             Usage : $all_chunks = $source->get_all_chunks;
79             Function: return (in order) the chunks from this source
80              
81             =cut
82              
83             sub get_all_chunks
84             {
85 148     148 1 645 my $self = shift;
86 148         191 return @{$self->{all_chunks}};
  148         1247  
87             }
88              
89             =head2 get_chunk_by_indx
90              
91             Title : get_chunk_by_indx
92             Usage : $chunk = $source->get_chunk_by_indx($indx);
93             Function: return the chunk/line at the given index in this source
94              
95             =cut
96              
97             sub get_chunk_by_indx
98             {
99 6     6 1 7 my $self = shift;
100 6         9 my $chunk_indx = shift;
101              
102 6         18 return $self->{all_chunks}[$chunk_indx];
103             }
104              
105             =head2 get_all_chunks_count
106              
107             Title : get_all_chunks_count
108             Usage : $count = $source->get_all_chunks_count;
109             Function: return the number of chunks in this source
110              
111             =cut
112              
113             sub get_all_chunks_count
114             {
115 7     7 1 11 my $self = shift;
116 7         35 return $self->{all_chunks_count};
117             }
118              
119             sub _make_chunk_maps
120             {
121 6     6   15 my $self = shift;
122 6         11 my $options = shift;
123              
124 6         493 my @filtered_chunk_indexes = ();
125 6         17 my %filtered_hash = ();
126 6         11 my %real_index_to_filtered_index = ();
127 6         13 my %filtered_index_to_real_index = ();
128              
129 6         13 my $filtered_chunk_count = 0;
130              
131 6         193 for (my $i = 0; $i < scalar(@{$self->{all_chunks}}); $i++) {
  96         342  
132 90         194 my $chunk = $self->{all_chunks}[$i];
133 90 100       755 if (!is_ignorable($options, $chunk)) {
134 80         163 push @filtered_chunk_indexes, $i;
135 80         238 $real_index_to_filtered_index{$i} = $filtered_chunk_count;
136 80         184 $filtered_index_to_real_index{$filtered_chunk_count} = $i;
137              
138 80         116 push @{$filtered_hash{Text::Same::Util::hash($options, $chunk)}}, $i;
  80         255  
139 80         344 $filtered_chunk_count++;
140             }
141             }
142              
143 6         71 return \@filtered_chunk_indexes, \%filtered_hash,
144             \%real_index_to_filtered_index, \%filtered_index_to_real_index;
145             }
146              
147              
148             sub _get_map_key_from_options
149             {
150 68     68   91 my $self = shift;
151 68         88 my $options = shift;
152              
153 68 50       156 if (!defined $options) {
154 0         0 carp("\$options is undefined");
155             }
156              
157             return
158 68 100       480 ("key_" .
    100          
    100          
    50          
159             ($options->{ignore_case} ? "w" : "W") . "_" .
160             ($options->{ignore_blanks} ? "b" : "B") . "_" .
161             ($options->{ignore_case} ? "i" : "I") . "_" .
162             ($options->{ignore_simple} ? $options->{ignore_simple} : "0"));
163             }
164              
165             sub _maybe_make_filtered_maps
166             {
167 34     34   46 my $self = shift;
168 34         45 my $options = shift;
169              
170 34         65 my $key = $self->_get_map_key_from_options($options);
171              
172 34 100       138 if (!exists $self->{filtered_chunk_indexes}{$key}) {
173 6         334 ($self->{filtered_chunk_indexes}{$key},
174             $self->{filtered_hash}{$key},
175             $self->{real_to_filtered}{$key},
176             $self->{filtered_to_real}{$key}) = $self->_make_chunk_maps($options);
177              
178             }
179             }
180              
181             =head2 get_filtered_chunk_indexes
182              
183             Title : get_filtered_chunk_indexes
184             Usage : $filtered_chunk_indexes = $source->get_filtered_chunk_indexes($options);
185             Function: return (in order) the chunks from this source that match the given
186             options:
187             ignore_case=> (0 or 1) -- ignore case when comparing
188             ignore_blanks=> (0 or 1) -- ignore blank lines when comparing
189             ignore_space=> (0 or 1) -- ignore whitespace in chunks
190              
191             =cut
192              
193             sub get_filtered_chunk_indexes
194             {
195 16     16 1 6643 my $self = shift;
196 16         26 my $options = shift;
197              
198 16         46 my $key = $self->_get_map_key_from_options($options);
199              
200 16         60 $self->_maybe_make_filtered_maps($options);
201              
202 16         71 return $self->{filtered_chunk_indexes}{$key};
203             }
204              
205             =head2 get_matching_chunk_indexes
206              
207             Title : get_matching_chunk_indexes
208             Usage : $matches = $source->get_matching_chunk_indexes($options, $text);
209             Function: return (in order) the chunks from this source that match the given
210             text.
211             options:
212             ignore_case=> (0 or 1) -- ignore case when comparing
213             ignore_blanks=> (0 or 1) -- ignore blank lines when comparing
214             ignore_space=> (0 or 1) -- ignore whitespace in chunks
215              
216             =cut
217              
218             sub get_matching_chunk_indexes
219             {
220 2     2 1 3 my $self = shift;
221 2         3 my $options = shift;
222 2         4 my $text = shift;
223              
224 2         5 my $key = $self->_get_map_key_from_options($options);
225              
226 2         6 $self->_maybe_make_filtered_maps($options);
227              
228 2         4 my $chunk_hash = $self->{filtered_hash}{$key};
229              
230 2 50       5 return @{$chunk_hash->{hash($options, $text)} || []};
  2         6  
231             }
232              
233             =head2 _get_filtered_indx_from_real
234              
235             Title : _get_filtered_indx_from_real
236             Usage : $indx = $source->_get_filtered_indx_from_real($options, $real_indx);
237             Function: for the given index (eg. line number) in this source, return the
238             corresponding index in the list of chunks generated by applying the
239             $options. For example if $options->{ignore_blanks} is true the
240             filtered chunks will contain no blank lines.
241              
242             eg. input lines:
243              
244             some text on line 0
245            
246            
247             some text on line 3
248              
249             the real index of "some text on line 3" is 3, but the filtered index is 1 if
250             ignore_blanks is set because the filtered lines are:
251             some text on line 0
252             some text on line 3
253              
254             =cut
255              
256             sub _get_filtered_indx_from_real
257             {
258 16     16   21 my $self = shift;
259 16         18 my $options = shift;
260 16         20 my $real_indx = shift;
261              
262 16         29 my $key = $self->_get_map_key_from_options($options);
263              
264 16         38 $self->_maybe_make_filtered_maps($options);
265              
266 16         53 return $self->{real_to_filtered}{$key}{$real_indx};
267             }
268              
269             =head2 get_previous_chunk_indx
270              
271             Title : get_previous_chunk_indx
272             Usage : $prev_chunk_indx =
273             $source->get_previous_chunk_indx($options, $chunk_indx);
274             Function: return the previous chunk index from the list of filtered chunk
275             indexes (for the given $options). See discussion above.
276              
277             =cut
278              
279             sub get_previous_chunk_indx
280             {
281 12     12 1 15 my $self = shift;
282 12         15 my $options = shift;
283 12         16 my $chunk_indx = shift;
284              
285 12         33 my $prev_filtered_indx =
286             $self->_get_filtered_indx_from_real($options, $chunk_indx) - 1;
287              
288 12 100       30 if ($prev_filtered_indx < 0) {
289 6         17 return undef;
290             }
291              
292 6         11 return ($self->get_filtered_chunk_indexes($options))->[$prev_filtered_indx];
293             }
294              
295             =head2 get_next_chunk_indx
296              
297             Title : get_next_chunk_indx
298             Usage : $next_chunk_indx =
299             $source->get_next_chunk_indx($options, $chunk_indx);
300             Function: return the next chunk index from the list of filtered chunk
301             indexes (for the given $options). See discussion above.
302              
303             =cut
304              
305             sub get_next_chunk_indx
306             {
307 4     4 1 6 my $self = shift;
308 4         6 my $options = shift;
309 4         5 my $chunk_indx = shift;
310              
311 4         9 my $next_filtered_indx =
312             $self->_get_filtered_indx_from_real($options, $chunk_indx) + 1;
313              
314 4 100       10 if ($next_filtered_indx >= $self->get_all_chunks_count()) {
315 3         9 return undef;
316             }
317              
318 1         12 return ($self->get_filtered_chunk_indexes($options))->[$next_filtered_indx];
319             }
320              
321             =head1 AUTHOR
322              
323             Kim Rutherford
324              
325             =head1 COPYRIGHT & LICENSE
326              
327             Copyright 2005,2006 Kim Rutherford. All rights reserved.
328              
329             This program is free software; you can redistribute it and/or modify it
330             under the same terms as Perl itself.
331              
332             =head1 DISCLAIMER
333              
334             This module is provided "as is" without warranty of any kind. It
335             may redistributed under the same conditions as Perl itself.
336              
337             =cut
338              
339             1;