File Coverage

blib/lib/HTML/TableContent/Parser.pm
Criterion Covered Total %
statement 110 117 94.0
branch 44 44 100.0
condition 4 6 66.6
subroutine 20 23 86.9
pod 7 13 53.8
total 185 203 91.1


line stmt bran cond sub pod time code
1             package HTML::TableContent::Parser;
2              
3 18     18   115 use Moo;
  18         40  
  18         1427  
4              
5             our $VERSION = '0.18';
6              
7             extends 'HTML::Parser';
8              
9 18     18   18209 use HTML::TableContent::Table;
  18         60  
  18         19066  
10              
11             has [qw(current_tables nested caption_selectors)] => (
12             is => 'rw',
13             lazy => 1,
14             clearer => 1,
15             default => sub { [] },
16             );
17              
18             has [qw(current_table current_element selected)] => (
19             is => 'rw',
20             lazy => 1,
21             clearer => 1,
22             );
23              
24             has options => (
25             is => 'ro',
26             lazy => 1,
27             builder => 1,
28             );
29              
30 2938 100   2938 0 4252 sub has_caption_selector { return scalar @{ $_[0]->caption_selectors } ? 1 : 0 }
  2938         38096  
31              
32 8679     8679 0 15750 sub count_nested { return scalar @{ $_[0]->nested }; }
  8679         115035  
33              
34 7809 100   7809 0 15197 sub has_nested { return $_[0]->count_nested ? 1 : 0; }
35              
36 789     789 0 14377 sub get_last_nested { return $_[0]->nested->[ $_[0]->count_nested - 1 ]; }
37              
38             sub clear_last_nested {
39 81     81 0 1006 return delete $_[0]->nested->[ $_[0]->count_nested - 1 ];
40             }
41              
42 0     0 1 0 sub all_current_tables { return @{ $_[0]->current_tables }; }
  0         0  
43              
44 0     0 1 0 sub count_current_tables { return scalar @{ $_[0]->current_tables }; }
  0         0  
45              
46             sub current_or_nested {
47 7433 100   7433 0 15742 return $_[0]->has_nested ? $_[0]->get_last_nested : $_[0]->current_table;
48             }
49              
50             sub parse {
51 435     435 1 10067 my ( $self, $data ) = @_;
52              
53 435         4020 $self->SUPER::parse($data);
54              
55 435         6350 return $self->current_tables;
56             }
57              
58             sub parse_file {
59 61     61 1 550 my ( $self, $file ) = @_;
60              
61 61         309 $self->SUPER::parse_file($file);
62              
63 61         1076 return $self->current_tables;
64             }
65              
66             sub start {
67 6659     6659 1 16085 my ( $self, $tag, $attr, $attrseq, $origtext ) = @_;
68              
69 6659 100 66     22678 if ($self->current_element && $attr->{href}) {
70 262         403 push @{ $self->current_element->links }, $attr->{href};
  262         777  
71             }
72              
73 6659         11742 $tag = lc $tag;
74 6659 100       95938 if ( my $option = $self->options->{$tag} ) {
75 3721         30464 my $table = $self->current_or_nested;
76 3721         27316 my $action = $option->{add};
77 3721         9296 my $element = $self->$action($attr, $table);
78 3721         27043 return $self->current_element($element);
79             }
80              
81 2938 100       22115 if ( $self->has_caption_selector ) {
82 2352         15671 foreach my $selector ( @{ $self->caption_selectors }) {
  2352         29098  
83 3069 100       16377 if ( $selector eq $tag ) {
84 38         208 return $self->selected($attr);
85             }
86            
87 3031         4915 for my $field (qw/id class/) {
88 6060         9428 my $val = $attr->{$field};
89 6060 100       12574 next unless $val;
90            
91 1893 100       8664 if ( $val =~ m/$selector/ixms) {
92 2         18 return $self->selected($attr);
93             }
94             }
95             }
96             }
97              
98 2898         18171 return;
99             }
100              
101             sub text {
102 8204     8204 1 21528 my ( $self, $text ) = @_;
103              
104 8204 100       21298 if ( my $elem = $self->current_element ) {
105 6418 100       20291 if ( $text =~ m{\S+}xms ) {
106 2728         9439 $text =~ s{^\s+|\s+$}{}g;
107 2728         4288 push @{ $elem->data }, $text;
  2728         7336  
108             }
109             }
110 8204 100       20395 if ( my $selected = $self->selected) {
111 370 100       1151 if ( $text =~ m{\S+}xms ) {
112 317         578 $selected->{text} = $text;
113 317         562 $self->selected($selected);
114             }
115             }
116              
117 8204         36267 return;
118             }
119              
120             sub end {
121 6526     6526 1 13800 my ( $self, $tag, $origtext ) = @_;
122              
123 6526         10596 $tag = lc $tag;
124              
125 6526 100       90844 if ( my $option = $self->options->{$tag} ) {
126 3712         30322 my $table = $self->current_or_nested;
127 3712 100       30818 if ( my $action = $option->{close} ) {
128 1352         3630 my $element = $self->$action($table);
129             }
130             }
131              
132 6526         44320 return;
133             }
134              
135             sub _build_options {
136             return {
137 122     122   2288 table => {
138             add => '_add_table',
139             close => '_close_table',
140             },
141             th => {
142             add => '_add_header',
143             },
144             tr => {
145             add => '_add_row',
146             close => '_close_row',
147             },
148             td => {
149             add => '_add_cell',
150             },
151             caption => {
152             add => '_add_caption'
153             }
154             };
155             }
156              
157             sub _add_header {
158 547     547   1187 my ($self, $attr, $table) = @_;
159              
160 547         1759 my $header = $table->add_header($attr);
161 547         1619 $table->get_last_row->header($header);
162 547         3903 return $header;
163             }
164              
165             sub _add_row {
166 1062     1062   2124 my ($self, $attr, $table) = @_;
167              
168 1062         3056 my $row = $table->add_row($attr);
169 1062         2090 return $row;
170             }
171              
172             sub _add_cell {
173 1816     1816   3619 my ($self, $attr, $table) = @_;
174              
175 1816         4884 my $cell = $table->get_last_row->add_cell($attr);
176 1816         6371 $table->parse_to_column($cell);
177 1816         3406 return $cell;
178             }
179              
180             sub _add_caption {
181 0     0   0 my ($self, $attr, $table) = @_;
182              
183 0         0 my $caption = $table->add_caption($attr);
184 0         0 return $caption;
185             }
186              
187             sub _add_table {
188 296     296   745 my ($self, $attr, $table) = @_;
189              
190 296         4643 my $element = HTML::TableContent::Table->new($attr);
191              
192 296 100 66     3634 if ( defined $table && $table->isa('HTML::TableContent::Table') ) {
193 81 100       204 if ( $self->has_nested ) {
194 28         203 push @{ $self->current_table->nested }, $element;
  28         83  
195             }
196 81         437 push @{ $self->nested }, $element;
  81         1053  
197 81         452 push @{ $table->nested }, $element;
  81         193  
198 81         115 push @{ $table->get_last_row->get_last_cell->nested }, $element;
  81         231  
199             }
200             else {
201 215 100       827 if ( my $caption = $self->selected ){
202 18         96 $element->add_caption($caption);
203 18         255 $self->clear_selected;
204             }
205 215         796 $self->current_table($element);
206             }
207             }
208              
209             sub _close_table {
210 295     295   703 my ($self, $table) = @_;
211              
212 295 100       688 if ( $self->has_nested ) {
213 81         588 return $self->clear_last_nested;
214             }
215             else {
216 214         1491 push @{ $self->current_tables }, $self->current_table;
  214         2978  
217 214         4102 $self->clear_current_element;
218 214         3963 return $self->clear_current_table;
219             }
220             }
221              
222             sub _close_row {
223 1057     1057   2021 my ($self, $table) = @_;
224              
225 1057         2731 my $row = $table->get_last_row;
226              
227 1057 100       8193 if ( $row->header ) {
    100          
228 247         877 $table->clear_last_row;
229              
230 247         1651 my $index = 0;
231 247         932 foreach my $cell ( $row->all_cells ) {
232 39         634 my $row = $table->rows->[$index];
233 39 100       227 if ( defined $row ) {
234 26         41 push @{ $row->cells }, $cell;
  26         303  
235             }
236             else {
237 13         33 my $new_row = $table->add_row({});
238 13         20 push @{ $new_row->cells }, $cell;
  13         159  
239             }
240 39         179 $index++;
241             }
242             }
243             elsif ( $row->cell_count == 0 ) {
244 10         27 $table->clear_last_row;
245             }
246              
247 1057         7018 return;
248             }
249              
250             1;
251              
252             __END__