File Coverage

blib/lib/CPAN/Testers/WWW/Statistics/Excel.pm
Criterion Covered Total %
statement 135 135 100.0
branch 48 52 92.3
condition 48 49 97.9
subroutine 13 13 100.0
pod 2 2 100.0
total 246 251 98.0


line stmt bran cond sub pod time code
1             package CPAN::Testers::WWW::Statistics::Excel;
2              
3 9     9   208856 use warnings;
  9         25  
  9         339  
4 9     9   51 use strict;
  9         14  
  9         324  
5 9     9   48 use vars qw($VERSION);
  9         22  
  9         686  
6              
7             $VERSION = '0.05';
8              
9             #----------------------------------------------------------------------------
10              
11             =head1 NAME
12              
13             CPAN::Testers::WWW::Statistics::Excel - CPAN Testers Statistics Excel tool.
14              
15             =head1 SYNOPSIS
16              
17             my %hash = { logfile => 'my.log' };
18             my $ct = CPAN::Testers::WWW::Statistics::Excel->new(%hash);
19             $ct->create( source => $source, target => $target );
20              
21             =head1 DESCRIPTION
22              
23             Using previously formatted data, generate Excel format files.
24              
25             =cut
26              
27             # -------------------------------------
28             # Library Modules
29              
30 9     9   49 use base qw(Class::Accessor::Fast);
  9         26  
  9         8722  
31              
32 9     9   51288 use File::Basename;
  9         20  
  9         1179  
33 9     9   54 use File::Path;
  9         20  
  9         662  
34 9     9   12487 use HTML::Entities;
  9         95186  
  9         983  
35 9     9   8841 use HTML::TokeParser;
  9         49737  
  9         348  
36 9     9   7414 use IO::File;
  9         94594  
  9         1587  
37 9     9   35926 use Spreadsheet::WriteExcel;
  9         1080620  
  9         14398  
38              
39             # -------------------------------------
40             # Variables
41              
42             my %format_config = (
43             head => { border => 1, pattern => 1, color => 'black', bg_color => 'gray', bold => 1 },
44             lots => { border => 1, pattern => 1, color => 'black', bg_color => 'green', align => 'right' },
45             more => { border => 1, pattern => 1, color => 'black', bg_color => 'lime', align => 'right' },
46             some => { border => 1, pattern => 1, color => 'black', bg_color => 'yellow', align => 'right' },
47             none => { border => 1, pattern => 1, color => 'black', bg_color => 'silver', align => 'center', valign => 'middle' },
48             totals => { border => 1, pattern => 1, color => 'white', bg_color => 'black', bold => 1 },
49             );
50              
51             # -------------------------------------
52             # Subroutines
53              
54             =head1 INTERFACE
55              
56             =head2 The Constructor
57              
58             =over 4
59              
60             =item * new
61              
62             Object constructor. Takes an optional hash, which can contain initial settings
63             for log file creation:
64              
65             logfile - path to log file
66             logclean - append (0) or overwrite/create (1)
67              
68             =back
69              
70             =cut
71              
72             sub new {
73 6     6 1 7304 my $class = shift;
74 6         25 my %hash = @_;
75              
76 6         15 my $self = {};
77 6         19 bless $self, $class;
78              
79 6   100     61 $self->logfile( $hash{logfile} || '' );
80 6   100     133 $self->logclean( $hash{logclean} || 0 );
81              
82 6         42 $self->_log("logfile =" . $self->logfile );
83 6         205 $self->_log("logclean =" . $self->logclean );
84              
85 6         136 return $self;
86             }
87              
88             =head2 Methods
89              
90             =over 4
91              
92             =item * create
93              
94             Method to facilitate the creation of an Excel file.
95              
96             Parameter values are contained within a hash to the method:
97              
98             source - path to source HTML containing table
99             target - path to target Excel format file
100              
101             In addition the following hash values can also be passed:
102              
103             title - title for the file (Excel property)
104             author - author of the file (Excel property)
105             comments - comments string (Excel property)
106              
107             =item * logfile
108              
109             Accessor for the path to the file to use for log messages. If no path is given
110             either via this method or through the constructor, no log messages are printed.
111              
112             =item * logclean
113              
114             Accessor for log creation. If a false value will append log messages,
115             otherwise will overwrite any existing logfile.
116              
117             =back
118              
119             =cut
120              
121             __PACKAGE__->mk_accessors( qw( logfile logclean ) );
122              
123              
124             sub create {
125 5     5 1 2032 my $self = shift;
126 5         17 my %hash = @_;
127 5         7 my %opt;
128              
129 5         20 $self->_log("start");
130              
131 5 100       49 die "Source file not provided\n" unless( $hash{source});
132 4 100       18 die "Target file not provided\n" unless( $hash{target});
133 3 100       69 die "Source file [$hash{source}] not found\n" unless(-f $hash{source});
134 2         307 mkpath(dirname($hash{target}));
135              
136 2         20 my $workbook = Spreadsheet::WriteExcel->new( $hash{target} );
137              
138 2         16690 $workbook->set_custom_color(23, '#999999'); # head
139 2         85 $workbook->set_custom_color(17, '#00ff00'); # lots
140 2         48 $workbook->set_custom_color(11, '#99ff99'); # more
141 2         120 $workbook->set_custom_color(13, '#ddffdd'); # some
142 2         46 $workbook->set_custom_color(22, '#dddddd'); # none
143              
144             # Add and define a format
145 2         38 my %formats;
146 2         12 for my $format (keys %format_config) {
147 12         16 my $class = $workbook->add_format( %{ $format_config{$format} } ); # Add a format
  12         72  
148 12         1872 $formats{$format} = $class;
149             }
150              
151 2         15 my $worksheet = $workbook->add_worksheet();
152              
153 2         961 my $cell = {};
154 2         5 my ($title,$table,$row,$col) = (0,0,0,0);
155 2         22 my $p = HTML::TokeParser->new( $hash{source}, %opt );
156 2         662 while(my $token = $p->get_token) {
157              
158             # if no title given, use the H2 tag.
159 36232 100 100     407263 unless($table || $hash{title}) {
160 192 100 100     585 if($token->[0] eq 'S' && $token->[1] eq 'h2') {
161 1         3 $title = 1;
162 1         4 $cell = {text => ''};
163 1         7 next;
164             }
165 191 100 100     457 if($token->[0] eq 'E' && $token->[1] eq 'h2') {
166 1         2 $title = 0;
167 1         10 $hash{title} = decode_entities($cell->{text});
168 1         8 $self->_log("TITLE: '$cell->{text}'");
169 1         12 next;
170             }
171 190 100 66     421 if($title && $token->[0] eq 'T') {
172 1 50       4 $cell->{text} .= "\n" if($cell->{text});
173 1         4 $cell->{text} .= $token->[1];
174             }
175             }
176              
177 36230 100 100     74748 next unless($table || $token->[1] eq 'table');
178              
179 36002 100 100     118138 if($token->[0] eq 'S' && $token->[1] eq 'table') {
180 2         4 $table = 1;
181 2         13 next;
182             }
183 36000 100 100     114234 if($token->[0] eq 'E' && $token->[1] eq 'table') {
184 2         3 $table = 0;
185 2         4 last;
186             }
187              
188 35998 100 100     113898 if($token->[0] eq 'S' && $token->[1] eq 'tr') {
189 129         218 $col = 0;
190 129         571 next;
191             }
192 35869 100 100     95925 if($token->[0] eq 'E' && $token->[1] eq 'tr') {
193 129         149 $row++;
194 129         471 next;
195             }
196              
197 35740 100 100     113322 if($token->[0] eq 'S' && $token->[1] eq 'th') {
198 1116         3514 $cell = { class => 'head', text => '' };
199 1116 100       3550 if($token->[2]->{class}) {
200 550         1782 $cell = { class => $token->[2]->{class}, text => '' };
201             }
202 1116         5059 next;
203             }
204 34624 100 100     94232 if($token->[0] eq 'E' && $token->[1] eq 'th') {
205             # write cell
206 1116         4687 $self->_log("CELL: TH: [$row/$col] $cell->{class} '$cell->{text}'");
207 1116         12730 $worksheet->write($row, $col, decode_entities($cell->{text}), $formats{$cell->{class}});
208 1116         89285 $col++;
209 1116         4496 next;
210             }
211              
212 33508 100 100     95191 if($token->[0] eq 'S' && $token->[1] eq 'td') {
213 9075         27188 $cell = { class => 'none', text => '' };
214 9075 50       31661 if($token->[2]->{class}) {
215 9075         25773 $cell = { class => $token->[2]->{class}, text => '' };
216             }
217 9075         46357 next;
218             }
219 24433 100 100     83286 if($token->[0] eq 'E' && $token->[1] eq 'td') {
220             # write cell
221 9075         42104 $self->_log("CELL: TD: [$row/$col] $cell->{class} '$cell->{text}'");
222 9075         108398 $worksheet->write($row, $col, decode_entities($cell->{text}), $formats{$cell->{class}});
223 9075         783474 $col++;
224 9075         34989 next;
225             }
226              
227 15358 100       52086 if($token->[0] eq 'T') {
228 11566 100       23262 $cell->{text} .= "\n" if($cell->{text});
229 11566         70529 $cell->{text} .= $token->[1];
230             }
231             }
232              
233 2   100     12 $hash{title} ||= 'CPAN Testers Matrix';
234 2   100     12 $hash{author} ||= 'CPAN Testers';
235 2   100     10 $hash{comments} ||= 'Copyright (C) 2009 The Perl Foundation';
236              
237 2         9 $worksheet->set_landscape(); # Landscape mode
238 2         15 $worksheet->set_paper(9); # A4
239 2         17 $worksheet->fit_to_pages(0, 1); # 1 page deep, many wide
240 2         24 $worksheet->set_header('&L&D&C'.$hash{title}.'&R&T');
241 2         39 $worksheet->set_footer('&RPage &P of &N');
242              
243 2         39 $worksheet->repeat_rows(0, 1); # Repeat the first two rows
244 2         16 $worksheet->repeat_columns(0, 1); # Repeat the first two columns
245              
246              
247 2         39 $workbook->set_properties(
248             title => $hash{title},
249             author => $hash{author},
250             comments => $hash{comments},
251             );
252              
253 2 50       908 $workbook->close() or die "Error closing file: $!";
254 2         67428 $self->_log("finish");
255             }
256              
257             # -------------------------------------
258             # Private Methods
259              
260             sub _log {
261 10215     10215   21625 my $self = shift;
262 10215 100       25335 my $log = $self->logfile or return;
263 10 100       535 mkpath(dirname($log)) unless(-f $log);
264              
265 10 100       33 my $mode = $self->logclean ? 'w+' : 'a+';
266 10         79 $self->logclean(0);
267              
268 10         434 my @dt = localtime(time);
269 10         76 my $dt = sprintf "%04d/%02d/%02d %02d:%02d:%02d", $dt[5]+1900,$dt[4]+1,$dt[3],$dt[2],$dt[1],$dt[0];
270              
271 10 50       121 my $fh = IO::File->new($log,$mode) or die "Cannot write to log file [$log]: $!\n";
272 10         1418 print $fh "$dt ", @_, "\n";
273 10         46 $fh->close;
274             }
275              
276             q('This module is dedicated to the Birmingham Perl Mongers');
277              
278             __END__