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   72 use Moo;
  18         19  
  18         69  
4              
5             our $VERSION = '0.17';
6              
7             extends 'HTML::Parser';
8              
9 18     18   15766 use HTML::TableContent::Table;
  18         34  
  18         19215  
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 1956 sub has_caption_selector { return scalar @{ $_[0]->caption_selectors } ? 1 : 0 }
  2938         34803  
31              
32 8679     8679 0 7446 sub count_nested { return scalar @{ $_[0]->nested }; }
  8679         102154  
33              
34 7809 100   7809 0 8297 sub has_nested { return $_[0]->count_nested ? 1 : 0; }
35              
36 789     789 0 11511 sub get_last_nested { return $_[0]->nested->[ $_[0]->count_nested - 1 ]; }
37              
38             sub clear_last_nested {
39 81     81 0 899 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 9032 return $_[0]->has_nested ? $_[0]->get_last_nested : $_[0]->current_table;
48             }
49              
50             sub parse {
51 435     435 1 7400 my ( $self, $data ) = @_;
52              
53 435         3127 $self->SUPER::parse($data);
54              
55 435         5550 return $self->current_tables;
56             }
57              
58             sub parse_file {
59 61     61 1 322 my ( $self, $file ) = @_;
60              
61 61         202 $self->SUPER::parse_file($file);
62              
63 61         967 return $self->current_tables;
64             }
65              
66             sub start {
67 6659     6659 1 7970 my ( $self, $tag, $attr, $attrseq, $origtext ) = @_;
68              
69 6659 100 66     16412 if ($self->current_element && $attr->{href}) {
70 262         184 push @{ $self->current_element->links }, $attr->{href};
  262         500  
71             }
72              
73 6659         6072 $tag = lc $tag;
74 6659 100       86485 if ( my $option = $self->options->{$tag} ) {
75 3721         17499 my $table = $self->current_or_nested;
76 3721         16583 my $action = $option->{add};
77 3721         6232 my $element = $self->$action($attr, $table);
78 3721         21387 return $self->current_element($element);
79             }
80              
81 2938 100       12761 if ( $self->has_caption_selector ) {
82 2352         9240 foreach my $selector ( @{ $self->caption_selectors }) {
  2352         26754  
83 3069 100       9392 if ( $selector eq $tag ) {
84 38         155 return $self->selected($attr);
85             }
86            
87 3031         2276 for my $field (qw/id class/) {
88 6060         4443 my $val = $attr->{$field};
89 6060 100       7576 next unless $val;
90            
91 1893 100       6700 if ( $val =~ m/$selector/ixms) {
92 2         14 return $self->selected($attr);
93             }
94             }
95             }
96             }
97              
98 2898         13560 return;
99             }
100              
101             sub text {
102 8204     8204 1 10418 my ( $self, $text ) = @_;
103              
104 8204 100       14244 if ( my $elem = $self->current_element ) {
105 6418 100       13669 if ( $text =~ m{\S+}xms ) {
106 2728         6751 $text =~ s{^\s+|\s+$}{}g;
107 2728         1871 push @{ $elem->data }, $text;
  2728         4690  
108             }
109             }
110 8204 100       12565 if ( my $selected = $self->selected) {
111 370 100       759 if ( $text =~ m{\S+}xms ) {
112 317         291 $selected->{text} = $text;
113 317         294 $self->selected($selected);
114             }
115             }
116              
117 8204         27634 return;
118             }
119              
120             sub end {
121 6526     6526 1 6326 my ( $self, $tag, $origtext ) = @_;
122              
123 6526         5408 $tag = lc $tag;
124              
125 6526 100       82828 if ( my $option = $self->options->{$tag} ) {
126 3712         17506 my $table = $self->current_or_nested;
127 3712 100       19685 if ( my $action = $option->{close} ) {
128 1352         2380 my $element = $self->$action($table);
129             }
130             }
131              
132 6526         30252 return;
133             }
134              
135             sub _build_options {
136             return {
137 122     122   1713 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   576 my ($self, $attr, $table) = @_;
159              
160 547         1204 my $header = $table->add_header($attr);
161 547         1145 $table->get_last_row->header($header);
162 547         2458 return $header;
163             }
164              
165             sub _add_row {
166 1062     1062   1007 my ($self, $attr, $table) = @_;
167              
168 1062         1972 my $row = $table->add_row($attr);
169 1062         1412 return $row;
170             }
171              
172             sub _add_cell {
173 1816     1816   1738 my ($self, $attr, $table) = @_;
174              
175 1816         3205 my $cell = $table->get_last_row->add_cell($attr);
176 1816         3810 $table->parse_to_column($cell);
177 1816         1883 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   317 my ($self, $attr, $table) = @_;
189              
190 296         4137 my $element = HTML::TableContent::Table->new($attr);
191              
192 296 100 66     2880 if ( defined $table && $table->isa('HTML::TableContent::Table') ) {
193 81 100       137 if ( $self->has_nested ) {
194 28         146 push @{ $self->current_table->nested }, $element;
  28         91  
195             }
196 81         278 push @{ $self->nested }, $element;
  81         937  
197 81         240 push @{ $table->nested }, $element;
  81         148  
198 81         65 push @{ $table->get_last_row->get_last_cell->nested }, $element;
  81         152  
199             }
200             else {
201 215 100       563 if ( my $caption = $self->selected ){
202 18         44 $element->add_caption($caption);
203 18         244 $self->clear_selected;
204             }
205 215         530 $self->current_table($element);
206             }
207             }
208              
209             sub _close_table {
210 295     295   308 my ($self, $table) = @_;
211              
212 295 100       387 if ( $self->has_nested ) {
213 81         353 return $self->clear_last_nested;
214             }
215             else {
216 214         878 push @{ $self->current_tables }, $self->current_table;
  214         2715  
217 214         3208 $self->clear_current_element;
218 214         3201 return $self->clear_current_table;
219             }
220             }
221              
222             sub _close_row {
223 1057     1057   958 my ($self, $table) = @_;
224              
225 1057         1845 my $row = $table->get_last_row;
226              
227 1057 100       5186 if ( $row->header ) {
    100          
228 247         527 $table->clear_last_row;
229              
230 247         1015 my $index = 0;
231 247         595 foreach my $cell ( $row->all_cells ) {
232 39         546 my $row = $table->rows->[$index];
233 39 100       141 if ( defined $row ) {
234 26         17 push @{ $row->cells }, $cell;
  26         289  
235             }
236             else {
237 13         26 my $new_row = $table->add_row({});
238 13         10 push @{ $new_row->cells }, $cell;
  13         151  
239             }
240 39         111 $index++;
241             }
242             }
243             elsif ( $row->cell_count == 0 ) {
244 10         19 $table->clear_last_row;
245             }
246              
247 1057         4581 return;
248             }
249              
250             1;
251              
252             __END__