line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Excel::Grinder; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = "1.1"; |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# time to grow up |
6
|
1
|
|
|
1
|
|
812
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
7
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
27
|
|
8
|
1
|
|
|
1
|
|
4
|
use Carp; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
67
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# this stands on the feet of giants |
11
|
1
|
|
|
1
|
|
1438
|
use Excel::Writer::XLSX; |
|
1
|
|
|
|
|
236713
|
|
|
1
|
|
|
|
|
62
|
|
12
|
1
|
|
|
1
|
|
633
|
use Spreadsheet::XLSX; |
|
1
|
|
|
|
|
67660
|
|
|
1
|
|
|
|
|
797
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# OO out of habit |
15
|
|
|
|
|
|
|
sub new { |
16
|
1
|
|
|
1
|
1
|
547
|
my ($class, $default_directory) = @_; |
17
|
|
|
|
|
|
|
|
18
|
1
|
|
|
|
|
2
|
my $path_separator = '/'; |
19
|
1
|
|
|
|
|
3
|
my $temp_directory = '/tmp'; |
20
|
|
|
|
|
|
|
|
21
|
1
|
50
|
|
|
|
7
|
if( $^O eq "MSWin32" ){ |
22
|
0
|
|
|
|
|
0
|
$path_separator = '\\'; |
23
|
0
|
|
|
|
|
0
|
$temp_directory = $ENV{'temp'}; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
# default the default directory to /tmp/excel_grinder |
26
|
1
|
|
33
|
|
|
15
|
$default_directory ||= $temp_directory . $path_separator . 'excel_grinder'; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# make sure that directory exists |
29
|
1
|
50
|
|
|
|
305
|
mkdir $default_directory if !(-d $default_directory); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# if it still does exist, bail out |
32
|
1
|
50
|
|
|
|
20
|
croak "Error: $default_directory does not exist and cannot be auto-created." if !(-d $default_directory); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# become! |
35
|
1
|
|
|
|
|
6
|
my $self = bless { |
36
|
|
|
|
|
|
|
'default_directory' => $default_directory, |
37
|
|
|
|
|
|
|
'path_separator' => $path_separator, |
38
|
|
|
|
|
|
|
}, $class; |
39
|
|
|
|
|
|
|
|
40
|
1
|
|
|
|
|
5
|
return $self; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# method to convert a three-level array into a nice excel file |
44
|
|
|
|
|
|
|
sub write_excel { |
45
|
|
|
|
|
|
|
# required arguments are (1) the filename and (2) the data structure to turn into an XLSX file |
46
|
1
|
|
|
1
|
1
|
459
|
my ($self, %args) = @_; |
47
|
|
|
|
|
|
|
# looks like: |
48
|
|
|
|
|
|
|
# 'filename' => 'some_file.xlsx', # will be saved under /opt/majestica/tmp/DATABASE_NAME/some_file.xlsx; required |
49
|
|
|
|
|
|
|
# 'the_data' => @$three_level_arrayref, # worksheets->rows->columns; see below; required |
50
|
|
|
|
|
|
|
# 'headings_in_data' => 1, # if filled, first row of each worksheet will be captialized; optional |
51
|
|
|
|
|
|
|
# 'worksheet_names' => ['Names','of','Worksheets'], # if filled, will be the names to give the worksheets |
52
|
|
|
|
|
|
|
|
53
|
1
|
|
|
|
|
2
|
my ($tmp_dir, $item, $col, @bits, $workbook, $worksheet_data, $worksheet, $n, $row_array, $row_upper, $worksheet_name); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# fail without a filename |
56
|
1
|
50
|
|
|
|
4
|
croak 'Error: Filename required for write_excel()' if !$args{filename}; |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# the data structure must be an array of arrays of arrays |
59
|
|
|
|
|
|
|
# three levels: worksheets, rows, columns |
60
|
1
|
50
|
|
|
|
3
|
croak 'Error: Must send a three-level arrayref (workbook->rows->columns) to write_excel()' if !$args{the_data}[0][0][0]; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# place into default_directory unless they specified a directory |
63
|
|
|
|
|
|
|
|
64
|
1
|
50
|
|
|
|
21
|
$args{filename} = $self->{default_directory}.$self->{path_separator}.$args{filename} if $args{filename} !~ m#$self->{path_separator}#; |
65
|
1
|
50
|
|
|
|
6
|
$args{filename} .= '.xlsx' if $args{filename} !~ /\.xlsx$/; |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# start our workbook |
68
|
1
|
|
|
|
|
9
|
$workbook = Excel::Writer::XLSX->new( $args{filename} ); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# Set the format for dates. |
71
|
1
|
|
|
|
|
799
|
my $date_format = $workbook->add_format( num_format => 'mm/dd/yy' ); |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# start adding worksheets |
74
|
1
|
|
|
|
|
105
|
foreach $worksheet_data (@{ $args{the_data} }) { |
|
1
|
|
|
|
|
2
|
|
75
|
2
|
|
|
|
|
4
|
$worksheet_name = shift @{ $args{worksheet_names} }; # if it's there |
|
2
|
|
|
|
|
4
|
|
76
|
2
|
|
|
|
|
8
|
$worksheet_name =~ s/[^0-9a-z\-\s]//gi; # clean it up |
77
|
2
|
|
|
|
|
23
|
$worksheet = $workbook->add_worksheet($worksheet_name); |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# go thru each row... |
80
|
2
|
|
|
|
|
697
|
$n = 0; |
81
|
2
|
|
|
|
|
5
|
foreach $row_array (@$worksheet_data) { |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
# do they want the first row to the headings? |
84
|
9
|
100
|
66
|
|
|
56
|
if ($args{headings_in_data} && $n == 0) { # uppercase the first row |
85
|
2
|
|
|
|
|
7
|
@$row_upper = map { uc($_) } @$row_array; |
|
6
|
|
|
|
|
24
|
|
86
|
2
|
|
|
|
|
20
|
$row_array = $row_upper; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# now each column... |
90
|
9
|
|
|
|
|
29
|
$col = 0; |
91
|
9
|
|
|
|
|
18
|
foreach $item (@$row_array) { |
92
|
|
|
|
|
|
|
# dates are no funzies |
93
|
27
|
50
|
|
|
|
1492
|
if ($item =~ /^(\d{4})-(\d{2})-(\d{2})$/) { # special routine for dates |
94
|
0
|
|
|
|
|
0
|
$worksheet->write_date_time( $n, $col++, $1.'-'.$2.'-'.$3.'T', $date_format ); |
95
|
|
|
|
|
|
|
} else { |
96
|
27
|
|
|
|
|
96
|
$worksheet->write( $n, $col++, $item ); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
} |
100
|
9
|
|
|
|
|
709
|
$n++; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# that's not so hard, now is it? |
105
|
1
|
|
|
|
|
11
|
return $args{filename}; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# method to import an excel file into a nice three-level array |
109
|
|
|
|
|
|
|
sub read_excel { |
110
|
|
|
|
|
|
|
# require argument is the filename or full path to the excel xlsx file |
111
|
|
|
|
|
|
|
# if it's just a filename, look in the default directory |
112
|
1
|
|
|
1
|
1
|
40720
|
my ($self,$filename) = @_; |
113
|
|
|
|
|
|
|
|
114
|
1
|
50
|
|
|
|
25
|
$filename = $self->{default_directory}.$self->{path_separator}.$filename if $filename !~ m#$self->{path_separator}#; |
115
|
1
|
50
|
|
|
|
8
|
$filename .= '.xlsx' if $filename !~ /\.xlsx$/; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# gotta exist, after all that |
118
|
1
|
50
|
|
|
|
18
|
croak 'Error: Must send a valid full file path to an XLSX file to read_excel()' if !(-e "$filename"); |
119
|
|
|
|
|
|
|
|
120
|
1
|
|
|
|
|
4
|
my ($excel, $sheet_num, $sheet, $row_num, $row, @the_data, $cell, $col); |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# again, stand on the shoulders of giants |
123
|
1
|
|
|
|
|
11
|
$excel = Spreadsheet::XLSX->new($filename); |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# read it in, sheet by sheet |
126
|
1
|
|
|
|
|
18080
|
$sheet_num = 0; |
127
|
1
|
|
|
|
|
3
|
foreach $sheet (@{$excel->{Worksheet}}) { |
|
1
|
|
|
|
|
5
|
|
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# set the max = 0 if there is one or none rows |
130
|
2
|
|
33
|
|
|
6
|
$sheet->{MaxRow} ||= $sheet->{MinRow}; |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# same for the columns |
133
|
2
|
|
33
|
|
|
5
|
$sheet->{MaxCol} ||= $sheet->{MinCol}; |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# cycle through each row |
136
|
2
|
|
|
|
|
3
|
$row_num = 0; |
137
|
2
|
|
|
|
|
6
|
foreach $row ($sheet->{MinRow} .. $sheet->{MaxRow}) { |
138
|
|
|
|
|
|
|
# go through each available column |
139
|
9
|
|
|
|
|
17
|
foreach $col ($sheet->{MinCol} .. $sheet->{MaxCol}) { |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# get ahold of the actual cell object |
142
|
27
|
|
|
|
|
35
|
$cell = $sheet->{Cells}[$row][$col]; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# next if !$cell; # skip if blank |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# add it to our nice array |
147
|
27
|
|
|
|
|
28
|
push (@{ $the_data[$sheet_num][$row] }, $cell->{Val} ); |
|
27
|
|
|
|
|
54
|
|
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
# advance |
150
|
9
|
|
|
|
|
15
|
$row_num++; |
151
|
|
|
|
|
|
|
} |
152
|
2
|
|
|
|
|
13
|
$sheet_num++; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# send it back |
156
|
1
|
|
|
|
|
32
|
return \@the_data; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
1; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
__END__ |