line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Excel::Table; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Excel::Table - Table processing class for Excel worksheets. |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use Excel::Table; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
my $xs = Excel::Table->new('dir' => '/cygdrive/c/Users/self/Desktop'); |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
for ($xs->list_workbooks) { |
14
|
|
|
|
|
|
|
print "workbook [$_]\n"; |
15
|
|
|
|
|
|
|
} |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
$xs->open('mybook.xls'); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $wb1 = $xs->open_re('foo*bar*'); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
for my $worksheet ($wb1->worksheets) { |
22
|
|
|
|
|
|
|
print "worksheet: " . $worksheet->get_name() . "\n"; |
23
|
|
|
|
|
|
|
} |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
$xs->null("this is a null value"); |
26
|
|
|
|
|
|
|
$xs->force_null(1); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
$xs->rowid(0); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
$xs->trim(0); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
my @data = $xs->extract('Sheet1'); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
for (@data) { |
35
|
|
|
|
|
|
|
printf "rowid [%s] title [%s] max_width [%d] value [%s]\n", |
36
|
|
|
|
|
|
|
$_->[0], |
37
|
|
|
|
|
|
|
$xs->titles->[0], |
38
|
|
|
|
|
|
|
$xs->widths->[0], |
39
|
|
|
|
|
|
|
$data{$_}->[0]; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
@data = $xs->extract_hash('Sheet1'); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
@data = $xs->select("column1,column2,column3", 'Sheet1'); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
@data = $xs->select_hash("column1,column2,column3", 'Sheet1'); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
printf "columns %d rows %d title_row %d\n", |
49
|
|
|
|
|
|
|
$xs->columns, $xs->rows, $xs->title_row; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
printf "regexp [%s] pathname [%s] sheet_name [%s]\n", |
52
|
|
|
|
|
|
|
$xs->regexp, $xs->pathname, $xs->sheet_name; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
printf "colid2title(0) = [%s]\n", $xs->colid2title(0); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
printf "title2colid('Foo') = %d\n", $xs->title2colid('Foo'); |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=head1 DESCRIPTION |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
"Excel::Table" retrieves worksheets as if they are structured |
61
|
|
|
|
|
|
|
tables in array-format or optionally in hash-format. |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=over 4 |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=item 1a. OBJ->dir(EXPR) |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Override the directory location in which to look for workbooks. |
68
|
|
|
|
|
|
|
Defaults to "." (i.e. the current working directory). |
69
|
|
|
|
|
|
|
This location is critical to the B, B, |
70
|
|
|
|
|
|
|
and B methods. |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=item 1b. OBJ->list_workbooks |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
Returns an array of workbook files in the directory defined by the |
75
|
|
|
|
|
|
|
B property. |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=item 2a. OBJ->open(EXPR) |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
Parses the filename specified by EXPR. The B property |
80
|
|
|
|
|
|
|
will designate the search path. |
81
|
|
|
|
|
|
|
Once opened, via this method (or B) the |
82
|
|
|
|
|
|
|
workbook is available for use by the B method. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=item 2b. OBJ->open_re(EXPR) |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
This will search for a file which has a filename matching the regexp EXPR. |
87
|
|
|
|
|
|
|
A warning will be issued if multiple matches are found, only the first will |
88
|
|
|
|
|
|
|
be opened. |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=item 3. OBJ->regexp |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
Returns the regexp used to search for the workbook on the filesystem. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=item 4. OBJ->pathname |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
Returns the pathname of the opened workbook. |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=item 5a. OBJ->extract(EXPR,[TITLE_ROW]) |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
This will extract all data from the worksheet named EXPR. Data is extracted |
101
|
|
|
|
|
|
|
into an array and returned. Format of data is per below: |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
[ value1, value2, value3, ... ], |
104
|
|
|
|
|
|
|
[ value1, value2, value3, ... ], |
105
|
|
|
|
|
|
|
[ value1, value2, value3, ... ], |
106
|
|
|
|
|
|
|
... |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
The object OBJ will be populated with various properties to assist you to |
109
|
|
|
|
|
|
|
access the data in the array, including column titles and widths. |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
A worksheet object is temporarily created in order to populate the array. |
112
|
|
|
|
|
|
|
Once a worksheet is extracted, the associated worksheet object is destroyed. |
113
|
|
|
|
|
|
|
This routine can be called again on any worksheet in the workbook. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
If the TITLE_ROW argument is specified, then the B property will |
116
|
|
|
|
|
|
|
also be updated prior to extraction. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=item 5b. OBJ->extract_hash(EXPR,[TITLE_ROW]) |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
Per the B method, but returns an array of hashes, with the hash |
121
|
|
|
|
|
|
|
keys corresponding to the titles. |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=item 5c. OBJ->select(CLAUSE,EXPR,[TITLE_ROW]) |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
Similar to the B method, this will extract all rows from the worksheet EXPR, constraining the columns to those specified by the B argument, |
126
|
|
|
|
|
|
|
which is a comma-separated string, e.g. "column1,column2,column3". |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
As with the B method, the B and B properties will |
129
|
|
|
|
|
|
|
be revised. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=item 5d. OBJ->select_hash(CLAUSE,EXPR,[TITLE_ROW]) |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Per the B |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=item 6. OBJ->columns or OBJ->rows |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
Returns the number of columns or rows available in the sheet extracted via the |
138
|
|
|
|
|
|
|
B method. |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=item 7a. OBJ->force_null |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
Flag which determines if whitespace fields should be |
143
|
|
|
|
|
|
|
replaced by specific text (see OBJ->null). |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=item 7b. OBJ->null |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
String to replace whitespace fields with. Defaults to "(null)". |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=item 8. OBJ->rowid |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
Flag which determines whether a pseudo-column "rowid" is included in each |
152
|
|
|
|
|
|
|
tuple. The value will take the form "999999999" Defaults to FALSE. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=item 9. OBJ->sheet_name |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
Returns the sheet_name against which data was extracted via B. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=item 10. OBJ->trim |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
Flag which determines if trailing whitespace fields should be trimmed. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=item 11a. OBJ->title_row |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
Returns the title row of the worksheet (defaults to zero), following extract. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=item 11b. OBJ->titles |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
Returns an array of title fields, the title row number having been defined |
169
|
|
|
|
|
|
|
as OBJ->title_row. |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=item 11c. OBJ->colid2title(colid) |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Converts the column number (colid) to a string column title (i.e. |
174
|
|
|
|
|
|
|
the offset within the title_row array). |
175
|
|
|
|
|
|
|
If no match, then returns undef. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=item 11d. OBJ->title2colid(REGEXP) |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
Returns the column number of the title identified by REGEXP. |
180
|
|
|
|
|
|
|
If no match, then returns undef. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=item 12. OBJ->widths |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Returns an array of maximum lengths of any (non-title) data in each column. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=back |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=cut |
189
|
|
|
|
|
|
|
|
190
|
9
|
|
|
9
|
|
658426
|
use strict; |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
334
|
|
191
|
9
|
|
|
9
|
|
35
|
use warnings; |
|
9
|
|
|
|
|
14
|
|
|
9
|
|
|
|
|
224
|
|
192
|
|
|
|
|
|
|
|
193
|
9
|
|
|
9
|
|
614
|
use Data::Dumper; |
|
9
|
|
|
|
|
6955
|
|
|
9
|
|
|
|
|
586
|
|
194
|
9
|
|
|
9
|
|
7689
|
use Spreadsheet::ParseExcel 0.57; |
|
9
|
|
|
|
|
533845
|
|
|
9
|
|
|
|
|
284
|
|
195
|
9
|
|
|
9
|
|
5650
|
use Spreadsheet::XLSX; |
|
9
|
|
|
|
|
537737
|
|
|
9
|
|
|
|
|
319
|
|
196
|
9
|
|
|
9
|
|
93
|
use File::Basename; |
|
9
|
|
|
|
|
12
|
|
|
9
|
|
|
|
|
608
|
|
197
|
|
|
|
|
|
|
|
198
|
9
|
|
|
9
|
|
48
|
use Carp qw(cluck confess); # only use stack backtrace within class |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
499
|
|
199
|
9
|
|
|
9
|
|
40
|
use Log::Log4perl qw/ get_logger /; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
86
|
|
200
|
|
|
|
|
|
|
|
201
|
9
|
|
|
9
|
|
485
|
use vars qw/ @EXPORT $VERSION /; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
520
|
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
$VERSION = "1.022"; # update this on new release |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
#@ISA = qw(Exporter); |
206
|
|
|
|
|
|
|
#@EXPORT = qw(); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# package constants |
209
|
9
|
|
|
9
|
|
105
|
use constant S_RID => "rowid"; |
|
9
|
|
|
|
|
12
|
|
|
9
|
|
|
|
|
560
|
|
210
|
9
|
|
|
9
|
|
35
|
use constant S_NULL => "(null)"; |
|
9
|
|
|
|
|
11
|
|
|
9
|
|
|
|
|
385
|
|
211
|
9
|
|
|
|
|
553
|
use constant EXT_EXCEL => qw/ |
212
|
|
|
|
|
|
|
\.xls \.xla \.xlb \.xlc \.xld \.xlk \.xll \.xlm \.xlt |
213
|
|
|
|
|
|
|
\.xlv \.xlw \.xls \.xlt |
214
|
9
|
|
|
9
|
|
34
|
/; # known extensions for EXCEL file |
|
9
|
|
|
|
|
12
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
# need the Spreadsheet::XLSX module for the following: |
217
|
9
|
|
|
|
|
21748
|
use constant EXT_EXCEL_2007 => qw/ |
218
|
|
|
|
|
|
|
\.xlsx \.xlsm \.xlsb \.xltm \.xlam |
219
|
9
|
|
|
9
|
|
43
|
/; # known extensions for EXCEL 2007 file |
|
9
|
|
|
|
|
8
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# package globals |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
our $AUTOLOAD; |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# package locals |
228
|
|
|
|
|
|
|
my $n_Objects = 0; # counter of objects created. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
my %attribute = ( |
231
|
|
|
|
|
|
|
_n_objects => \$n_Objects, |
232
|
|
|
|
|
|
|
_xl_vers => undef, |
233
|
|
|
|
|
|
|
columns => undef, |
234
|
|
|
|
|
|
|
dir => ".", |
235
|
|
|
|
|
|
|
_log => get_logger("Excel::Table"), |
236
|
|
|
|
|
|
|
null => S_NULL, |
237
|
|
|
|
|
|
|
pathname => undef, |
238
|
|
|
|
|
|
|
regexp => undef, |
239
|
|
|
|
|
|
|
force_null => 0, |
240
|
|
|
|
|
|
|
rows => undef, |
241
|
|
|
|
|
|
|
rowid => 0, |
242
|
|
|
|
|
|
|
sheet_name => undef, |
243
|
|
|
|
|
|
|
title_row => 0, # if title row is zero, first data row is 1 |
244
|
|
|
|
|
|
|
titles => undef, |
245
|
|
|
|
|
|
|
trim => 0, |
246
|
|
|
|
|
|
|
widths => undef, |
247
|
|
|
|
|
|
|
workbook => undef, |
248
|
|
|
|
|
|
|
); |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
#INIT { }; |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub AUTOLOAD { |
255
|
18998
|
|
|
18998
|
|
551230
|
my $self = shift; |
256
|
18998
|
50
|
|
|
|
30823
|
my $type = ref($self) or croak("self is not an object"); |
257
|
|
|
|
|
|
|
|
258
|
18998
|
|
|
|
|
17635
|
my $name = $AUTOLOAD; |
259
|
18998
|
|
|
|
|
44639
|
$name =~ s/.*://; # strip fully−qualified portion |
260
|
|
|
|
|
|
|
|
261
|
18998
|
50
|
|
|
|
37155
|
unless (exists $self->{_permitted}->{$name} ) { |
262
|
0
|
|
|
|
|
0
|
confess "no attribute [$name] in class [$type]"; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
18998
|
100
|
|
|
|
24488
|
if (@_) { |
266
|
328
|
|
|
|
|
850
|
return $self->{$name} = shift; |
267
|
|
|
|
|
|
|
} else { |
268
|
18670
|
|
|
|
|
54636
|
return $self->{$name}; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub new { |
274
|
24
|
|
|
24
|
0
|
32653
|
my ($class) = shift; |
275
|
|
|
|
|
|
|
#my $self = $class->SUPER::new(@_); |
276
|
24
|
|
|
|
|
352
|
my $self = { _permitted => \%attribute, %attribute }; |
277
|
|
|
|
|
|
|
|
278
|
24
|
|
|
|
|
81
|
++ ${ $self->{_n_objects} }; |
|
24
|
|
|
|
|
65
|
|
279
|
|
|
|
|
|
|
|
280
|
24
|
|
|
|
|
61
|
bless ($self, $class); |
281
|
|
|
|
|
|
|
|
282
|
24
|
|
|
|
|
69
|
my %args = @_; # start processing any parameters passed |
283
|
24
|
|
|
|
|
40
|
my ($method,$value); # start processing any parameters passed |
284
|
24
|
|
|
|
|
453
|
while (($method, $value) = each %args) { |
285
|
|
|
|
|
|
|
|
286
|
31
|
50
|
|
|
|
75
|
confess "SYNTAX new(method => value, ...) value not specified" |
287
|
|
|
|
|
|
|
unless (defined $value); |
288
|
|
|
|
|
|
|
|
289
|
31
|
|
|
|
|
145
|
$self->_log->debug("method [self->$method($value)]"); |
290
|
|
|
|
|
|
|
|
291
|
31
|
|
|
|
|
273
|
$self->$method($value); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
24
|
|
|
|
|
79
|
return $self; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
sub _determine_xl_vers { |
299
|
303
|
|
|
303
|
|
376
|
my ($self,$pn)=@_; |
300
|
303
|
50
|
|
|
|
547
|
$self->_log->logcroak("SYNTAX: _determine_xl_vers(path)") |
301
|
|
|
|
|
|
|
unless defined ($pn); |
302
|
|
|
|
|
|
|
# return version string or undef for given pathname |
303
|
303
|
|
|
|
|
265
|
my $extension; |
304
|
|
|
|
|
|
|
my @extensions; |
305
|
303
|
|
|
|
|
285
|
my $retval = undef; |
306
|
|
|
|
|
|
|
|
307
|
303
|
|
|
|
|
915
|
$self->_log->debug("pn [$pn]"); |
308
|
|
|
|
|
|
|
|
309
|
303
|
|
|
|
|
2257
|
@extensions = EXT_EXCEL; |
310
|
303
|
|
|
|
|
26561
|
(undef,undef,$extension) = fileparse($pn,@extensions); |
311
|
|
|
|
|
|
|
#$self->_log->debug(sprintf " extension [%s] \@extensions [%s]", $extension, Dumper(\@extensions)); |
312
|
|
|
|
|
|
|
|
313
|
303
|
100
|
|
|
|
841
|
$retval = 'xl2003' if ($extension ne ""); |
314
|
|
|
|
|
|
|
|
315
|
303
|
|
|
|
|
818
|
@extensions = EXT_EXCEL_2007; |
316
|
303
|
|
|
|
|
12851
|
(undef,undef,$extension) = fileparse($pn,@extensions); |
317
|
|
|
|
|
|
|
|
318
|
303
|
100
|
|
|
|
759
|
$retval = 'xl2007' if ($extension ne ""); |
319
|
|
|
|
|
|
|
|
320
|
303
|
100
|
|
|
|
498
|
if (defined $retval) { |
321
|
56
|
|
|
|
|
243
|
$self->_log->debug("pn [$pn] returning [$retval]"); |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
303
|
|
|
|
|
1652
|
return $retval; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub list_workbooks { |
329
|
13
|
|
|
13
|
1
|
1064
|
my $self = shift; |
330
|
|
|
|
|
|
|
|
331
|
13
|
|
|
|
|
68
|
my $dn = $self->dir; |
332
|
13
|
|
|
|
|
24
|
my ($dh,$fn); |
333
|
0
|
|
|
|
|
0
|
my @workbooks; |
334
|
|
|
|
|
|
|
|
335
|
13
|
|
|
|
|
47
|
$self->_log->debug("dn [$dn]"); |
336
|
|
|
|
|
|
|
|
337
|
13
|
50
|
|
|
|
776
|
opendir($dh, $dn) || $self->_log->logcroak("opendir($dn)"); |
338
|
|
|
|
|
|
|
|
339
|
13
|
|
|
|
|
212
|
while ($fn = readdir($dh)) { |
340
|
273
|
|
|
|
|
2004
|
my $pn = File::Spec->catfile($dn, $fn); |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# need to remember just the filename here, not the path because |
343
|
|
|
|
|
|
|
# open will use the self->dir property to make the path |
344
|
273
|
100
|
|
|
|
693
|
push @workbooks, $fn |
345
|
|
|
|
|
|
|
if (defined($self->_determine_xl_vers($pn))); |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
13
|
|
|
|
|
309
|
closedir $dh; |
349
|
|
|
|
|
|
|
|
350
|
13
|
|
|
|
|
74
|
$self->_log->debug(sprintf '@workbooks [%s]', Dumper(\@workbooks)); |
351
|
|
|
|
|
|
|
|
352
|
13
|
|
|
|
|
1456
|
return @workbooks; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub open { |
357
|
30
|
|
|
30
|
1
|
9374
|
my ($self,$fn)=@_; |
358
|
30
|
50
|
|
|
|
107
|
$self->_log->logcroak("SYNTAX: open(file)") unless defined ($fn); |
359
|
30
|
|
|
|
|
192
|
my $pn = File::Spec->catfile($self->dir, $fn); |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# to look for the file in the cwd, is not good behaviour, |
362
|
|
|
|
|
|
|
# so dir must be explicit, thus the default to "." |
363
|
|
|
|
|
|
|
|
364
|
30
|
50
|
|
|
|
796
|
if (-f $pn) { |
365
|
30
|
|
|
|
|
157
|
$self->pathname($pn); |
366
|
|
|
|
|
|
|
} else { |
367
|
0
|
|
|
|
|
0
|
$self->_log->logcroak("no such path [$pn]"); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
30
|
|
|
|
|
154
|
$self->_log->debug("parsing [$pn]"); |
371
|
|
|
|
|
|
|
|
372
|
30
|
|
|
|
|
290
|
$self->{'_xl_vers'} = $self->_determine_xl_vers($pn); |
373
|
|
|
|
|
|
|
|
374
|
30
|
|
|
|
|
49
|
my $parser; |
375
|
|
|
|
|
|
|
|
376
|
30
|
100
|
|
|
|
143
|
if ($self->_xl_vers eq 'xl2007') { |
377
|
13
|
|
|
|
|
240
|
$parser = Spreadsheet::XLSX->new($pn); |
378
|
|
|
|
|
|
|
|
379
|
13
|
50
|
|
|
|
399694
|
$self->_log->logcroak("Spreadsheet::XLSX->new($pn) failed") |
380
|
|
|
|
|
|
|
unless defined $parser; |
381
|
|
|
|
|
|
|
|
382
|
13
|
|
|
|
|
130
|
$self->workbook($parser); |
383
|
|
|
|
|
|
|
} else { |
384
|
17
|
|
|
|
|
153
|
$parser = Spreadsheet::ParseExcel->new(); |
385
|
17
|
|
|
|
|
27745
|
$self->workbook($parser->Parse($pn)); |
386
|
|
|
|
|
|
|
|
387
|
17
|
50
|
|
|
|
831
|
$self->_log->logcroak("Parse() failed, error: " . $self->workbook->error()) |
388
|
|
|
|
|
|
|
unless defined $self->workbook; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
|
392
|
30
|
|
|
|
|
139
|
return $self->workbook; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
sub open_re { |
397
|
7
|
|
|
7
|
1
|
3381
|
my $self = shift; |
398
|
7
|
50
|
|
|
|
28
|
if (@_) { $self->regexp(shift); } else { $self->_log->logcroak("SYNTAX: open_re(regexp)"); } |
|
7
|
|
|
|
|
51
|
|
|
0
|
|
|
|
|
0
|
|
399
|
7
|
|
|
|
|
46
|
my $re = $self->regexp; |
400
|
7
|
|
|
|
|
12
|
my $matches = 0; |
401
|
7
|
|
|
|
|
10
|
my $wb = undef; |
402
|
|
|
|
|
|
|
|
403
|
7
|
|
|
|
|
28
|
$self->_log->debug(sprintf "regexp [%s]", $self->regexp); |
404
|
7
|
|
|
|
|
55
|
for ( $self->list_workbooks ) { |
405
|
14
|
|
|
|
|
85
|
$self->_log->debug(" file [$_]"); |
406
|
14
|
100
|
|
|
|
184
|
if ($_ =~ /$re/) { |
407
|
10
|
|
|
|
|
34
|
$self->_log->debug(" FOUND [$_]"); |
408
|
10
|
100
|
|
|
|
96
|
$wb = $_ unless ($matches++); # remember first occurence |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
7
|
100
|
|
|
|
21
|
unless (defined $wb) { |
413
|
1
|
|
|
|
|
3
|
$self->_log->logcarp("could not find file matching [$re]"); |
414
|
1
|
|
|
|
|
600
|
return undef; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
6
|
100
|
|
|
|
61
|
$self->_log->logwarn("non-unique match on [$re]") |
418
|
|
|
|
|
|
|
if ($matches > 1); |
419
|
|
|
|
|
|
|
|
420
|
6
|
|
|
|
|
1528
|
return $self->open($wb); |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
sub _prepend_rowid { |
425
|
110
|
|
|
110
|
|
152
|
my ($self, $ra_columns, $id)=@_; |
426
|
|
|
|
|
|
|
|
427
|
110
|
100
|
|
|
|
329
|
my $rowid = ($id == $self->title_row) ? S_RID : sprintf "%09d", $id; |
428
|
|
|
|
|
|
|
|
429
|
110
|
|
|
|
|
225
|
push @$ra_columns, $rowid; |
430
|
|
|
|
|
|
|
|
431
|
110
|
|
|
|
|
136
|
return $rowid; |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub extract { |
436
|
36
|
|
|
36
|
1
|
5245
|
my $self = shift; |
437
|
36
|
50
|
|
|
|
123
|
if (@_) { $self->sheet_name(shift); } |
|
36
|
|
|
|
|
213
|
|
438
|
36
|
50
|
|
|
|
130
|
if (@_) { $self->title_row(shift); } |
|
0
|
|
|
|
|
0
|
|
439
|
|
|
|
|
|
|
|
440
|
36
|
50
|
33
|
|
|
144
|
$self->_log->logcroak("SYNTAX: extract(sheet_name,title_row)") |
441
|
|
|
|
|
|
|
unless (defined $self->sheet_name && defined $self->title_row); |
442
|
|
|
|
|
|
|
|
443
|
36
|
|
|
|
|
162
|
$self->_log->debug(sprintf "opening [%s]", $self->sheet_name); |
444
|
|
|
|
|
|
|
|
445
|
36
|
|
|
|
|
400
|
my $ws = $self->workbook->worksheet($self->sheet_name); |
446
|
|
|
|
|
|
|
|
447
|
36
|
|
|
|
|
537
|
my ($minr, $maxr) = $ws->row_range(); |
448
|
36
|
|
|
|
|
370
|
my ($minc, $maxc) = $ws->col_range(); |
449
|
|
|
|
|
|
|
|
450
|
36
|
|
|
|
|
375
|
$self->rows($maxr); |
451
|
36
|
|
|
|
|
164
|
$self->columns($maxc + 1); |
452
|
|
|
|
|
|
|
|
453
|
36
|
100
|
|
|
|
111
|
$self->title_row($minr) # fix minimum row |
454
|
|
|
|
|
|
|
if ($self->title_row < $minr); |
455
|
|
|
|
|
|
|
|
456
|
36
|
|
|
|
|
122
|
$self->_log->debug(sprintf "sheet_name [%s] minr [%d] maxr [%d] minc [%d] maxc [%d]", |
457
|
|
|
|
|
|
|
$self->sheet_name, $minr, $maxr, $minc, $maxc); |
458
|
|
|
|
|
|
|
|
459
|
36
|
|
|
|
|
216
|
my ($subr,$subc,$value); |
460
|
0
|
|
|
|
|
0
|
my @data; |
461
|
0
|
|
|
|
|
0
|
my (@columns,@widths); |
462
|
|
|
|
|
|
|
|
463
|
36
|
|
|
|
|
118
|
for ($subr = $self->title_row; $subr <= $maxr; $subr++) { |
464
|
|
|
|
|
|
|
|
465
|
368
|
100
|
|
|
|
1098
|
$self->_prepend_rowid(\@columns, $subr) |
466
|
|
|
|
|
|
|
if ($self->rowid); |
467
|
|
|
|
|
|
|
|
468
|
368
|
|
|
|
|
904
|
for ($subc = $minc; $subc <= $maxc; $subc++) { |
469
|
|
|
|
|
|
|
|
470
|
3584
|
|
|
|
|
8000
|
my $cell = $ws->get_cell($subr, $subc); |
471
|
|
|
|
|
|
|
|
472
|
3584
|
100
|
|
|
|
29146
|
if (defined $cell) { |
473
|
3552
|
100
|
|
|
|
9842
|
$value = ($self->trim) ? $self->_trim_whitespace($cell->value) : $cell->value; |
474
|
|
|
|
|
|
|
} else { |
475
|
32
|
|
|
|
|
49
|
$value = undef; |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
3584
|
100
|
|
|
|
14386
|
$value = $self->_resolve_null($value, $self->null) |
479
|
|
|
|
|
|
|
if ($self->force_null); |
480
|
|
|
|
|
|
|
|
481
|
3584
|
|
|
|
|
8241
|
push @columns, $value; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# adjust widths, including rowid column |
485
|
368
|
|
|
|
|
363
|
$subc = 0; |
486
|
368
|
|
|
|
|
530
|
for $value (@columns) { |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
# calculate width, ignoring title_row |
489
|
|
|
|
|
|
|
|
490
|
3694
|
100
|
|
|
|
9555
|
if ($subr == $self->title_row) { |
491
|
346
|
|
|
|
|
376
|
$widths[$subc] = 0; |
492
|
|
|
|
|
|
|
} else { |
493
|
3348
|
100
|
100
|
|
|
11934
|
$widths[$subc] = length($value) |
494
|
|
|
|
|
|
|
if (defined($value) && |
495
|
|
|
|
|
|
|
length($value) > $widths[$subc]); |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
|
498
|
3694
|
|
|
|
|
4040
|
$subc++; |
499
|
|
|
|
|
|
|
} |
500
|
|
|
|
|
|
|
|
501
|
368
|
|
|
|
|
994
|
$self->_log->debug(sprintf '@columns [%s]', Dumper(\@columns)); |
502
|
368
|
|
|
|
|
28631
|
$self->_log->debug(sprintf '@widths [%s]', Dumper(\@widths)); |
503
|
|
|
|
|
|
|
|
504
|
368
|
100
|
|
|
|
24671
|
if ($subr == $self->title_row) { |
505
|
36
|
|
|
|
|
192
|
$self->titles([ @columns ]); |
506
|
|
|
|
|
|
|
} else { |
507
|
332
|
|
|
|
|
1009
|
push @data, [ @columns ]; |
508
|
|
|
|
|
|
|
} |
509
|
368
|
|
|
|
|
1242
|
@columns = (); |
510
|
|
|
|
|
|
|
} |
511
|
36
|
|
|
|
|
213
|
$self->widths([ @widths ]); |
512
|
|
|
|
|
|
|
|
513
|
36
|
|
|
|
|
97
|
@widths = $ws = (); |
514
|
|
|
|
|
|
|
|
515
|
36
|
|
|
|
|
331
|
return @data; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
sub colid2title { |
520
|
4
|
|
|
4
|
1
|
10
|
my ($self,$colid)=@_; |
521
|
|
|
|
|
|
|
|
522
|
4
|
50
|
|
|
|
14
|
$self->_log->logcroak("SYNTAX: colid2title2(colid)") |
523
|
|
|
|
|
|
|
unless (defined $colid); |
524
|
|
|
|
|
|
|
|
525
|
4
|
|
|
|
|
25
|
$self->_log->debug("colid [$colid]"); |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
return undef |
528
|
4
|
50
|
|
|
|
37
|
if ($colid < 0); |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
return undef |
531
|
4
|
100
|
|
|
|
5
|
unless ($colid < scalar @{ $self->titles }); |
|
4
|
|
|
|
|
19
|
|
532
|
|
|
|
|
|
|
|
533
|
2
|
|
|
|
|
8
|
return $self->titles->[$colid]; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub title2colid { |
538
|
44
|
|
|
44
|
1
|
84
|
my ($self,$title)=@_; |
539
|
|
|
|
|
|
|
|
540
|
44
|
50
|
|
|
|
96
|
$self->_log->logcroak("SYNTAX: title2colid(title)") |
541
|
|
|
|
|
|
|
unless (defined $title); |
542
|
|
|
|
|
|
|
|
543
|
44
|
|
|
|
|
151
|
$self->_log->debug("title [$title] "); |
544
|
|
|
|
|
|
|
|
545
|
44
|
|
|
|
|
221
|
my $tmax = scalar @{ $self->titles }; |
|
44
|
|
|
|
|
137
|
|
546
|
|
|
|
|
|
|
|
547
|
44
|
|
|
|
|
126
|
for (my $tsub = 0; $tsub < $tmax; $tsub++) { |
548
|
294
|
100
|
|
|
|
789
|
if ($self->titles->[$tsub] =~ /$title/) { |
549
|
30
|
|
|
|
|
107
|
$self->_log->debug("match at colid $tsub"); |
550
|
30
|
|
|
|
|
223
|
return $tsub; |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
} |
553
|
14
|
|
|
|
|
54
|
$self->_log->debug("NO MATCH"); |
554
|
|
|
|
|
|
|
|
555
|
14
|
|
|
|
|
98
|
return undef; |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
sub _trim_whitespace { |
560
|
1526
|
|
|
1526
|
|
4905
|
my ($self,$s_value)=@_; |
561
|
|
|
|
|
|
|
|
562
|
1526
|
50
|
|
|
|
2154
|
if (defined $s_value) { |
563
|
1526
|
|
|
|
|
3097
|
$self->_log->debug("s_value [$s_value]"); |
564
|
|
|
|
|
|
|
|
565
|
1526
|
|
|
|
|
7659
|
$s_value =~ s/^[[:cntrl:][:space:]]+//; # trim leading |
566
|
1526
|
|
|
|
|
2021
|
$s_value =~ s/[[:cntrl:][:space:]]+$//; # trim trailing |
567
|
|
|
|
|
|
|
|
568
|
1526
|
|
|
|
|
3325
|
$self->_log->debug("after s_value [$s_value]"); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
1526
|
|
|
|
|
7015
|
return $s_value; |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
sub _resolve_null { |
576
|
440
|
|
|
440
|
|
408
|
my ($self, $s_value, $s_null)=@_; |
577
|
|
|
|
|
|
|
|
578
|
440
|
100
|
|
|
|
812
|
$self->_log->debug(sprintf "s_value [%s] s_null [%s]", |
|
|
50
|
|
|
|
|
|
579
|
|
|
|
|
|
|
(defined $s_value) ? $s_value : "not defined", |
580
|
|
|
|
|
|
|
(defined $s_null) ? $s_null : "not defined", |
581
|
|
|
|
|
|
|
); |
582
|
|
|
|
|
|
|
|
583
|
440
|
100
|
|
|
|
1886
|
if (defined $s_value) { |
584
|
436
|
100
|
|
|
|
667
|
$s_value = $s_null |
585
|
|
|
|
|
|
|
if ($s_value eq ""); |
586
|
|
|
|
|
|
|
} else { |
587
|
4
|
|
|
|
|
5
|
$s_value = $s_null; |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
440
|
|
|
|
|
504
|
return $s_value; |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
sub _array_to_hash { |
595
|
4
|
|
|
4
|
|
6
|
my $self = shift; |
596
|
4
|
|
|
|
|
5
|
my @data; |
597
|
|
|
|
|
|
|
|
598
|
4
|
|
|
|
|
9
|
for my $row (@_) { |
599
|
40
|
|
|
|
|
118
|
$self->_log->debug(sprintf '$row [%s]', Dumper($row)); |
600
|
|
|
|
|
|
|
|
601
|
40
|
|
|
|
|
2068
|
my %data; |
602
|
40
|
|
|
|
|
41
|
my $unique = 0; |
603
|
40
|
|
|
|
|
49
|
my $m_value = scalar(@$row); |
604
|
|
|
|
|
|
|
|
605
|
40
|
|
|
|
|
81
|
for (my $ss_value = 0; $ss_value < $m_value; $ss_value++) { |
606
|
|
|
|
|
|
|
|
607
|
260
|
|
|
|
|
541
|
my $column = $self->titles->[$ss_value]; |
608
|
260
|
|
|
|
|
249
|
my $value = $row->[$ss_value]; |
609
|
|
|
|
|
|
|
|
610
|
260
|
100
|
|
|
|
369
|
my $key = (exists $data{$column}) ? $column . $unique++ : $column; |
611
|
260
|
|
|
|
|
526
|
$data{$key} = $value; |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
40
|
|
|
|
|
82
|
$self->_log->debug(sprintf 'data [%s]', Dumper(\%data)); |
615
|
|
|
|
|
|
|
|
616
|
40
|
|
|
|
|
2458
|
push @data, { %data }; |
617
|
|
|
|
|
|
|
|
618
|
40
|
|
|
|
|
123
|
%data = (); |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
4
|
|
|
|
|
29
|
return @data; |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
sub extract_hash { |
626
|
2
|
|
|
2
|
1
|
4
|
my $self = shift; |
627
|
|
|
|
|
|
|
|
628
|
2
|
50
|
|
|
|
8
|
$self->_log->logcroak("SYNTAX: extract_hash(sheet_name,[title_row])") |
629
|
|
|
|
|
|
|
unless (@_ > 0); |
630
|
|
|
|
|
|
|
|
631
|
2
|
|
|
|
|
9
|
return $self->_array_to_hash($self->extract(@_)); |
632
|
|
|
|
|
|
|
} |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
sub select_hash { |
636
|
2
|
|
|
2
|
1
|
8481
|
my $self = shift; |
637
|
2
|
|
|
|
|
4
|
my $clause = shift; |
638
|
|
|
|
|
|
|
|
639
|
2
|
50
|
|
|
|
9
|
$self->_log->logcroak("SYNTAX: select_hash(clause,[sheet_name,title_row])") |
640
|
|
|
|
|
|
|
unless (@_ > 0); |
641
|
|
|
|
|
|
|
|
642
|
2
|
|
|
|
|
7
|
return $self->_array_to_hash($self->select($clause, @_)); |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
sub select { |
647
|
14
|
|
|
14
|
1
|
9861
|
my $self = shift; |
648
|
14
|
|
|
|
|
44
|
my $clause = shift; |
649
|
|
|
|
|
|
|
|
650
|
14
|
50
|
|
|
|
47
|
$self->_log->logcroak("SYNTAX: select(clause,[sheet_name,title_row])") |
651
|
|
|
|
|
|
|
unless (defined $clause); |
652
|
|
|
|
|
|
|
|
653
|
14
|
|
|
|
|
56
|
my @pre = $self->extract(@_); |
654
|
14
|
|
|
|
|
34
|
my (@post, @id); |
655
|
0
|
|
|
|
|
0
|
my (@columns, @widths); |
656
|
|
|
|
|
|
|
|
657
|
14
|
100
|
|
|
|
60
|
$clause = join(',', S_RID, $clause) |
658
|
|
|
|
|
|
|
if ($self->rowid); |
659
|
|
|
|
|
|
|
|
660
|
14
|
|
|
|
|
88
|
for my $column (split(/,/, $clause)) { |
661
|
40
|
|
|
|
|
3252
|
$self->_log->debug("column [$column]"); |
662
|
|
|
|
|
|
|
|
663
|
40
|
|
|
|
|
262
|
my $id = $self->title2colid($column); |
664
|
|
|
|
|
|
|
|
665
|
40
|
100
|
|
|
|
81
|
if (defined $id) { |
666
|
28
|
|
|
|
|
48
|
push @id, $id; |
667
|
28
|
|
|
|
|
32
|
push @columns, $column; |
668
|
28
|
|
|
|
|
90
|
push @widths, $self->widths->[$id]; |
669
|
|
|
|
|
|
|
} else { |
670
|
12
|
|
|
|
|
45
|
$self->_log->logwarn("invalid column [$column]"); |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
} |
673
|
|
|
|
|
|
|
|
674
|
14
|
|
|
|
|
977
|
$self->_log->debug(sprintf '@id [%s]', Dumper(\@id)); |
675
|
|
|
|
|
|
|
|
676
|
14
|
100
|
|
|
|
940
|
my $f_no_columns = ($self->rowid) ? 1 : 0; |
677
|
|
|
|
|
|
|
|
678
|
14
|
100
|
|
|
|
51
|
unless (scalar(@columns) == $f_no_columns) { # no columns, thus no rows |
679
|
10
|
|
|
|
|
22
|
for my $row (@pre) { |
680
|
100
|
|
|
|
|
366
|
$self->_log->debug(sprintf 'row [%s]', Dumper($row)); |
681
|
|
|
|
|
|
|
|
682
|
100
|
|
|
|
|
6058
|
my @wanted = (); |
683
|
|
|
|
|
|
|
|
684
|
100
|
|
|
|
|
142
|
for my $id (@id) { |
685
|
260
|
|
|
|
|
372
|
push @wanted, $row->[$id]; |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
|
688
|
100
|
|
|
|
|
321
|
$self->_log->debug(sprintf '@wanted [%s]', Dumper(\@wanted)); |
689
|
|
|
|
|
|
|
|
690
|
100
|
50
|
|
|
|
4811
|
push @post, [ @wanted ] |
691
|
|
|
|
|
|
|
if (scalar(@wanted)); # account for null case |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
} |
694
|
|
|
|
|
|
|
|
695
|
14
|
|
|
|
|
64
|
$self->_log->debug(sprintf '@columns [%s]', Dumper(\@columns)); |
696
|
14
|
|
|
|
|
730
|
$self->_log->debug(sprintf '@widths [%s]', Dumper(\@widths)); |
697
|
|
|
|
|
|
|
|
698
|
14
|
|
|
|
|
702
|
$self->titles([ @columns ]); |
699
|
14
|
|
|
|
|
66
|
$self->widths([ @widths ]); |
700
|
|
|
|
|
|
|
|
701
|
14
|
|
|
|
|
249
|
return @post; |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
DESTROY { |
706
|
24
|
|
|
24
|
|
75790
|
my $self = shift; |
707
|
24
|
|
|
|
|
38
|
-- ${ $self->{_n_objects} }; |
|
24
|
|
|
|
|
3423
|
|
708
|
|
|
|
|
|
|
}; |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
#END { } |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
1; |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
__END__ |