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"; |
||||||||||||||||||||||
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__ |