File Coverage

lib/Spreadsheet/Write.pm
Criterion Covered Total %
statement 68 84 80.9
branch 14 30 46.6
condition 5 12 41.6
subroutine 13 19 68.4
pod 6 8 75.0
total 106 153 69.2


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Spreadsheet::Write - Writer for spreadsheet files (CSV, XLS, XLSX, ...)
4              
5             =head1 SYNOPSIS
6              
7             Basic usage:
8              
9             use Spreadsheet::Write;
10              
11             my $sp=Spreadsheet::Write->new(file => 'test.xlsx');
12              
13             $sp->addrow('hello','world');
14              
15             $sp->close();
16              
17             More possibilities:
18              
19             use Spreadsheet::Write;
20              
21             my $sp=Spreadsheet::Write->new(
22             file => $ARGV[0], # eg. test.xls, test.xlsx, or test.csv
23             sheet => 'Test Data',
24             styles => {
25             money => {
26             format => '$#,##0.00;-$#,##0.00',
27             },
28             bright => {
29             font_weight => 'bold',
30             font_color => 'blue',
31             font_style => 'italic',
32             },
33             },
34             );
35              
36             $sp->addrow(
37             'col1',
38             { content => [ 'col2', 'col3', 'col4' ], style => 'bright' },
39             { content => 'col5', bg_color => 'gray' },
40             'col6',
41             );
42              
43             $sp->freeze(1,0);
44              
45             $sp->addrow(
46             { content => [ 1, 1.23, 123.45, -234.56 ], style => 'money' },
47             );
48              
49             my @data=(
50             [ qw(1 2 3 4) ],
51             [ qw(a s d f) ],
52             [ qw(z x c v b) ],
53             # ...
54             );
55              
56             foreach my $row (@data) {
57             $sp->addrow({ style => 'ntext', content => $row });
58             }
59              
60             $sp->close();
61              
62             =head1 DESCRIPTION
63              
64             C writes files in CSV, XLS (Microsoft Excel 97),
65             XLSX (Microsoft Excel 2007), and other formats if their drivers
66             exist. It is especially suitable for building various dumps and reports
67             where rows are built in sequence, one after another.
68              
69             The same calling format and options can be used with any output file
70             format. Unsupported options are ignored where possible allowing for easy
71             run-time selection of the output format by file name.
72              
73             =head1 METHODS
74              
75             =cut
76              
77             ###############################################################################
78             package Spreadsheet::Write;
79              
80             require 5.008_009;
81              
82 1     1   13697 use strict;
  1         2  
  1         21  
83 1     1   350 use IO::File;
  1         5107  
  1         664  
84              
85             our $VERSION='1.03';
86              
87             sub version {
88 0     0 0 0 return $VERSION;
89             }
90              
91             ###############################################################################
92              
93             =head2 new ()
94              
95             $spreadsheet = Spreadsheet::Write->new(
96             file => 'table.xls',
97             styles => {
98             mynumber => '#,##0.00',
99             }
100             );
101              
102             Creates a new spreadsheet object. It takes a list of options. The
103             following are valid:
104              
105             file filename of the new spreadsheet or an IO handle (mandatory)
106             encoding encoding of output file (optional, csv format only)
107             format format of spreadsheet - 'csv', 'xls', 'xlsx', or 'auto' (default)
108             sheet Sheet name (optional, not supported by some formats)
109             styles Defines cell formatting shortcuts (optional)
110              
111             If file format is 'auto' (or omitted), the format is guessed from the
112             filename extention. If impossible to guess the format defaults to 'csv'.
113              
114             An IO-like handle can be given as 'file' argument (IO::File, IO::Scalar,
115             etc). In this case the format argument is mandatory.
116              
117             Default styles are:
118             header => {
119             font_weight => 'bold',
120             type => 'string',
121             },
122             ntext => {
123             format => '@',
124             type => 'string',
125             },
126             money => {
127             format => '$#,##0.00;-$#,##0.00',
128             },
129              
130             =cut
131              
132             sub new(@) {
133 6     6 1 215082 my $proto = shift;
134 6 50       35 my $args=ref($_[0]) eq 'HASH' ? $_[0] : {@_};
135              
136 6   0     25 my $filename=$args->{'file'} || $args->{'filename'} || die 'No file given';
137              
138 6   50     19 my $format=$args->{'format'} || 'auto';
139 6 50       16 if($format eq 'auto') {
140 0 0       0 die "Need a 'format' argument for IO-handle in 'file'" if ref $filename;
141 0 0       0 $format=($filename=~/.*\.(.+?)$/) ? lc($1) : 'csv';
142             }
143              
144             # Some commonly used styles
145             #
146 6         10 my %parm=%{$args};
  6         24  
147 6   50     47 $parm{'styles'}->{'ntext'}||={
148             format => '@',
149             type => 'string',
150             };
151 6   50     32 $parm{'styles'}->{'header'}||={
152             font_weight => 'bold',
153             type => 'string',
154             };
155 6   50     30 $parm{'styles'}->{'money'}||={
156             format => '$#,##0.00;-$#,##0.00',
157             };
158              
159             # CPAN ownership of Spreadsheet::Write::CSV and a number of other
160             # simpler names belongs to Toby Inkman, with Spreadsheet::Wright
161             # clone.
162             #
163             my $implementation={
164             csv => 'WriteCSV',
165             xls => 'WriteXLS',
166             xlsx => 'WriteXLSX',
167 6         28 }->{lc $format};
168              
169 6 50       17 $implementation ||
170             die "Format $format is not supported";
171              
172 6         16 $implementation=join('::',(__PACKAGE__,$implementation));
173              
174 1     1   441 eval "use $implementation;";
  1     1   2  
  1     1   14  
  1     1   7  
  1     1   1  
  1     1   13  
  1         372  
  1         3  
  1         13  
  1         7  
  1         2  
  1         17  
  1         321  
  1         3  
  1         14  
  1         4  
  1         2  
  1         11  
  6         325  
175 6 50       17 die $@ if $@;
176              
177 6         25 return $implementation->new(%parm);
178             }
179              
180             ###############################################################################
181              
182             sub DESTROY {
183 6     6   1465 my $self=shift;
184             ### print STDERR "DESTROY: ".ref($self)."\n";
185 6         19 $self->close();
186             }
187              
188             ###############################################################################
189              
190             sub error {
191 0     0 0 0 my $self=shift;
192 0         0 return $self->{'_ERROR'};
193             }
194              
195             ###############################################################################
196              
197             sub _open($) {
198 22     22   24 my $self=shift;
199              
200 22 50       32 $self->{'_CLOSED'} && die "Can't reuse a closed spreadsheet";
201              
202 22         19 my $fh=$self->{'_FH'};
203              
204 22 100       30 if(!$fh) {
205 6   50     11 my $filename=$self->{'_FILENAME'} || return undef;
206              
207 6 50       13 if(ref($filename)) {
208 0         0 $fh=$filename;
209 0         0 $self->{'_EXT_HANDLE'}=1;
210             }
211             else {
212 6         24 $fh=new IO::File;
213 6 50       191 $fh->open($filename,"w") || die "Can't open file $filename for writing: $!";
214 6         587 $fh->binmode(':utf8');
215             }
216             }
217              
218 22         87 $self->{'_FH'}=$fh;
219              
220 22         38 return $self->_prepare;
221             }
222              
223             ###############################################################################
224              
225       0     sub _prepare {
226             # no-op by default
227             }
228              
229             ###############################################################################
230              
231             =head2 addrow(arg1,arg2,...)
232              
233             Adds a row into the spreadsheet. Takes arbitrary number of
234             arguments. Arguments represent cell values and may be strings or hash
235             references. If an argument is a hash reference, it takes the following
236             structure:
237              
238             content value to put into the cell
239             style formatting style, as defined in new(), scalar or array-ref
240             type type of the content (defaults to 'auto')
241             format number format (see Spreadsheet::WriteExcel for details)
242             font_weight weight of font. Only valid value is 'bold'
243             font_style style of font. Only valid value is 'italic'
244             font_decoration 'underline' or 'strikeout' (or both, space separated)
245             font_face font of column; default is 'Arial'
246             font_color color of font (see Spreadsheet::WriteExcel for color values)
247             font_size size of font
248             bg_color color of background (see Spreadsheet::WriteExcel for color values)
249             align alignment
250             valign vertical alignment
251             width column width, excel units (only makes sense once per column)
252             height row height, excel units (only makes sense once per row)
253             comment hidden comment for the cell, where supported
254              
255             Styles can be used to assign default values for any of these formatting
256             parameters thus allowing easy global changes. Other parameters specified
257             override style definitions.
258              
259             Example:
260              
261             my $sp=Spreadsheet::Write->new(
262             file => 'employees.xlsx',
263             styles => {
264             header => { font_weight => 'bold' },
265             },
266             );
267             $sp->addrow(
268             { content => 'First Name', font_weight => 'bold' },
269             { content => 'Last Name', font_weight => 'bold' },
270             { content => 'Age', style => 'header' },
271             );
272             $sp->addrow("John","Doe",34);
273             $sp->addrow("Susan","Smith",28);
274              
275             Note that in this example all header cells will have identical
276             formatting even though some use direct formats and one uses
277             style.
278              
279             If you want to store text that looks like a number you might want to use
280             { type => 'string', format => '@' } arguments. By default the type detection is automatic,
281             as done by for instance L write() method.
282              
283             It is also possible to supply an array reference in the 'content'
284             parameter of the extended format. It means to use the same formatting
285             for as many cells as there are elements in this array. Useful for
286             creating header rows. For instance, the above example can be rewritten
287             as:
288              
289             $sp->addrow(
290             { style => 'header',
291             content => [ 'First Name','Last Name','Age' ],
292             }
293             );
294              
295             Not all styling options are supported in all formats. Where they are not
296             supported they are safely ignored.
297              
298             =cut
299              
300             sub addrow (@) {
301 18     18 1 140 my $self = shift;
302 18 50       32 $self->_open() || return undef;
303              
304 18         20 my @cells;
305              
306 18         31 foreach my $item (@_) {
307 42 100       55 if (ref $item eq 'HASH') {
308 30 100       39 if (ref $item->{'content'} eq 'ARRAY') {
309 18         37 foreach my $i (@{ $item->{'content'} }) {
  18         29  
310 48         96 my %newitem = %$item;
311 48         57 $newitem{'content'} = $i;
312 48         62 push @cells, \%newitem;
313             }
314             }
315             else {
316 12         14 push @cells, $item;
317             }
318             }
319             else {
320 12         20 push @cells, { content => $item };
321             }
322             }
323              
324 18         31 return $self->_add_prepared_row(@cells);
325             }
326              
327             ###############################################################################
328              
329             =head2 addrows([$cell1A,$cell1B,...],[$cell2A,$cell2B,...],...)
330              
331             Shortcut for adding multiple rows.
332              
333             Each argument is an arrayref representing a row.
334              
335             Any argument that is not a reference (i.e. a scalar) is taken to be the
336             title of a new worksheet.
337              
338             =cut
339              
340             sub addrows (@) {
341 0     0 1 0 my $self=shift;
342              
343 0         0 foreach my $row (@_) {
344 0 0       0 if (ref $row eq 'ARRAY') {
    0          
345 0         0 $self->addrow(@$row);
346             }
347             elsif (!ref $row) {
348 0         0 $self->addsheet($row);
349             }
350             else {
351 0         0 warn "Unsupported row format '".ref($row)."'";
352             }
353             }
354              
355 0         0 return $self;
356             }
357              
358             ###############################################################################
359              
360             =head2 addsheet(name)
361              
362             Adds a new sheet into the document and makes it active. Subsequent
363             addrow() calls will add rows to that new sheet.
364              
365             For CSV format this call is NOT ignored, but produces a fatal error
366             currently.
367              
368             =cut
369              
370             sub addsheet ($$) {
371 0     0 1 0 die (((caller(0))[3])." - pure virtual method called");
372             }
373              
374             ###############################################################################
375              
376             =head2 freeze($row, $col, $top_row, $left_col))
377              
378             Sets a freeze-pane at the given position, equivalent to Spreadsheet::WriteExcel->freeze_panes().
379             Ignored for CSV files.
380              
381             =cut
382              
383             sub freeze (@) {
384 2     2 1 14 return shift;
385             }
386              
387             ###############################################################################
388              
389             =head2 close ()
390              
391             Finalizes the spreadsheet and closes the file. It is a good idea
392             to call this method explicitly instead of relying on perl's garbage
393             collector because for many formats the file may be in an unusable
394             state until this method is called.
395              
396             Once a spreadsheet is closed, calls to addrow() will fail.
397              
398             =cut
399              
400             sub close {
401             ### print STDERR "0: ".join("/",map { $_ || 'UNDEF' } caller(0))."\n";
402             ### print STDERR "1: ".join("/",map { $_ || 'UNDEF' } caller(1))."\n";
403             ### print STDERR "2: ".join("/",map { $_ || 'UNDEF' } caller(2))."\n";
404             ### print STDERR "3: ".join("/",map { $_ || 'UNDEF' } caller(3))."\n";
405 0     0 1   die (((caller(0))[3])." - pure virtual method called");
406             }
407              
408             ###############################################################################
409              
410             1;
411             __END__