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   120602 use warnings;
  9         29  
  9         315  
4 9     9   40 use strict;
  9         10  
  9         264  
5 9     9   39 use vars qw($VERSION);
  9         12  
  9         564  
6              
7             $VERSION = '0.06';
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   43 use base qw(Class::Accessor::Fast);
  9         18  
  9         4865  
31              
32 9     9   64986 use File::Basename;
  9         18  
  9         772  
33 9     9   44 use File::Path;
  9         11  
  9         414  
34 9     9   5311 use HTML::Entities;
  9         120064  
  9         671  
35 9     9   4664 use HTML::TokeParser;
  9         33189  
  9         259  
36 9     9   3994 use IO::File;
  9         65644  
  9         1224  
37 9     9   88456 use Spreadsheet::WriteExcel;
  9         673255  
  9         10515  
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 4024 my $class = shift;
74 6         18 my %hash = @_;
75              
76 6         9 my $self = {};
77 6         14 bless $self, $class;
78              
79 6   100     45 $self->logfile( $hash{logfile} || '' );
80 6   100     99 $self->logclean( $hash{logclean} || 0 );
81              
82 6         32 $self->_log("logfile =" . $self->logfile );
83 6         150 $self->_log("logclean =" . $self->logclean );
84              
85 6         92 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 1994 my $self = shift;
126 5         18 my %hash = @_;
127 5         6 my %opt;
128              
129 5         18 $self->_log("start");
130              
131 5 100       42 die "Source file not provided\n" unless( $hash{source});
132 4 100       14 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         354 mkpath(dirname($hash{target}));
135              
136 2         19 my $workbook = Spreadsheet::WriteExcel->new( $hash{target} );
137              
138 2         417241 $workbook->set_custom_color(23, '#999999'); # head
139 2         83 $workbook->set_custom_color(17, '#00ff00'); # lots
140 2         33 $workbook->set_custom_color(11, '#99ff99'); # more
141 2         52 $workbook->set_custom_color(13, '#ddffdd'); # some
142 2         30 $workbook->set_custom_color(22, '#dddddd'); # none
143              
144             # Add and define a format
145 2         28 my %formats;
146 2         10 for my $format (keys %format_config) {
147 12         11 my $class = $workbook->add_format( %{ $format_config{$format} } ); # Add a format
  12         48  
148 12         1388 $formats{$format} = $class;
149             }
150              
151 2         11 my $worksheet = $workbook->add_worksheet();
152              
153 2         990 my $cell = {};
154 2         4 my ($title,$table,$row,$col) = (0,0,0,0);
155 2         16 my $p = HTML::TokeParser->new( $hash{source}, %opt );
156 2         458 while(my $token = $p->get_token) {
157              
158             # if no title given, use the H2 tag.
159 36232 100 100     268662 unless($table || $hash{title}) {
160 192 100 100     453 if($token->[0] eq 'S' && $token->[1] eq 'h2') {
161 1         2 $title = 1;
162 1         3 $cell = {text => ''};
163 1         2 next;
164             }
165 191 100 100     387 if($token->[0] eq 'E' && $token->[1] eq 'h2') {
166 1         1 $title = 0;
167 1         7 $hash{title} = decode_entities($cell->{text});
168 1         5 $self->_log("TITLE: '$cell->{text}'");
169 1         8 next;
170             }
171 190 100 66     379 if($title && $token->[0] eq 'T') {
172 1 50       3 $cell->{text} .= "\n" if($cell->{text});
173 1         3 $cell->{text} .= $token->[1];
174             }
175             }
176              
177 36230 100 100     55145 next unless($table || $token->[1] eq 'table');
178              
179 36002 100 100     82995 if($token->[0] eq 'S' && $token->[1] eq 'table') {
180 2         4 $table = 1;
181 2         9 next;
182             }
183 36000 100 100     75307 if($token->[0] eq 'E' && $token->[1] eq 'table') {
184 2         3 $table = 0;
185 2         5 last;
186             }
187              
188 35998 100 100     80193 if($token->[0] eq 'S' && $token->[1] eq 'tr') {
189 129         112 $col = 0;
190 129         348 next;
191             }
192 35869 100 100     72567 if($token->[0] eq 'E' && $token->[1] eq 'tr') {
193 129         102 $row++;
194 129         289 next;
195             }
196              
197 35740 100 100     75996 if($token->[0] eq 'S' && $token->[1] eq 'th') {
198 1116         2400 $cell = { class => 'head', text => '' };
199 1116 100       2781 if($token->[2]->{class}) {
200 550         1074 $cell = { class => $token->[2]->{class}, text => '' };
201             }
202 1116         3287 next;
203             }
204 34624 100 100     71150 if($token->[0] eq 'E' && $token->[1] eq 'th') {
205             # write cell
206 1116         3420 $self->_log("CELL: TH: [$row/$col] $cell->{class} '$cell->{text}'");
207 1116         9375 $worksheet->write($row, $col, decode_entities($cell->{text}), $formats{$cell->{class}});
208 1116         75394 $col++;
209 1116         3487 next;
210             }
211              
212 33508 100 100     71475 if($token->[0] eq 'S' && $token->[1] eq 'td') {
213 9075         18403 $cell = { class => 'none', text => '' };
214 9075 50       21726 if($token->[2]->{class}) {
215 9075         16834 $cell = { class => $token->[2]->{class}, text => '' };
216             }
217 9075         26039 next;
218             }
219 24433 100 100     52332 if($token->[0] eq 'E' && $token->[1] eq 'td') {
220             # write cell
221 9075         24069 $self->_log("CELL: TD: [$row/$col] $cell->{class} '$cell->{text}'");
222 9075         70549 $worksheet->write($row, $col, decode_entities($cell->{text}), $formats{$cell->{class}});
223 9075         596392 $col++;
224 9075         25349 next;
225             }
226              
227 15358 100       28556 if($token->[0] eq 'T') {
228 11566 100       17727 $cell->{text} .= "\n" if($cell->{text});
229 11566         30185 $cell->{text} .= $token->[1];
230             }
231             }
232              
233 2   100     9 $hash{title} ||= 'CPAN Testers Matrix';
234 2   100     14 $hash{author} ||= 'CPAN Testers';
235 2   100     8 $hash{comments} ||= 'Copyright (C) 2009 The Perl Foundation';
236              
237 2         9 $worksheet->set_landscape(); # Landscape mode
238 2         13 $worksheet->set_paper(9); # A4
239 2         14 $worksheet->fit_to_pages(0, 1); # 1 page deep, many wide
240 2         21 $worksheet->set_header('&L&D&C'.$hash{title}.'&R&T');
241 2         39 $worksheet->set_footer('&RPage &P of &N');
242              
243 2         36 $worksheet->repeat_rows(0, 1); # Repeat the first two rows
244 2         14 $worksheet->repeat_columns(0, 1); # Repeat the first two columns
245              
246              
247 2         38 $workbook->set_properties(
248             title => $hash{title},
249             author => $hash{author},
250             comments => $hash{comments},
251             );
252              
253 2 50       829 $workbook->close() or die "Error closing file: $!";
254 2         76632 $self->_log("finish");
255             }
256              
257             # -------------------------------------
258             # Private Methods
259              
260             sub _log {
261 10215     10215   12633 my $self = shift;
262 10215 100       17674 my $log = $self->logfile or return;
263 10 100       222 mkpath(dirname($log)) unless(-f $log);
264              
265 10 100       22 my $mode = $self->logclean ? 'w+' : 'a+';
266 10         46 $self->logclean(0);
267              
268 10         168 my @dt = localtime(time);
269 10         51 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       45 my $fh = IO::File->new($log,$mode) or die "Cannot write to log file [$log]: $!\n";
272 10         819 print $fh "$dt ", @_, "\n";
273 10         28 $fh->close;
274             }
275              
276             q('This module is dedicated to the Birmingham Perl Mongers');
277              
278             __END__