File Coverage

blib/lib/Chess/ELO/FEDA.pm
Criterion Covered Total %
statement 47 163 28.8
branch 15 96 15.6
condition 5 14 35.7
subroutine 11 21 52.3
pod 5 6 83.3
total 83 300 27.6


line stmt bran cond sub pod time code
1             package Chess::ELO::FEDA;
2             $Chess::ELO::FEDA::VERSION = '0.04';
3 2     2   1517 use strict;
  2         4  
  2         56  
4 2     2   10 use warnings;
  2         4  
  2         57  
5              
6 2     2   3136 use DBI;
  2         35148  
  2         114  
7 2     2   1290 use DBD::CSV;
  2         408831  
  2         112  
8 2     2   1500 use DBD::SQLite;
  2         16186  
  2         69  
9 2     2   946 use File::Spec::Functions;
  2         1604  
  2         160  
10 2     2   1396 use HTTP::Tiny;
  2         68481  
  2         90  
11 2     2   1353 use IO::Uncompress::Unzip qw/$UnzipError/;
  2         91720  
  2         240  
12 2     2   1798 use Spreadsheet::ParseExcel;
  2         94482  
  2         84  
13 2     2   20 use Encode qw/decode/;
  2         4  
  2         4069  
14              
15             # ABSTRACT: Download FEDA ELO (L) into differents backends (SQLite)
16              
17              
18             sub new {
19 6     6 1 2387 my $class = shift;
20 6         16 my %args = @_;
21 6         35 my $self = {-verbose=>0, -url=>'', -target=>'', -ext=>'', -path=>''};
22 6 100       18 $self->{-path} = $args{-folder} if exists $args{-folder};
23 6 100       15 $self->{-target} = $args{-target} if exists $args{-target};
24 6 50       17 $self->{-url} = $args{-url} if exists $args{-url};
25 6 50       10 $self->{-verbose} = $args{-verbose} if exists $args{-verbose};
26 6 50       13 $self->{-callback} = $args{-callback} if exists $args{-callback};
27              
28 6 100 66     42 if( $self->{-target} && ($self->{-target} =~ m!(\w+)$!) ) {
29 4         14 $self->{-ext} = lc( $1 );
30             }
31            
32 6 100 100     24 if( ($self->{-ext} ne 'sqlite') && ($self->{-ext} ne 'csv') ) {
33 3 100       8 if( $self->{-target} ) {
34 1         11 die "Unsupported target: [" . $self->{-ext} . "]";
35             }
36             else {
37 2         4 $self->{-ext} = 'NULL';
38             }
39             }
40              
41 5 100       138 unless(-d $self->{-path} ) {
42 2         30 die "Invalid path: [" . $self->{-path} . "]";
43             }
44 3         30 bless $self, $class;
45             }
46              
47             #-------------------------------------------------------------------------------
48              
49              
50             sub cleanup {
51 0     0 1   my $self = shift;
52 0 0         if( -e $self->{-xls} ) {
53 0 0         $self->{-verbose} and print "+ remove xls file: ", $self->{-xls}, "\n";
54 0           unlink $self->{-xls};
55             }
56             }
57              
58             #-------------------------------------------------------------------------------
59              
60              
61             sub download {
62 0     0 1   my $self = shift;
63 0   0       my $filename = $self->{-target} || 'chess_elo_feda';
64 0           my $target_filename = catfile($self->{-path}, $filename);
65 0           my $zip_filename = $target_filename . '.zip';
66 0           my $xls_filename = $target_filename . '.xls';
67              
68             ##my $response = {content=>'', status=>200, reason=>'OK'};
69 0           my $response = HTTP::Tiny->new->get($self->{-url});
70 0 0         die "GET [$self->{-url}] failed" unless $response->{success};
71              
72 0 0         if( length $response->{content} ) {
73 0 0         open my $fhz, ">", $zip_filename or die "Cannot open file: $zip_filename";
74 0           binmode $fhz;
75 0           print $fhz $response->{content} ;
76 0           close $fhz;
77             }
78 0 0         print "+ Download: ", $zip_filename, " => [", $response->{status}, "]: ", $response->{reason}, "\n" if $self->{-verbose};
79 0           $self->_extract_file_from_zip($xls_filename, $zip_filename, qr!\.xls$!i);
80 0           unlink $zip_filename;
81 0 0         print "+ Unzip: ", $xls_filename, "\n" if $self->{-verbose};
82 0           $self->{-xls} = $xls_filename;
83 0 0         return (-e $self->{-xls}) ? 1 : 0;
84             }
85              
86             #-------------------------------------------------------------------------------
87              
88              
89             sub parse {
90 0     0 1   my $self = shift;
91            
92 0           my $rc = 0;
93              
94 0 0         if( $self->{-ext} eq 'NULL' ) {
    0          
    0          
95 0           $rc = $self->_parse_null;
96             }
97             elsif( $self->{-ext} eq 'sqlite' ) {
98 0           $rc = $self->_parse_sqlite;
99             }
100             elsif( $self->{-ext} eq 'csv' ) {
101 0           $rc = $self->_parse_csv;
102             }
103             else {
104 0           die "Unsupported target. Not in [sqlite, csv]";
105             }
106              
107 0           return $rc;
108             }
109              
110             #-------------------------------------------------------------------------------
111              
112              
113             sub run {
114 0     0 1   my $self = shift;
115 0           my $rc = 0;
116              
117 0 0         if( $self->download() ) {
118 0           $rc = $self->parse;
119 0           $self->cleanup;
120             }
121              
122 0           return $rc;
123             }
124              
125             #-------------------------------------------------------------------------------
126              
127             sub _extract_file_from_zip {
128 0     0     my ($self, $xlsfile, $zipfile, $regexpr_file_to_extract) = @_;
129 0 0         my $u = new IO::Uncompress::Unzip $zipfile or die "Cannot open $zipfile: $UnzipError";
130 0           my $filename = undef;
131              
132 0           for( my $status = 1; $status > 0; $status = $u->nextStream() )
133             {
134 0           my $name = $u->getHeaderInfo()->{Name};
135 0 0         next unless $name =~ $regexpr_file_to_extract;
136            
137 0           my $buff;
138 0 0         open my $fh, '>', $xlsfile or die "Couldn't write to $name: $!";
139 0           binmode $fh;
140 0           while( ($status = $u->read($buff)) > 0 ) {
141 0           syswrite $fh, $buff;
142             }
143 0           close $fh;
144 0           $filename = $name;
145 0           last;
146             }
147            
148 0 0         return ($filename) ? $xlsfile . "/$filename" : undef;
149             }
150              
151             #-------------------------------------------------------------------------------
152              
153             sub _parse_null {
154 0     0     my $self = shift;
155            
156 0 0         $self->{-verbose} and print "+ NULL target", "\n";
157 0           my $rc = $self->_parse_abstract_dbd(undef);
158            
159 0           return $rc;
160             }
161              
162             #-------------------------------------------------------------------------------
163              
164             sub _parse_sqlite {
165 0     0     my $self = shift;
166            
167 0           $self->{-dbfile} = catfile($self->{-path}, $self->{-target});
168 0 0         $self->{-verbose} and print "+ DB File: ", $self->{-dbfile}, "\n";
169 0 0         unlink $self->{-dbfile} if -e $self->{-dbfile};
170              
171 0 0         my $dbh = DBI->connect("dbi:SQLite:dbname=" . $self->{-dbfile}, "", "", {
172             RaiseError=>1,
173             AutoCommit=>0
174             }) or die $DBI::errstr;
175 0           my $rc = $self->_parse_abstract_dbd($dbh);
176 0           $dbh->disconnect;
177 0           return $rc;
178             }
179              
180             #-------------------------------------------------------------------------------
181              
182             sub _parse_csv {
183 0     0     my $self = shift;
184              
185 0           $self->{-dbfile} = catfile($self->{-path}, $self->{-target});
186 0 0         $self->{-verbose} and print "+ DB File: ", $self->{-dbfile}, "\n";
187 0 0         unlink $self->{-dbfile} if -e $self->{-dbfile};
188              
189             my $dbh = DBI->connect ("dbi:CSV:", "", "", {
190             f_schema => undef,
191             f_dir => $self->{-path},
192             f_encoding => "utf8",
193             csv_eol => "\n",
194             csv_sep_char => ",",
195             csv_quote_char => '"',
196             csv_escape_char => '"',
197             csv_class => "Text::CSV_XS",
198             csv_null => 1,
199             csv_always_quote => 1,
200             csv_tables => { elo_feda => { f_file => $self->{-target} } },
201 0 0         RaiseError => 1,
202             AutoCommit => 1
203             }) or die $DBI::errstr;
204 0           my $rc = $self->_parse_abstract_dbd($dbh);
205 0           $dbh->disconnect;
206 0           return $rc;
207             }
208              
209             #-------------------------------------------------------------------------------
210              
211             sub _parse_abstract_dbd {
212 0     0     my $self = shift;
213 0           my $dbh = shift;
214            
215 0 0         $dbh and $dbh->do(qq/CREATE TABLE elo_feda(
216             feda_id integer primary key,
217             surname varchar(32) not null,
218             name varchar(32),
219             fed varchar(8),
220             rating integer,
221             games integer,
222             birth integer,
223             title varchar(16),
224             flag varchar(8)
225             )/ );
226 0 0         $self->{-verbose} and print "+ Load XLS: ", $self->{-xls}, "\n";
227              
228 0           my $parser = Spreadsheet::ParseExcel->new;
229             my $workbook = $parser->parse( $self->{-xls} )
230 0 0         or die $parser->error(), "\n";
231              
232 0           my $worksheet = $workbook->worksheet('ELO');
233 0           my ( $row_min, $row_max ) = $worksheet->row_range();
234              
235 0           my $START_XLS_ROW = 4;
236 0           my @player_keys = qw/feda_id name fed rating games birth title flag/;
237              
238             sub new_xls_player {
239 0     0 0   my ($worksheet, $stmt, $player_keys, $callback, $start_row, $stop_row, $verbose) = @_;
240 0           for my $row ( $start_row .. $stop_row ) {
241 0           my %feda_player;
242 0           for my $col_index( 0..7 ) {
243 0           my $cell = $worksheet->get_cell($row, $col_index);
244 0 0         my $value = $cell ? $cell->value : undef;
245 0           $feda_player{ $player_keys->[$col_index] } = $value;
246             }
247            
248 0           $feda_player{name} = decode('latin1', $feda_player{name});
249            
250 0           my $name = $feda_player{name};
251 0           my ($apellidos, $nombre) = split / *, */, $name;
252              
253 0 0 0       if( $apellidos && $nombre ) {
    0          
    0          
254 0           $feda_player{surname} = $apellidos;
255 0           $feda_player{name} = $nombre;
256             }
257             elsif( index($name, '.') >= 0 ) {
258 0           ($apellidos, $nombre) = split / *\. */, $name;
259 0           $feda_player{surname} = $apellidos;
260 0           $feda_player{name} = $nombre;
261             }
262             elsif( $apellidos ) {
263 0           $feda_player{surname} = $apellidos;
264 0           $feda_player{name} = '***';
265             }
266 0           eval {
267             $stmt and $stmt->execute(
268             $feda_player{feda_id},
269             $feda_player{surname},
270             $feda_player{name},
271             $feda_player{fed},
272             $feda_player{rating},
273             $feda_player{games},
274             $feda_player{birth},
275             $feda_player{title},
276             $feda_player{flag}
277 0 0         );
278 0 0         $callback and $callback->(\%feda_player);
279             };
280 0 0         if($@) {
281 0 0         $verbose and print "DB Error: $@", "\n";
282             }
283             }
284             }
285              
286 0           my $BLOCK_TXN = 2000;
287 0           my $i = $START_XLS_ROW;
288 0           my $j = $i + $BLOCK_TXN - 1;
289            
290 0 0         my $stmt = $dbh ?
291             $dbh->prepare("insert into elo_feda (feda_id, surname, name, fed, rating, games, birth, title, flag) values (?,?,?,?,?,?,?,?,?)"):
292             undef;
293              
294 0           do {
295 0           new_xls_player($worksheet, $stmt, \@player_keys, $self->{-callback}, $i, $j, $self->{-verbose});
296 0 0 0       if( $dbh && (! $dbh->{AutoCommit}) ) {
297 0 0         $dbh->commit unless $dbh->{AutoCommit};
298             }
299 0           $i += $BLOCK_TXN;
300 0 0         $j = ($i + $BLOCK_TXN -1) > $row_max ? $row_max : $i + $BLOCK_TXN - 1;
301             } while( $i <= $row_max );
302              
303 0 0         $stmt and $stmt->finish;
304              
305 0           return 1;
306             }
307              
308             #-------------------------------------------------------------------------------
309              
310             1;
311              
312             __END__