File Coverage

blib/lib/Sport/Analytics/NHL/Report/RO.pm
Criterion Covered Total %
statement 98 167 58.6
branch 25 60 41.6
condition 8 16 50.0
subroutine 12 16 75.0
pod 10 10 100.0
total 153 269 56.8


line stmt bran cond sub pod time code
1             package Sport::Analytics::NHL::Report::RO;
2              
3 19     19   62570 use v5.10.1;
  19         60  
4 19     19   76 use strict;
  19         31  
  19         356  
5 19     19   74 use warnings FATAL => 'all';
  19         30  
  19         532  
6 19     19   84 use experimental qw(smartmatch);
  19         30  
  19         97  
7              
8 19     19   1406 use Sport::Analytics::NHL::Tools;
  19         34  
  19         2669  
9              
10 19     19   106 use parent 'Sport::Analytics::NHL::Report';
  19         33  
  19         118  
11              
12             =head1 NAME
13              
14             Sport::Analytics::NHL::Report::RO - Class for the NHL HTML RO report.
15              
16             =head1 SYNOPSYS
17              
18             Class for the NHL HTML RO report. Should not be constructed directly, but via Sport::Analytics::NHL::Report (q.v.)
19             As with any other HTML report, there are two types: old (pre-2007) and new (2007 and on). Parsers of them may have something in common but may turn out to be completely different more often than not.
20              
21             =head1 METHODS
22              
23             =over 2
24              
25             =item C
26              
27             Gets the coach from the roster table of the new RO report.
28              
29             Arguments: the roster table section containing the team's coach
30             Returns: the coach name
31              
32             =item C
33              
34             Gets the coach from the roster table of the old RO report.
35              
36             Arguments: the roster table section containing the team's coach
37             Returns: the coach name
38              
39             =item C
40              
41             Gets the officials from the roster table of the new RO report.
42              
43             Arguments: the roster table section containing the game officials
44             Returns: the officials and possibly their jersey numbers
45              
46             =item C
47              
48             Gets the officials from the roster table of the old RO report.
49              
50             Arguments: the roster table section containing the game officials
51             Returns: the officials and possibly their jersey numbers
52              
53             =item C
54              
55             Gets the actual roster and scratches from the roster table of the new RO report.
56              
57             Arguments:
58             * the roster table section containing the players
59             * the flag if the game roster or scratches are parsed
60             Returns: the list of players and their data:
61             * state (captain, a.c.)
62             * starting lineup
63             * position, number, name...
64              
65             =item C
66              
67             Gets the actual roster and scratches from the roster table of the old RO report.
68              
69             Arguments:
70             * the roster table section containing the players
71             * the flag if the game roster or scratches are parsed
72             Returns: the list of players and their data:
73             * state (captain, a.c.)
74             * starting lineup
75             * position, number, name...
76              
77             =item C
78              
79             A wrapper to call get_roster or get_roster_old (q.v.) with 'scratch' flag on.
80              
81             =item C
82              
83             Parse the report: call either old or new read_roster (q.v.)
84              
85             =item C
86              
87             Reads the new Roster report into a boxscore structure
88              
89             Arguments: none
90             Returns: void. Everything is in $self.
91              
92             =item C
93              
94             Reads the old Roster report into a boxscore structure
95              
96             Arguments: none
97             Returns: void. Everything is in $self.
98              
99             =back
100              
101             =cut
102              
103             sub get_roster_old ($$$;$) {
104              
105 0     0 1 0 my $self = shift;
106 0         0 my $row = shift;
107 0   0     0 my $is_scratch = shift || 0;
108              
109 0         0 my $r = 2;
110 0         0 my @fields = qw(number position name status);
111 0 0       0 pop @fields if $is_scratch;
112 0         0 my $sf = scalar @fields;
113 0 0       0 my $roster = $is_scratch ? 'scratches' : 'roster';
114 0         0 while (my $tr = $self->get_sub_tree(0, [$r], $row)) {
115 0 0       0 last unless ref $tr;
116 0         0 for my $lr (0, $sf) {
117 0         0 my $player = { start => 0, status => ' ' };
118 0         0 my $f = 0;
119 0         0 for my $field (@fields) {
120 0         0 my $td = $self->get_sub_tree(0, [$f+$lr,0,0], $tr);
121 0 0       0 unless (ref $td) {
122 0         0 $player->{$field} = $td;
123             }
124             else {
125 0 0       0 if ($field ne 'status') {
126 0         0 $player->{$field} = $self->get_sub_tree(0, [0,0], $td);
127 0         0 $player->{start} = 1;
128             }
129             }
130 0         0 $f++;
131             }
132 0 0       0 next unless $player->{name};
133 0         0 $player->{number} =~ s/\D//g;
134             push(
135 0         0 @{$self->{teams}[$lr/$sf]{$roster}},
  0         0  
136             $player,
137             );
138             }
139 0         0 $r++;
140             }
141             }
142              
143             sub get_roster ($$$;$) {
144              
145 8     8 1 13 my $self = shift;
146 8         12 my $table = shift;
147 8         11 my $is_scratch = shift;
148              
149 8         13 my $r = 1;
150 8         17 my $roster;
151 8         33 while (my $tr = $self->get_sub_tree(0, [$r], $table)) {
152 98 100 66     316 last unless $tr && ref $tr;
153 90         162 $r++;
154 90         552 my $player = {
155             number => $self->get_sub_tree(0, [0,0], $tr),
156             position => $self->get_sub_tree(0, [1,0], $tr),
157             name => $self->get_sub_tree(0, [2,0], $tr),
158             };
159 90 50       241 unless ($is_scratch) {
160 90   100     255 my $class = $tr->{_content}->[2]->attr('class') || '';
161 90 100       1240 $player->{start} = $class =~ /bold/ ? 1 : 0;
162 90 100       255 if ($player->{name} =~ /\((\w)\)/) {
163 12         37 $player->{status} = $1;
164 12         62 $player->{name} =~ s/(.*\S).+\(.*/$1/e;
  12         44  
165             }
166             else {
167 78         151 $player->{status} = ' ';
168             }
169             }
170 90         203 $player->{number} =~ s/\D//g;
171 90         121 push(@{$roster}, $player);
  90         374  
172             }
173 8         20 $roster;
174             }
175              
176             sub get_scratch_roster ($$$$) {
177              
178 4     4 1 8 my $self = shift;
179 4         12 $self->get_roster(shift, shift, shift, 1);
180             }
181              
182             sub get_coach_old ($$$) {
183              
184 0     0 1 0 my $self = shift;
185 0         0 my $row = shift;
186              
187 0         0 for my $t (0,1) {
188 0         0 my $coach = $self->get_sub_tree(0, [1,$t,0,0], $row);
189 0         0 $self->{teams}[$t]{coach} = $coach;
190             }
191             }
192              
193             sub get_coach ($$$) {
194              
195 4     4 1 6 my $self = shift;
196 4         6 my $table = shift;
197              
198 4         11 my $coach = $self->get_sub_tree(0, [0,0,0], $table);
199 4         9 $coach;
200             }
201              
202             sub get_officials_old ($$$) {
203              
204 0     0 1 0 my $self = shift;
205 0         0 my $table = shift;
206              
207 0         0 my $r = 0;
208 0         0 while (my $tr = $self->get_sub_tree(0, [$r], $table)) {
209 0 0       0 last unless ref $tr;
210 0         0 my $type = $self->get_sub_tree(0, [0,0,0], $tr);
211 0 0       0 if ($type =~ /referee/i) {
212 0         0 $type = 'referees';
213             }
214             else {
215 0         0 $type = 'linesmen';
216             }
217 0         0 my $official = $self->get_sub_tree(0, [1,0,0], $tr);
218 0         0 push(@{$self->{officials}{$type}}, { number => 0, name => $official });
  0         0  
219 0         0 $r++;
220             }
221 0         0 for my $type (qw(referees linesmen)) {
222 0 0       0 if (@{$self->{officials}{$type}} == 1) {
  0         0  
223 0         0 push(@{$self->{officials}{$type}}, { number => 0, name => 'Y' });
  0         0  
224             }
225             }
226             }
227              
228             sub get_officials ($$$) {
229              
230 2     2 1 6 my $self = shift;
231 2         6 my $table = shift;
232              
233 2         20 my $officials = {referees => [], linesmen => []};
234              
235 2         6 my $r = 0;
236             ROW:
237 2         20 while (my $tr = $self->get_sub_tree(0, [$r], $table)) {
238 10 100 66     43 last unless $tr && ref $tr;
239 8         10 $r++;
240 8         18 my $d; my $d_inc; my $d_ref;
  8         0  
241 8 50       14 if (@{$tr->{_content}} == 4) {
  8         27  
242 0         0 $d = 1; $d_inc = 2; $d_ref = 1;
  0         0  
  0         0  
243             }
244             else {
245 8         23 $d = 0; $d_inc = 1; $d_ref = 0;
  8         10  
  8         9  
246             }
247             TD_TABLE:
248 8         19 while (my $td_table = $self->get_sub_tree(0, [$d,0], $tr)) {
249 12 100 66     50 next ROW unless $td_table && ref $td_table;
250 8 100       20 my $type = $d == $d_ref ? 'referees' : 'linesmen';
251 8         10 $d += $d_inc;
252 8         18 my $e = 0;
253 8         24 while (my $official = $self->get_sub_tree(0, [$e,0,0,], $td_table)) {
254 8 50       14 next TD_TABLE unless $official;
255 8         9 $e++;
256 8         28 $official =~ /\#(\d+).*?(\w.*)/;
257             push(
258 8         45 @{$officials->{$type}}, {
259             number => $1,
260             name => $2,
261             },
262 8 50       10 ) unless @{$officials->{$type}} == 2;
  8         20  
263             }
264             }
265             }
266 2         7 $officials;
267             }
268              
269             sub read_roster_old ($$) {
270              
271 0     0 1 0 my $self = shift;
272              
273 0         0 $self->{teams}[0]{roster} = [];
274 0         0 $self->{teams}[1]{roster} = [];
275 0         0 $self->{teams}[0]{scratches} = [];
276 0         0 $self->{teams}[1]{scratches} = [];
277 0         0 $self->{officials} = {referees => [], linesmen => []};
278 0 0       0 my @r = @{$self->{head}} == 2 ? (3, 0) : (3);
  0         0  
279 0         0 while ($r[0] <= 9) {
280 0         0 my $row = $self->get_sub_tree(0, [@r]);
281 0 0 0     0 if ($row->tag eq 'table' || $row->tag eq 'tbody') {
282 0 0       0 if ($r[0] == 3) {
    0          
    0          
283 0         0 $self->get_roster_old($row, 0);
284             }
285             elsif ($r[0] == 5) {
286 0         0 $self->get_roster_old($row, 1);
287             }
288             elsif ($r[0] == 7) {
289 0         0 $self->get_coach_old($row);
290             }
291             else {
292 0         0 $self->get_officials_old($row);
293             }
294             }
295 0         0 $r[0] += 2;
296             }
297             }
298              
299             sub read_roster ($$) {
300              
301 2     2 1 5 my $self = shift;
302              
303 2         10 my $roster_table = $self->get_sub_tree(0, [3,0,0], $self->{content_table});
304 2         6 my $r = 0;
305 2         15 while (my $row = $self->get_sub_tree(0, [$r], $roster_table)) {
306 8         16 my $method;
307             my $header;
308 8 100       17 if ($r) {
309 6         21 $header = $self->get_sub_tree(0, [$r-1,0,0], $roster_table);
310 6 100       35 if ($header =~ /Head Coaches/) {
    100          
    50          
311 2         6 $header = 'coach';
312 2         15 $method = 'get_coach';
313             }
314             elsif ($header =~ /Scratches/) {
315 2         12 $header = 'scratches';
316 2         6 $method = 'get_scratch_roster';
317             }
318             elsif ($header =~ /Officials/) {
319 2         7 last;
320             }
321             }
322             else {
323 2         3 $header = 'roster';
324 2         5 $method = 'get_roster';
325             }
326 6         22 my $rowx = $self->get_sub_tree(0, [$r], $roster_table);
327 6         15 for my $t (0,1) {
328 12         30 my $table = $self->get_sub_tree(0, [$t,0], $rowx);
329 12 50       31 next unless $table;
330 12         34 my $roster = $self->$method($table);
331 12         31 $self->{teams}[$t]{$header} = $roster;
332             }
333 6         18 $r += 3;
334             }
335 2         9 my $officials_row = $self->get_sub_tree(0, [$r], $roster_table);
336 2         8 my $officials_table = $self->get_sub_tree(0, [0,0], $officials_row);
337 2         8 $self->{officials} = $self->get_officials($officials_table);
338             }
339              
340             sub parse ($$) {
341              
342 2     2 1 6 my $self = shift;
343              
344             $self->{old} ?
345 2 50       10 $self->read_roster_old() :
346             $self->read_roster();
347             }
348              
349             1;
350              
351             =head1 AUTHOR
352              
353             More Hockey Stats, C<< >>
354              
355             =head1 BUGS
356              
357             Please report any bugs or feature requests to C, or through
358             the web interface at L. I will be notified, and then you'll
359             automatically be notified of progress on your bug as I make changes.
360              
361              
362             =head1 SUPPORT
363              
364             You can find documentation for this module with the perldoc command.
365              
366             perldoc Sport::Analytics::NHL::Report::RO
367              
368             You can also look for information at:
369              
370             =over 4
371              
372             =item * RT: CPAN's request tracker (report bugs here)
373              
374             L
375              
376             =item * AnnoCPAN: Annotated CPAN documentation
377              
378             L
379              
380             =item * CPAN Ratings
381              
382             L
383              
384             =item * Search CPAN
385              
386             L
387              
388             =back