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