| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package List::RewriteElements; |
|
2
|
|
|
|
|
|
|
#$Id: RewriteElements.pm 1123 2007-01-23 03:39:35Z jimk $ |
|
3
|
|
|
|
|
|
|
$VERSION = 0.09; |
|
4
|
7
|
|
|
7
|
|
8789
|
use strict; |
|
|
7
|
|
|
|
|
17
|
|
|
|
7
|
|
|
|
|
494
|
|
|
5
|
7
|
|
|
7
|
|
42
|
use warnings; |
|
|
7
|
|
|
|
|
25
|
|
|
|
7
|
|
|
|
|
243
|
|
|
6
|
7
|
|
|
7
|
|
53
|
use Carp; |
|
|
7
|
|
|
|
|
13
|
|
|
|
7
|
|
|
|
|
598
|
|
|
7
|
7
|
|
|
7
|
|
40
|
use Cwd; |
|
|
7
|
|
|
|
|
21
|
|
|
|
7
|
|
|
|
|
503
|
|
|
8
|
7
|
|
|
7
|
|
42
|
use File::Basename; |
|
|
7
|
|
|
|
|
13
|
|
|
|
7
|
|
|
|
|
647
|
|
|
9
|
7
|
|
|
7
|
|
6958
|
use File::Copy; |
|
|
7
|
|
|
|
|
19714
|
|
|
|
7
|
|
|
|
|
431
|
|
|
10
|
7
|
|
|
7
|
|
43
|
use File::Spec; |
|
|
7
|
|
|
|
|
12
|
|
|
|
7
|
|
|
|
|
126
|
|
|
11
|
7
|
|
|
7
|
|
9273
|
use Tie::File; |
|
|
7
|
|
|
|
|
181316
|
|
|
|
7
|
|
|
|
|
10261
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub new { |
|
14
|
32
|
|
|
32
|
1
|
402030
|
my ($class, $argsref) = @_; |
|
15
|
32
|
100
|
|
|
|
375
|
croak "Hash ref passed to constructor must contain 'body_rule' element" |
|
16
|
|
|
|
|
|
|
unless defined $argsref->{body_rule}; |
|
17
|
31
|
100
|
|
|
|
292
|
croak "'body_rule' element value must be a code ref" |
|
18
|
|
|
|
|
|
|
unless ref($argsref->{body_rule}) eq 'CODE'; |
|
19
|
30
|
100
|
100
|
|
|
394
|
croak "Hash ref passed to constructor must have either a 'file' element or a 'list' element" |
|
20
|
|
|
|
|
|
|
unless (defined $argsref->{file} or defined $argsref->{list}); |
|
21
|
29
|
100
|
100
|
|
|
479
|
croak "'file' element passed to constructor not located" |
|
22
|
|
|
|
|
|
|
if (defined $argsref->{file} and not -f $argsref->{file}); |
|
23
|
28
|
100
|
100
|
|
|
555
|
croak "'list' element passed to constructor must be array ref" |
|
|
|
|
66
|
|
|
|
|
|
24
|
|
|
|
|
|
|
if ( defined $argsref->{list} and |
|
25
|
|
|
|
|
|
|
( |
|
26
|
|
|
|
|
|
|
(not ref($argsref->{list})) or |
|
27
|
|
|
|
|
|
|
(ref($argsref->{list}) ne 'ARRAY') |
|
28
|
|
|
|
|
|
|
) |
|
29
|
|
|
|
|
|
|
); |
|
30
|
26
|
100
|
100
|
|
|
359
|
croak "'body_suppress' element passed to constructor must be code ref" |
|
|
|
|
66
|
|
|
|
|
|
31
|
|
|
|
|
|
|
if ( defined $argsref->{body_suppress} and |
|
32
|
|
|
|
|
|
|
( |
|
33
|
|
|
|
|
|
|
(not ref($argsref->{body_suppress})) or |
|
34
|
|
|
|
|
|
|
(ref($argsref->{body_suppress}) ne 'CODE') |
|
35
|
|
|
|
|
|
|
) |
|
36
|
|
|
|
|
|
|
); |
|
37
|
24
|
100
|
100
|
|
|
505
|
croak "'header_rule' element passed to constructor must be code ref" |
|
|
|
|
66
|
|
|
|
|
|
38
|
|
|
|
|
|
|
if ( defined $argsref->{header_rule} and |
|
39
|
|
|
|
|
|
|
( |
|
40
|
|
|
|
|
|
|
(not ref($argsref->{header_rule})) or |
|
41
|
|
|
|
|
|
|
(ref($argsref->{header_rule}) ne 'CODE') |
|
42
|
|
|
|
|
|
|
) |
|
43
|
|
|
|
|
|
|
); |
|
44
|
22
|
100
|
100
|
|
|
1124
|
croak "If 'header_suppress' criterion is supplied, a 'header_rule' element must be supplied as well" |
|
45
|
|
|
|
|
|
|
if ( defined $argsref->{header_suppress} and |
|
46
|
|
|
|
|
|
|
! defined $argsref->{header_rule} |
|
47
|
|
|
|
|
|
|
); |
|
48
|
21
|
100
|
100
|
|
|
357
|
croak "'header_suppress' element passed to constructor must be code ref" |
|
|
|
|
66
|
|
|
|
|
|
49
|
|
|
|
|
|
|
if ( defined $argsref->{header_suppress} and |
|
50
|
|
|
|
|
|
|
( |
|
51
|
|
|
|
|
|
|
(not ref($argsref->{header_suppress})) or |
|
52
|
|
|
|
|
|
|
(ref($argsref->{header_suppress}) ne 'CODE') |
|
53
|
|
|
|
|
|
|
) |
|
54
|
|
|
|
|
|
|
); |
|
55
|
|
|
|
|
|
|
|
|
56
|
19
|
100
|
|
|
|
73
|
if ($argsref->{file}) { |
|
57
|
5
|
|
|
|
|
14
|
my @elements; |
|
58
|
5
|
50
|
|
|
|
108
|
tie @elements, 'Tie::File', $argsref->{file}, recsep => $/ |
|
59
|
|
|
|
|
|
|
or croak "Unable to tie to $argsref->{file}"; |
|
60
|
5
|
|
|
|
|
1639
|
$argsref->{working} = \@elements; |
|
61
|
|
|
|
|
|
|
} else { |
|
62
|
14
|
|
|
|
|
56
|
$argsref->{working} = $argsref->{list}; |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
19
|
|
|
|
|
130
|
my $self = bless ($argsref, $class); |
|
66
|
|
|
|
|
|
|
|
|
67
|
19
|
|
|
|
|
29
|
$self->{rows_in} = scalar(@{$self->{working}}); |
|
|
19
|
|
|
|
|
133
|
|
|
68
|
19
|
100
|
|
|
|
1434
|
if (defined $self->{header_rule}) { |
|
69
|
8
|
|
|
|
|
29
|
$self->{records_in} = $self->{rows_in} - 1; |
|
70
|
|
|
|
|
|
|
} else { |
|
71
|
11
|
|
|
|
|
45
|
$self->{records_in} = $self->{rows_in}; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
# Next attributes are initialized to empty strings because their value |
|
74
|
|
|
|
|
|
|
# is not fixed until after generate_output() has been called. |
|
75
|
19
|
|
|
|
|
70
|
$self->{output_path} = q{}; |
|
76
|
19
|
|
|
|
|
70
|
$self->{output_basename} = q{}; |
|
77
|
|
|
|
|
|
|
# Next attributes are initialized to zero because their value |
|
78
|
|
|
|
|
|
|
# is not fixed until after generate_output() has been called. |
|
79
|
19
|
|
|
|
|
51
|
$self->{rows_out} = 0; |
|
80
|
19
|
|
|
|
|
41
|
$self->{records_out} = 0; |
|
81
|
19
|
|
|
|
|
45
|
$self->{records_changed} = 0; |
|
82
|
19
|
|
|
|
|
42
|
$self->{records_unchanged} = 0; |
|
83
|
19
|
|
|
|
|
47
|
$self->{records_deleted} = 0; |
|
84
|
19
|
|
|
|
|
78
|
return $self; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub generate_output { |
|
88
|
19
|
|
|
19
|
1
|
17258
|
my $self = shift; |
|
89
|
19
|
100
|
100
|
|
|
199
|
if ( ! # print to STDOUT |
|
90
|
|
|
|
|
|
|
( |
|
91
|
|
|
|
|
|
|
defined $self->{output_file} or |
|
92
|
|
|
|
|
|
|
defined $self->{output_suffix} |
|
93
|
|
|
|
|
|
|
) |
|
94
|
|
|
|
|
|
|
) { |
|
95
|
11
|
|
|
|
|
42
|
$self->_handler_control(); |
|
96
|
|
|
|
|
|
|
} else { # print to file |
|
97
|
8
|
|
|
|
|
44
|
my $outfile; |
|
98
|
8
|
100
|
|
|
|
73
|
if (defined $self->{output_file}) { |
|
99
|
7
|
|
|
|
|
35
|
$outfile = $self->{output_file}; |
|
100
|
|
|
|
|
|
|
} else { |
|
101
|
1
|
|
|
|
|
13380
|
$outfile = File::Spec->catfile( ( cwd() ), |
|
102
|
|
|
|
|
|
|
basename($self->{file}) . $self->{output_suffix} ); |
|
103
|
|
|
|
|
|
|
} |
|
104
|
8
|
50
|
|
|
|
1443
|
open my $OUT, ">$outfile" |
|
105
|
|
|
|
|
|
|
or croak "Unable to open $outfile for writing"; |
|
106
|
8
|
|
|
|
|
82
|
my $oldfh = select($OUT); |
|
107
|
8
|
|
|
|
|
63
|
$self->_handler_control(); |
|
108
|
8
|
50
|
|
|
|
1483
|
close $OUT |
|
109
|
|
|
|
|
|
|
or croak "Unable to close $outfile after writing"; |
|
110
|
8
|
|
|
|
|
42
|
select $oldfh; |
|
111
|
8
|
|
|
|
|
40
|
$self->{output_path} = $outfile; |
|
112
|
8
|
|
|
|
|
929
|
$self->{output_basename} = basename($self->{output_path}); |
|
113
|
|
|
|
|
|
|
} |
|
114
|
19
|
|
|
|
|
235
|
$self->{records_out} = $self->{records_in} - $self->{records_deleted}; |
|
115
|
19
|
|
|
|
|
50
|
$self->{records_unchanged} = |
|
116
|
|
|
|
|
|
|
$self->{records_out} - $self->{records_changed}; |
|
117
|
19
|
100
|
|
|
|
237
|
if (! defined $self->{header_rule}) { |
|
118
|
11
|
|
|
|
|
42
|
$self->{rows_out} = $self->{records_out}; |
|
119
|
|
|
|
|
|
|
} else { |
|
120
|
8
|
100
|
|
|
|
34
|
if ($self->{header_status} != -1) { |
|
121
|
6
|
|
|
|
|
20
|
$self->{rows_out} = $self->{records_out} + 1; |
|
122
|
|
|
|
|
|
|
} else { |
|
123
|
2
|
|
|
|
|
7
|
$self->{rows_out} = $self->{records_out}; |
|
124
|
|
|
|
|
|
|
} |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub _handler_control { |
|
129
|
19
|
|
|
19
|
|
43
|
my $self = shift; |
|
130
|
19
|
100
|
|
|
|
72
|
if (! defined $self->{header_rule}) { |
|
131
|
11
|
|
|
|
|
94
|
$self->_body_rule_handler(); |
|
132
|
|
|
|
|
|
|
} else { |
|
133
|
8
|
|
|
|
|
33
|
$self->_header_body_rule_handler(); |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub _body_rule_handler { |
|
138
|
19
|
|
|
19
|
|
35
|
my $self = shift; |
|
139
|
19
|
|
|
|
|
136
|
RECORD: foreach my $el (@{$self->{working}}) { |
|
|
19
|
|
|
|
|
114
|
|
|
140
|
178
|
|
|
|
|
1214
|
chomp $el; |
|
141
|
178
|
100
|
|
|
|
14926
|
if (defined $self->{body_suppress}) { |
|
142
|
40
|
100
|
|
|
|
40
|
unless (defined (&{$self->{body_suppress}}($el))) { |
|
|
40
|
|
|
|
|
108
|
|
|
143
|
6
|
|
|
|
|
40
|
$self->{records_deleted}++; |
|
144
|
6
|
|
|
|
|
21
|
next RECORD; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
} |
|
147
|
172
|
|
|
|
|
393
|
my $newel = &{$self->{body_rule}}($el); |
|
|
172
|
|
|
|
|
561
|
|
|
148
|
172
|
|
|
|
|
2458
|
print "$newel\n"; |
|
149
|
172
|
100
|
|
|
|
6520
|
$self->{records_changed}++ if $el ne $newel; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub _header_body_rule_handler { |
|
154
|
8
|
|
|
8
|
|
17
|
my $self = shift; |
|
155
|
8
|
|
|
|
|
69
|
$self->{header_status} = 0; # header present, as yet unchanged |
|
156
|
8
|
|
|
|
|
13
|
my $header = shift(@{$self->{working}}); |
|
|
8
|
|
|
|
|
28
|
|
|
157
|
8
|
|
|
|
|
327
|
chomp $header; |
|
158
|
8
|
100
|
|
|
|
31
|
if (defined $self->{header_suppress}) { |
|
159
|
5
|
100
|
|
|
|
13
|
if (defined (&{$self->{header_suppress}}($header))) { |
|
|
5
|
|
|
|
|
20
|
|
|
160
|
3
|
|
|
|
|
24
|
my $newheader = &{$self->{header_rule}}($header); |
|
|
3
|
|
|
|
|
11
|
|
|
161
|
3
|
|
|
|
|
44
|
print "$newheader\n"; |
|
162
|
3
|
100
|
|
|
|
22
|
$self->{header_status} = 1 if $header ne $newheader; |
|
163
|
|
|
|
|
|
|
# header changed |
|
164
|
|
|
|
|
|
|
} else { |
|
165
|
2
|
|
|
|
|
17
|
$self->{header_status} = -1; # header suppressed |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
} else { |
|
168
|
3
|
|
|
|
|
4
|
my $newheader = &{$self->{header_rule}}($header); |
|
|
3
|
|
|
|
|
11
|
|
|
169
|
3
|
|
|
|
|
49
|
print "$newheader\n"; |
|
170
|
3
|
100
|
|
|
|
22
|
$self->{header_status} = 1 if $header ne $newheader; |
|
171
|
|
|
|
|
|
|
# header changed |
|
172
|
|
|
|
|
|
|
} |
|
173
|
8
|
|
|
|
|
33
|
$self->_body_rule_handler(); |
|
174
|
|
|
|
|
|
|
} |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub get_output_path { |
|
177
|
2
|
|
|
2
|
1
|
654
|
my $self = shift; |
|
178
|
2
|
|
|
|
|
30
|
return $self->{output_path}; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub get_output_basename { |
|
182
|
3
|
|
|
3
|
1
|
91
|
my $self = shift; |
|
183
|
3
|
|
|
|
|
105
|
return $self->{output_basename}; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub get_total_rows { |
|
187
|
13
|
|
|
13
|
1
|
5363
|
my $self = shift; |
|
188
|
13
|
|
|
|
|
84
|
return $self->{rows_out}; |
|
189
|
|
|
|
|
|
|
} |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
sub get_total_records { |
|
192
|
13
|
|
|
13
|
1
|
32
|
my $self = shift; |
|
193
|
13
|
|
|
|
|
74
|
return $self->{records_out}; |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub get_records_changed { |
|
197
|
13
|
|
|
13
|
1
|
37
|
my $self = shift; |
|
198
|
13
|
|
|
|
|
76
|
return $self->{records_changed}; |
|
199
|
|
|
|
|
|
|
} |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub get_records_unchanged { |
|
202
|
13
|
|
|
13
|
1
|
34
|
my $self = shift; |
|
203
|
13
|
|
|
|
|
83
|
return $self->{records_unchanged}; |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub get_records_deleted { |
|
207
|
13
|
|
|
13
|
1
|
943
|
my $self = shift; |
|
208
|
13
|
|
|
|
|
112
|
return $self->{records_deleted}; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub get_header_status { |
|
212
|
10
|
|
|
10
|
1
|
21
|
my $self = shift; |
|
213
|
10
|
|
|
|
|
76
|
return $self->{header_status}; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
1; |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
#################### DOCUMENTATION ################### |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head1 NAME |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
List::RewriteElements - Create a new list by rewriting elements of a first list |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
use List::RewriteElements; |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 Constructor |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Simplest case: Input from array, output to STDOUT. |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
$lre = List::RewriteElements->new( { |
|
234
|
|
|
|
|
|
|
list => \@source, |
|
235
|
|
|
|
|
|
|
body_rule => sub { |
|
236
|
|
|
|
|
|
|
my $record = shift; |
|
237
|
|
|
|
|
|
|
$record .= q{additional field}; |
|
238
|
|
|
|
|
|
|
}, |
|
239
|
|
|
|
|
|
|
} ); |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Input from file, output to STDOUT: |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
$lre = List::RewriteElements->new( { |
|
244
|
|
|
|
|
|
|
file => "/path/to/source/file", |
|
245
|
|
|
|
|
|
|
body_rule => sub { |
|
246
|
|
|
|
|
|
|
my $record = shift; |
|
247
|
|
|
|
|
|
|
$record .= q{,additional field}; |
|
248
|
|
|
|
|
|
|
}, |
|
249
|
|
|
|
|
|
|
} ); |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
Provide a different rule for the first element in the list: |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
$lre = List::RewriteElements->new( { |
|
254
|
|
|
|
|
|
|
file => "/path/to/source/file", |
|
255
|
|
|
|
|
|
|
header_rule => sub { |
|
256
|
|
|
|
|
|
|
my $record = shift; |
|
257
|
|
|
|
|
|
|
$record .= q{,ADDITIONAL HEADER}; |
|
258
|
|
|
|
|
|
|
}, |
|
259
|
|
|
|
|
|
|
body_rule => sub { |
|
260
|
|
|
|
|
|
|
my $record = shift; |
|
261
|
|
|
|
|
|
|
$record .= q{,additional field}; |
|
262
|
|
|
|
|
|
|
}, |
|
263
|
|
|
|
|
|
|
} ); |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
Input from file, output to file: |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
$lre = List::RewriteElements->new( { |
|
268
|
|
|
|
|
|
|
file => "/path/to/source/file", |
|
269
|
|
|
|
|
|
|
body_rule => sub { |
|
270
|
|
|
|
|
|
|
my $record = shift; |
|
271
|
|
|
|
|
|
|
$record .= q{additional field}; |
|
272
|
|
|
|
|
|
|
}, |
|
273
|
|
|
|
|
|
|
output_file => "/path/to/output/file", |
|
274
|
|
|
|
|
|
|
} ); |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
To name output file, just provide a suffix to filename: |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
$lre = List::RewriteElements->new( { |
|
279
|
|
|
|
|
|
|
file => "/path/to/source/file", |
|
280
|
|
|
|
|
|
|
body_rule => sub { |
|
281
|
|
|
|
|
|
|
my $record = shift; |
|
282
|
|
|
|
|
|
|
$record .= q{additional field}; |
|
283
|
|
|
|
|
|
|
}, |
|
284
|
|
|
|
|
|
|
output_suffix => '.out', |
|
285
|
|
|
|
|
|
|
} ); |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Provide criteria to suppress output of header or individual record. |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
$lre = List::RewriteElements->new( { |
|
290
|
|
|
|
|
|
|
file => "/path/to/source/file", |
|
291
|
|
|
|
|
|
|
header_suppress => sub { |
|
292
|
|
|
|
|
|
|
my $record = shift; |
|
293
|
|
|
|
|
|
|
return if $record =~ /$somepattern/; |
|
294
|
|
|
|
|
|
|
}, |
|
295
|
|
|
|
|
|
|
body_suppress => sub { |
|
296
|
|
|
|
|
|
|
my $record = shift; |
|
297
|
|
|
|
|
|
|
return if $record ne 'somestring'; |
|
298
|
|
|
|
|
|
|
}, |
|
299
|
|
|
|
|
|
|
body_rule => sub { |
|
300
|
|
|
|
|
|
|
my $record = shift; |
|
301
|
|
|
|
|
|
|
$record .= q{additional field}; |
|
302
|
|
|
|
|
|
|
}, |
|
303
|
|
|
|
|
|
|
} ); |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=head2 Generate Output |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
$lre->generate_output(); |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=head2 Report Output Information |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
$path_to_output_file = $lre->get_output_path(); |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
$output_file_basename = $lre->get_output_basename(); |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
$output_row_count = $lre->get_total_rows(); |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
$output_record_count = $lre->get_total_records(); |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
$records_changed = $lre->get_records_changed(); |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
$records_unchanged = $lre->get_records_unchanged(); |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
$records_deleted = $lre->get_records_deleted(); |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
$header_status = $lre->get_header_status(); |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
It is common in many situations for you to receive a flat data file from someone |
|
330
|
|
|
|
|
|
|
else and have to generate a new file in which each row or record in the |
|
331
|
|
|
|
|
|
|
incoming file must either (a) be transformed according to some rule before |
|
332
|
|
|
|
|
|
|
being printing to the new file; or (b) if it meets certain criteria, not output to the new file at all. |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
List::RewriteElements enables you to write such rules and criteria, generate |
|
335
|
|
|
|
|
|
|
the file of transformed data records, and get back some basic statistics about |
|
336
|
|
|
|
|
|
|
the transformation. |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
List::RewriteElements is useful when the number of records in the incoming |
|
339
|
|
|
|
|
|
|
file may be large and you do not want to hold the entire list in memory. |
|
340
|
|
|
|
|
|
|
Similarly, the newly generated records are not held in memory but are |
|
341
|
|
|
|
|
|
|
immediately Ced to STDOUT or to file. |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
On the other hand, if for some reason you already have an array of records in |
|
344
|
|
|
|
|
|
|
memory, you can use List::RewriteElements to apply rules and criteria to each |
|
345
|
|
|
|
|
|
|
element of the array and then print the transformed records (again, without |
|
346
|
|
|
|
|
|
|
holding the output in memory). |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=head1 SUBROUTINES |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head2 C |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
B List::RewriteElements constructor. |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
B Reference to a hash holding the following keys: |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=over 4 |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=item * C or C |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
The hash must hold either a C element or a C element -- but not |
|
361
|
|
|
|
|
|
|
both! The value for the C key must be an absolute path to an input |
|
362
|
|
|
|
|
|
|
file. The value for C must be a reference to an array in memory. |
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
=item * C |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
The hash must have a C element whose value is a reference to a |
|
367
|
|
|
|
|
|
|
subroutine providing a formula for the transformation of an individual record |
|
368
|
|
|
|
|
|
|
in the incoming file to a record in the outgoing file. The first argument |
|
369
|
|
|
|
|
|
|
passed to this subroutine must be the record from the incoming file. The |
|
370
|
|
|
|
|
|
|
return value from this subroutine should be a string immediately ready for |
|
371
|
|
|
|
|
|
|
printing to the output file (though the string should not end in a newline, as |
|
372
|
|
|
|
|
|
|
printing will be handled by C). |
|
373
|
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
=item * C |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
Optionally, you may provide a C element whose value is a |
|
377
|
|
|
|
|
|
|
reference to a subroutine providing a criterion according to which an |
|
378
|
|
|
|
|
|
|
individual record in the incoming file should be output to the outgoing file |
|
379
|
|
|
|
|
|
|
or not output, I, omitted from the output entirely. The first argument |
|
380
|
|
|
|
|
|
|
to this subroutine should be the record from the incoming file. The |
|
381
|
|
|
|
|
|
|
subroutine should, at least implicitly, return a true value when the record |
|
382
|
|
|
|
|
|
|
I be output. The subroutine should simply C, , |
|
383
|
|
|
|
|
|
|
return an implicit C, when the record should be omitted from the |
|
384
|
|
|
|
|
|
|
outgoing file. |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=item * C |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
Frequently the first row in a flat data file is a header row containing, say, |
|
389
|
|
|
|
|
|
|
the names of the columns in a data table, joined by a delimiter. Because the |
|
390
|
|
|
|
|
|
|
header row is different from all subsequent rows, you may optionally provide a |
|
391
|
|
|
|
|
|
|
C element whose value is a reference to a |
|
392
|
|
|
|
|
|
|
subroutine providing a formula for the transformation of the header row |
|
393
|
|
|
|
|
|
|
in the incoming file to the header in the outgoing file. The first argument |
|
394
|
|
|
|
|
|
|
passed to this subroutine must be the header row from the incoming file. The |
|
395
|
|
|
|
|
|
|
return value from this subroutine should be a string immediately ready for |
|
396
|
|
|
|
|
|
|
printing to the output file (though the string should not end in a newline, as |
|
397
|
|
|
|
|
|
|
printing will be handled by C). |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=item * C |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
Optionally, if you have provided a C element, you may provide |
|
402
|
|
|
|
|
|
|
a C element whose value is a |
|
403
|
|
|
|
|
|
|
reference to a subroutine providing a criterion according to which an |
|
404
|
|
|
|
|
|
|
the header row from the incoming file should be output to the outgoing file |
|
405
|
|
|
|
|
|
|
or not output, I, omitted from the output entirely. The first argument |
|
406
|
|
|
|
|
|
|
to this subroutine should be the header from the incoming file. The |
|
407
|
|
|
|
|
|
|
subroutine should, at least implicitly, return a true value when the header |
|
408
|
|
|
|
|
|
|
I be output. The subroutine should simply C, , |
|
409
|
|
|
|
|
|
|
return an implicit C, when the header should be omitted from the |
|
410
|
|
|
|
|
|
|
outgoing file. |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=item * C or C |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
It is recommended that you supply either an C or an |
|
415
|
|
|
|
|
|
|
C element to the constructor; otherwise, the new list generated |
|
416
|
|
|
|
|
|
|
by application of the rules and criteria will simply C to C. |
|
417
|
|
|
|
|
|
|
The value of an C element should be a full path to the newly |
|
418
|
|
|
|
|
|
|
created file. If you wish to create a new file name without specifying a full |
|
419
|
|
|
|
|
|
|
path but simply by tacking on a suffix to the name of the incoming file, |
|
420
|
|
|
|
|
|
|
provide an C element and the outgoing file will be created in |
|
421
|
|
|
|
|
|
|
the directory which is the I as of the point where |
|
422
|
|
|
|
|
|
|
C is called. An C element will |
|
423
|
|
|
|
|
|
|
be ignored if an C element is provided. |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
=item * Note 1 |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
If neither a C or C element is provide to the |
|
428
|
|
|
|
|
|
|
constructor, List::RewriteElements will treat the first row of the incoming |
|
429
|
|
|
|
|
|
|
file the same as any other row, C, it will apply the C |
|
430
|
|
|
|
|
|
|
transformation formula. |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=item * Note 2 |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
A C or C criterion, if present, will be |
|
435
|
|
|
|
|
|
|
logically applied I any C or C formula. We |
|
436
|
|
|
|
|
|
|
don't apply the formula to transform a record if the record should not be |
|
437
|
|
|
|
|
|
|
output at all. |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=item * Note 3 |
|
440
|
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=back |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
B List::RewriteElements object. |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
=head2 C |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
B Generates the output specified by arguments to C, |
|
448
|
|
|
|
|
|
|
I, creates an output file or Cs to C with records |
|
449
|
|
|
|
|
|
|
transformed as per those arguments. |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
B None. |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
B Returns true value upon success. In case of failure it will |
|
454
|
|
|
|
|
|
|
C with some error message. |
|
455
|
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=head2 C |
|
457
|
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
B Get the full path to the newly created output file. |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
B None. |
|
461
|
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
B String holding path to newly created output file. |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
B Since use of the C attribute means that the full |
|
465
|
|
|
|
|
|
|
path to the output file will not be known until C has been |
|
466
|
|
|
|
|
|
|
called, C will only give a meaningful result once |
|
467
|
|
|
|
|
|
|
C has been called. Otherwise, it will default to an empty |
|
468
|
|
|
|
|
|
|
string. |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=head2 C |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
B Get only the basename of the newly created output file. |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
B None. |
|
475
|
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
B String holding basename of newly created output file. |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
B Since use of the C attribute means that the full |
|
479
|
|
|
|
|
|
|
path to the output file will not be known until C has been |
|
480
|
|
|
|
|
|
|
called, C will only give a meaningful result once |
|
481
|
|
|
|
|
|
|
C has been called. Otherwise, it will default to an empty |
|
482
|
|
|
|
|
|
|
string. |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=head2 C |
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
B Get the total number of rows in the newly created output file. |
|
487
|
|
|
|
|
|
|
This will include any header row. |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
B None. |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
B Nonnegative integer. |
|
492
|
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=head2 C |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
B Get the total number of data records in the newly created output |
|
496
|
|
|
|
|
|
|
file. If a header row is present in that file, C will |
|
497
|
|
|
|
|
|
|
return a value C<1> less than that returned by C. |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
B None. |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
B Nonnegative integer. |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=head2 C |
|
504
|
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
B Get the number of data records in the newly created output file |
|
506
|
|
|
|
|
|
|
that are altered versions of records in the incoming file. This value does |
|
507
|
|
|
|
|
|
|
not include changes in the header row. |
|
508
|
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
B None. |
|
510
|
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
B Nonnegative integer. |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=head2 C |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
B Get the number of data records in the newly created output file |
|
516
|
|
|
|
|
|
|
that are unaltered versions of records in the incoming file. This value does |
|
517
|
|
|
|
|
|
|
not include changes in the header row. |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
B None. |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
B Nonnegative integer. |
|
522
|
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head2 C |
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
B Get the number of data records in the original source (file or |
|
526
|
|
|
|
|
|
|
list) that were omitted from the newly created output file due to application |
|
527
|
|
|
|
|
|
|
of a C criterion. This value does not include any suppression |
|
528
|
|
|
|
|
|
|
of a header row following application of a C criterion. |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
B None. |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
B Nonnegative integer. |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
=head2 C |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
B Indicate whether any header row in the original source (file or |
|
537
|
|
|
|
|
|
|
list) |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=over 4 |
|
540
|
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
=item * |
|
542
|
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
was rewritten in the newly created output file: return value C<1>; |
|
544
|
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
=item * |
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
was transferred to the newly created output file without alteration: return |
|
548
|
|
|
|
|
|
|
value C<0>; |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=item * |
|
551
|
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
was suppressed from appearing in the output file by application of a |
|
553
|
|
|
|
|
|
|
C criterion: return value C<-1>; |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
=item * |
|
556
|
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
no header row in the source: return value C. |
|
558
|
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
=back |
|
560
|
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
B None. |
|
562
|
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
B Numerical flag: C<1>, C<0>, C<-1> or C as described |
|
564
|
|
|
|
|
|
|
above. |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
=head1 FAQ |
|
567
|
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
=head2 Can I simultaneously rewrite records and interact with the external environment? |
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
Yes. If a C, C, C or C |
|
571
|
|
|
|
|
|
|
either (a) needs additional information from the external environment above |
|
572
|
|
|
|
|
|
|
and beyond that contained in the individual data record or (b) needs to cause |
|
573
|
|
|
|
|
|
|
a change in the external environment, you can write a closure and call that |
|
574
|
|
|
|
|
|
|
closure insider the rule. |
|
575
|
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
Example: |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
my @greeks = qw( alpha beta gamma ); |
|
579
|
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
my $get_a_greek = sub { |
|
581
|
|
|
|
|
|
|
return (shift @greeks); |
|
582
|
|
|
|
|
|
|
}; |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
my $lre = List::RewriteElements->new ( { |
|
585
|
|
|
|
|
|
|
list => [ map {"$_\n"} (1..5) ], |
|
586
|
|
|
|
|
|
|
body_rule => sub { |
|
587
|
|
|
|
|
|
|
my $record = shift; |
|
588
|
|
|
|
|
|
|
my $rv; |
|
589
|
|
|
|
|
|
|
chomp $record; |
|
590
|
|
|
|
|
|
|
if ($record eq '4') { |
|
591
|
|
|
|
|
|
|
$rv = &{$get_a_greek}; |
|
592
|
|
|
|
|
|
|
} else { |
|
593
|
|
|
|
|
|
|
$rv = (10 * $record); |
|
594
|
|
|
|
|
|
|
} |
|
595
|
|
|
|
|
|
|
return $rv; |
|
596
|
|
|
|
|
|
|
}, |
|
597
|
|
|
|
|
|
|
body_suppress => sub { |
|
598
|
|
|
|
|
|
|
my $record = shift; |
|
599
|
|
|
|
|
|
|
chomp $record; |
|
600
|
|
|
|
|
|
|
return if $record eq '5'; |
|
601
|
|
|
|
|
|
|
}, |
|
602
|
|
|
|
|
|
|
} ); |
|
603
|
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
$lre->generate_output(); |
|
605
|
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
This will produce: |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
10 |
|
609
|
|
|
|
|
|
|
20 |
|
610
|
|
|
|
|
|
|
30 |
|
611
|
|
|
|
|
|
|
alpha |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
=head2 Can I use List-Rewrite Elements with fixed-width data? |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
Yes. Suppose that you have this fixed-width data (adapted from Dave Cross' |
|
616
|
|
|
|
|
|
|
I): |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
my @dataset = ( |
|
619
|
|
|
|
|
|
|
q{00374Bloggs & Co 19991105100103+00015000}, |
|
620
|
|
|
|
|
|
|
q{00375Smith Brothers 19991106001234-00004999}, |
|
621
|
|
|
|
|
|
|
q{00376Camel Inc 19991107289736+00002999}, |
|
622
|
|
|
|
|
|
|
q{00377Generic Code 19991108056789-00003999}, |
|
623
|
|
|
|
|
|
|
); |
|
624
|
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
Suppose further that you need to update certain records and that C<%revisions> |
|
626
|
|
|
|
|
|
|
holds the data for updating: |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
my %revisions = ( |
|
629
|
|
|
|
|
|
|
376 => [ 'Camel Inc', 20061107, 388293, '+', 4999 ], |
|
630
|
|
|
|
|
|
|
377 => [ 'Generic Code', 20061108, 99821, '-', 6999 ], |
|
631
|
|
|
|
|
|
|
); |
|
632
|
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
Write a C subroutine which uses C, C and C |
|
634
|
|
|
|
|
|
|
as needed to update the records. |
|
635
|
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
my $lre = List::RewriteElements->new ( { |
|
637
|
|
|
|
|
|
|
list => \@dataset, |
|
638
|
|
|
|
|
|
|
body_rule => sub { |
|
639
|
|
|
|
|
|
|
my $record = shift; |
|
640
|
|
|
|
|
|
|
my $template = 'A5A18A8A6AA8'; |
|
641
|
|
|
|
|
|
|
my @rec = unpack($template, $record); |
|
642
|
|
|
|
|
|
|
$rec[0] =~ s/^0+//; |
|
643
|
|
|
|
|
|
|
my ($acctno, %values, $result); |
|
644
|
|
|
|
|
|
|
$acctno = $rec[0]; |
|
645
|
|
|
|
|
|
|
$values{$acctno} = [ @rec[1..$#rec] ]; |
|
646
|
|
|
|
|
|
|
if ($revisions{$acctno}) { |
|
647
|
|
|
|
|
|
|
$values{$acctno} = $revisions{$acctno}; |
|
648
|
|
|
|
|
|
|
} |
|
649
|
|
|
|
|
|
|
$result = sprintf "%05d%-18s%8d%06d%1s%08d", |
|
650
|
|
|
|
|
|
|
($acctno, @{$values{$acctno}}); |
|
651
|
|
|
|
|
|
|
return $result; |
|
652
|
|
|
|
|
|
|
}, |
|
653
|
|
|
|
|
|
|
} ); |
|
654
|
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
=head2 How does this differ from Tie::File? |
|
656
|
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
Mark Jason Dominus' Tie::File module is one of my Fave 5 CPAN modules. It's |
|
658
|
|
|
|
|
|
|
excellent for modifying a file in place. But I frequently have to leave the |
|
659
|
|
|
|
|
|
|
source file unmodified and create a new file, which implies, at the very |
|
660
|
|
|
|
|
|
|
least, opening, printing to, and closing filehandles in addition to using |
|
661
|
|
|
|
|
|
|
Tie::File. List::RewriteElements hides all |
|
662
|
|
|
|
|
|
|
that. It also provides the statistical report methods. |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
=head2 Couldn't I do this with C |
|
665
|
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
Quite possibly. But if your rules and criteria were complicated or long, the |
|
667
|
|
|
|
|
|
|
content of the C |
|
668
|
|
|
|
|
|
|
also wouldn't get the statistical report methods. |
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=head2 How Does It Work? |
|
671
|
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
Why do you care? Why do you want to look inside the black box? If you really |
|
673
|
|
|
|
|
|
|
want to know, read the source! |
|
674
|
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
=head1 PREREQUISITES |
|
676
|
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
List::RewriteElements relies only on modules distributed with the Perl core as |
|
678
|
|
|
|
|
|
|
of 5.8.0. IO::Capture::Stdout is required for the test suite, but a copy is |
|
679
|
|
|
|
|
|
|
included in the distribution under the F directory. |
|
680
|
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=head1 BUGS |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
None known at this time. File bug reports at L. |
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
=head1 HISTORY |
|
686
|
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
0.09 Mon Jan 22 22:35:56 EST 2007 |
|
688
|
|
|
|
|
|
|
- Update version number and release date only. Purpose: generate new |
|
689
|
|
|
|
|
|
|
round of tests by cpan testers, in the hope that it eliminates a FAIL report |
|
690
|
|
|
|
|
|
|
on v0.08 where failure was due solely to error on tester's box. |
|
691
|
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
0.08 Mon Jan 1 08:54:01 EST 2007 |
|
693
|
|
|
|
|
|
|
- xdg to the rescue! Applied and extended patches supplied by David |
|
694
|
|
|
|
|
|
|
Golden for Win32. In constructor, value of C<$/> is supplied to the C |
|
695
|
|
|
|
|
|
|
option. |
|
696
|
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
0.07 Sun Dec 31 11:13:04 EST 2006 |
|
698
|
|
|
|
|
|
|
- Switched to using File::Spec::catfile() to generate one path (rather |
|
699
|
|
|
|
|
|
|
than Cwd::realpath(). This was done in an attempt to respond to corion's FAIL |
|
700
|
|
|
|
|
|
|
reports (but I don't have a good Windows box, so I can't be certain of the |
|
701
|
|
|
|
|
|
|
results). |
|
702
|
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
0.06 Sat Dec 16 11:31:38 EST 2006 |
|
704
|
|
|
|
|
|
|
- Created t/07_fixed_width.t and t/testlib/fixed.t to illustrate use of |
|
705
|
|
|
|
|
|
|
List::RewriteElements with fixed-width data. |
|
706
|
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
0.05 Thu Dec 14 07:42:24 EST 2006 |
|
708
|
|
|
|
|
|
|
- Correction of POD formatting errors only; no change in functionality. |
|
709
|
|
|
|
|
|
|
CPAN upload. |
|
710
|
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
0.04 Wed Dec 13 23:04:33 EST 2006 |
|
712
|
|
|
|
|
|
|
- More tests; fine-tuning of code and documentation. First CPAN upload. |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
0.03 Tue Dec 12 22:13:00 EST 2006 |
|
715
|
|
|
|
|
|
|
- Implementation of statistical methods; more tests. |
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
0.02 Mon Dec 11 19:38:26 EST 2006 |
|
718
|
|
|
|
|
|
|
- Added tests to demonstrate use of closures to supply additional |
|
719
|
|
|
|
|
|
|
information to elements such as body_rule. |
|
720
|
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
0.01 Sat Dec 9 22:29:51 2006 |
|
722
|
|
|
|
|
|
|
- original version; created by ExtUtils::ModuleMaker 0.47 |
|
723
|
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
725
|
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
Thanks to David Landgren for raising the question of use of |
|
727
|
|
|
|
|
|
|
List-RewriteElements with fixed-width data. |
|
728
|
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
I then adapted an example from Dave Cross' I, |
|
730
|
|
|
|
|
|
|
Chapter 7.1, "Fixed-width Data," to provide a test |
|
731
|
|
|
|
|
|
|
demonstrating processing of fixed-width data. |
|
732
|
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
=head1 AUTHOR |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
James E Keenan. CPAN ID: JKEENAN. jkeenan@cpan.org. |
|
736
|
|
|
|
|
|
|
http://search.cpan.org/~jkeenan/ or |
|
737
|
|
|
|
|
|
|
http://thenceforward.net/perl/modules/List-RewriteElements. |
|
738
|
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
740
|
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
Copyright 2006 James E Keenan (USA). |
|
742
|
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
This program is free software; you can redistribute |
|
744
|
|
|
|
|
|
|
it and/or modify it under the same terms as Perl itself. |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
The full text of the license can be found in the |
|
747
|
|
|
|
|
|
|
LICENSE file included with this module. |
|
748
|
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
750
|
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
David Cross, I (Manning, 2001). |
|
752
|
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
=cut |
|
754
|
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
|