File Coverage

blib/lib/IO/StructuredOutput.pm
Criterion Covered Total %
statement 105 118 88.9
branch 33 54 61.1
condition 9 14 64.2
subroutine 20 20 100.0
pod 7 10 70.0
total 174 216 80.5


line stmt bran cond sub pod time code
1             package IO::StructuredOutput;
2              
3              
4             # I think I need to create a worksheet package, that this will inherit from.
5             # the worksheet will have most of the shit in it.
6             # I don't know how of if that'll work, but I can't figure out any way
7             # to make this work right now.
8             # I should make some test modules to do something similar to what I want,
9             # but just stick to one output or something.
10              
11 1     1   18622 use 5.00503;
  1         4  
  1         59  
12 1     1   6 use strict;
  1         3  
  1         45  
13 1     1   7 use Carp qw(croak);
  1         8  
  1         147  
14 1     1   5087 use Spreadsheet::WriteExcel;
  1         124212  
  1         40  
15 1     1   881 use IO::Scalar;
  1         5874  
  1         45  
16 1     1   981 use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
  1         62978  
  1         172  
17              
18             require Exporter;
19 1     1   501 use IO::StructuredOutput::Sheets;
  1         3  
  1         72  
20 1     1   868 use IO::StructuredOutput::Styles;
  1         11  
  1         85  
21 1     1   9 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         3  
  1         2378  
22             @ISA = qw(Exporter);
23              
24             # Items to export into callers namespace by default. Note: do not export
25             # names by default without a very good reason. Use EXPORT_OK instead.
26             # Do not simply export all your public functions/methods/constants.
27              
28             # This allows declaration use IO::StructuredOutput ':all';
29             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
30             # will save memory.
31             %EXPORT_TAGS = ( 'all' => [ qw(
32            
33             ) ] );
34              
35             @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
36              
37             @EXPORT = qw(
38            
39             );
40              
41             #$VERSION = do { my @r = (q$Revision: 1.8 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
42             $VERSION = sprintf '%d.%03d', q$Revision: 1.8 $ =~ /(\d+)/g;
43              
44             # valid output formats
45             my %valid_output_format = (
46             'html' => 1,
47             'csv' => 1,
48             'xls' => 1
49             );
50              
51             # Preloaded methods go here.
52              
53             sub new
54             {
55 4     4 1 3195 my $proto = shift;
56 4   33     30 my $class = ref($proto) || $proto;
57             # ref(my $class = shift) and croak "class name needed";
58 4         25 my $self = {
59             Format => 'html', # default format
60             Sytle => '',
61             wb => "",
62             Sheets => [ ]
63             };
64 4         23 bless $self, $class;
65             }
66              
67             sub addsheet
68             {
69 6 50   6 1 33 ref(my $self = shift) or croak "instance variable needed";
70 6   50     23 my $sheetnum = $_[0] || "";
71 6         21 $sheetnum =~ s/[:*?\/\\]//g; # get rid of invalid chars
72 6 50 66     15 if ( ($self->format() eq 'xls') && (length($sheetnum) > 31) )
73             { # max length for excel is 31 chars
74 0         0 $sheetnum = substr($sheetnum,0,31);
75             }
76 6         18 my $sheetcount = $self->sheetcount();
77 6 50       18 unless ($sheetnum)
78             {
79 0         0 $sheetnum = "Sheet " . ($sheetcount + 1);
80             }
81 6 50       18 if ($self->sheetnames($sheetnum))
82             { # name already in use
83 0         0 croak "Sheet '$sheetnum' already exists";
84             }
85              
86 6         18 $self->add_sheetname($sheetnum);
87              
88 6         41 my $wb;
89 6 100 100     14 if ( ($self->format() eq 'xls') && (! ref($self->{wb})) )
90             { # need to create a workbook if we haven't already
91 1         1 my $datablob;
92 1         20 $self->{wb} = Spreadsheet::WriteExcel->new( IO::Scalar->new_tie(\$datablob) );
93 1         16635 $self->{datablob} = \$datablob;
94             # } elsif ( ($self->format() eq 'html') && (! ref($self->{wb})) ){
95             # # first sheet added.
96             # # may need to do something here
97             }
98              
99             # need to setup the default style if we haven't already
100 6 100       23 if (! $self->defaultstyle())
101             {
102 3         12 $self->{Style} = $self->addstyle();
103             }
104              
105 6         17 my $sheet = IO::StructuredOutput::Sheets->addsheet(
106             {
107             name => $sheetnum,
108             format => $self->format(),
109             style => $self->defaultstyle(),
110             wb => $self->{wb} } );
111 6         20 push( @{ $self->{Sheets} }, $sheet);
  6         15  
112 6         23 return $sheet;
113             }
114              
115             sub output
116             {
117 3 50   3 1 14 ref(my $self = shift) or croak "instance variable needed";
118             # need to do this still
119 3         8 my $format = $self->format();
120 3 100       23 if ($format eq 'csv')
    100          
    50          
121             { # zip up all "sheets", return zip file
122 1         15 my $zip = Archive::Zip->new();
123 1         55 foreach my $sheet ($self->sheets())
124             {
125 2         21 my $member = $zip->addString($sheet->sheet(),$sheet->name());
126 2         544 $member->desiredCompressionMethod( COMPRESSION_DEFLATED );
127             }
128 1         12 my $zipfile;
129 1         10 my $zipfh = IO::Scalar->new(\$zipfile);
130 1         187 $zip->writeToFileHandle( $zipfh );
131 1         2325 return \$zipfile;
132             } elsif ($format eq 'html') {
133 1         1 my $output;
134 1         4 foreach my $sheet ($self->sheets())
135             {
136 2         10 $output .= "
" . $sheet->name() .
137             "
\n\n";
138 2         10 $output .= $sheet->sheet();
139 2         7 $output .= "
\n
\n";
140             }
141 1         4 return \$output;
142             } elsif ($format eq 'xls') {
143 1         16 $self->{wb}->close;
144 1         9753 return $self->{datablob};
145             }
146             }
147              
148             sub format
149             { # set output format
150 39 50   39 1 513 ref(my $self = shift) or croak "instance variable needed";
151 39 100       82 if (@_)
152             { # are there any more parameters? (it's a setter)
153 6         12 my $newformat = shift;
154 6 50       16 if ($self->_valid_output_format($newformat))
155             { # it's a valid format, set it
156 6         15 $self->{Format} = $newformat;
157 6         20 return $self->{Format};
158             } else {
159             # invalid output format, return undef
160 0         0 return;
161             }
162             } else { # no, it's a getter:
163 33         198 return $self->{Format};
164             }
165             }
166              
167             sub defaultstyle
168             {
169 12 50   12 1 35 ref(my $self = shift) or croak "instance variable needed";
170 12 50       25 if (@_)
171             { # are there any more parameters? (it's a setter)
172 0         0 my $info = shift;
173 0         0 $self->{Style} = $self->addstyle($info);
174 0         0 return $self->{Style};
175             } else {
176 12         94 return $self->{Style};
177             }
178             }
179              
180             sub addstyle
181             {
182 3 50   3 1 10 ref(my $self = shift) or croak "instance variable needed";
183 3         6 my $info = shift;
184              
185 3 50 66     9 if ( ($self->format() eq 'xls') && (! ref($self->{wb})) )
186             { # need to create a workbook if we haven't already
187 0         0 my $datablob;
188 0         0 $self->{wb} = Spreadsheet::WriteExcel->new( IO::Scalar->new_tie(\$datablob) );
189 0         0 $self->{datablob} = \$datablob;
190             }
191              
192 3         5 my $wbformat;
193 3 100       8 if ($self->format() eq 'xls')
194             {
195 1         16 $wbformat = $self->{wb}->add_format();
196             }
197              
198 3         93 my $style = IO::StructuredOutput::Styles->addstyle(
199             {
200             format => $self->format(),
201             wbformat => $wbformat,
202             wb => $self->{wb}
203             } );
204             # if they gave us some params, set them up for them
205 3 50       14 $style->modify($info) if $info;
206              
207             # give them the style object back
208 3         11 return $style;
209             }
210              
211             sub sheetnames
212             {
213 6 50   6 0 17 ref(my $self = shift) or croak "instance variable needed";
214 6 50       14 if ($_[0])
215             {
216 6 50       22 return 1 if ($self->{Sheetnames}{$_[0]});
217 6         16 return;
218             } else {
219 0         0 return keys %{ $self->{Sheetnames} };
  0         0  
220             }
221             }
222              
223             sub add_sheetname
224             {
225 6 50   6 0 29 ref(my $self = shift) or croak "instance variable needed";
226 6 50       15 if ($_[0])
227             {
228 6         25 $self->{Sheetnames}{$_[0]}++;
229             }
230             }
231              
232             sub _valid_output_format
233             { # internal method. Can be useful from the outside, but &format
234             # already checks this, and they should be using that anyway
235 6     6   9 my $either = shift;
236 6 50       13 if (ref($either))
237             { # called from instance
238 6         9 my $testformat = shift;
239 6         23 return $valid_output_format{$testformat};
240             } else {
241 0         0 return $valid_output_format{$either};
242             }
243             }
244              
245             sub sheets
246             { # returns an array of all sheet objects
247 2 50   2 0 8 ref(my $self = shift) or croak "instance variable needed";
248 2         49 return @{ $self->{Sheets} };
  2         10  
249             }
250              
251             sub sheetcount
252             {
253 12 50   12 1 39 ref(my $self = shift) or croak "instance variable needed";
254 12         14 return scalar(@{ $self->{Sheets} });
  12         64  
255             }
256              
257             1;
258             __END__