File Coverage

blib/lib/HTML5/DOM/Collection.pm
Criterion Covered Total %
statement 79 85 92.9
branch 25 26 96.1
condition 6 9 66.6
subroutine 24 27 88.8
pod 0 18 0.0
total 134 165 81.2


line stmt bran cond sub pod time code
1             package HTML5::DOM::Collection;
2 3     3   25 use strict;
  3         6  
  3         124  
3 3     3   17 use warnings;
  3         7  
  3         173  
4              
5 3     3   19 use List::Util;
  3         6  
  3         432  
6              
7             use overload
8 0     0   0 '""' => sub { shift->html },
9 0     0   0 'bool' => sub { 1 },
10 3     3   21 fallback => 1;
  3         27  
  3         30  
11              
12             sub new {
13 29     29 0 76 my ($class, $nodes) = @_;
14 29 50 33     148 $nodes = [] if (!$nodes || ref($nodes) ne 'ARRAY');
15 29         159 return bless $nodes, $class;
16             }
17              
18             sub add {
19 0     0 0 0 my $self = shift;
20 0         0 push @{$self}, shift;
  0         0  
21 0         0 return $self;
22             }
23              
24 256     256 0 77850 sub length { scalar(@{shift()}); }
  256         1284  
25              
26             sub first {
27 3     3 0 10 my ($self, $callback) = (shift, shift);
28 3 100       19 return $self->[0] if (!$callback);
29 2 100   4   6 return List::Util::first { $_ =~ $callback } @$self if (_is_regexp($callback));
  4         18  
30 1     4   8 return List::Util::first { $_->$callback(@_) } @$self;
  4         26  
31             }
32              
33 1     1 0 8 sub last { shift->[-1] }
34 47     47 0 11210 sub item { shift->[shift] }
35 2     2 0 7 sub array { [@{shift()}] }
  2         15  
36              
37             sub slice {
38 17     17 0 43 my ($self, $offset, $length) = @_;
39            
40             # handle negative value as offset from end
41 17 100       52 $offset = scalar(@$self) + $offset if ($offset < 0);
42            
43             # validate offset
44 17 100 100     103 return HTML5::DOM::Collection->new([]) if ($offset < 0 || $offset >= scalar(@$self) - 1);
45            
46             # mean all available elements if no length specified
47 11 100       31 $length = scalar(@$self) if !defined $length;
48            
49             # get maximum available length from offset
50 11         21 my $max_length = scalar(@$self) - $offset;
51            
52             # handle negative length
53 11 100       51 $length = $max_length + $length if ($length < 0);
54            
55             # limit available length
56 11 100       28 $length = $max_length if ($length > $max_length);
57            
58             # validate length
59 11 100       27 return HTML5::DOM::Collection->new([]) if ($length <= 0);
60            
61             # return requested slice
62 10         50 return HTML5::DOM::Collection->new([@$self[$offset..$offset + $length - 1]]);
63             }
64              
65             sub head {
66 4     4 0 11 my ($self, $length) = @_;
67 4         13 return $self->slice(0, $length);
68             }
69              
70             sub tail {
71 4     4 0 12 my ($self, $length) = @_;
72 4         11 return $self->slice(-$length);
73             }
74              
75             sub each {
76 1     1 0 382 my ($self, $callback) = (shift, shift);
77 1         3 my $index = 0;
78 1         4 for my $node (@$self) {
79 5         17 $callback->($node, $index++, @_);
80             }
81 1         5 return $self;
82             }
83              
84             sub uniq {
85 2     2 0 9 my ($self, $callback) = (shift, shift);
86 2         4 my %used;
87 2 100       10 return HTML5::DOM::Collection->new([grep { my $id = $_->$callback(@_); !$used{defined($id) ? $id : ''}++ } @$self]) if ($callback);
  5 100       16  
  5         47  
88 1         4 return HTML5::DOM::Collection->new([grep { !$used{$_->hash}++ } @$self]);
  5         59  
89             }
90              
91             sub grep {
92 2     2 0 6 my ($self, $callback) = (shift, shift);
93 2 100       7 return HTML5::DOM::Collection->new([grep { $_ =~ $callback } @$self]) if (_is_regexp($callback));
  5         41  
94 1         4 return HTML5::DOM::Collection->new([grep { $_->$callback(@_) } @$self]);
  5         43  
95             }
96              
97             sub reverse {
98 1     1 0 3 my ($self) = @_;
99 1         6 return HTML5::DOM::Collection->new([reverse @$self]);
100             }
101              
102             sub shuffle {
103 1     1 0 4 my ($self) = @_;
104 1         77 return HTML5::DOM::Collection->new([List::Util::shuffle @$self]);
105             }
106              
107             sub map {
108 6     6 0 372 my ($self, $callback) = (shift, shift);
109 6 100       36 if (ref($callback) eq 'CODE') {
110 1         3 my $index = 0;
111 1         4 return HTML5::DOM::Collection->new([map { $_->$callback($index++, @_) } @$self]);
  5         14  
112             } else {
113 5         17 return HTML5::DOM::Collection->new([map { $_->$callback(@_) } @$self]);
  21         135  
114             }
115             }
116              
117             sub text {
118 22     22 0 37 my @nodes;
119 22         41 for my $node (@{shift()}) {
  22         53  
120 49         227 push @nodes, $node->text;
121             }
122 22         147 return join("", @nodes);
123             }
124              
125             sub html {
126 1     1 0 3 my @nodes;
127 1         3 for my $node (@{shift()}) {
  1         4  
128 5         33 push @nodes, $node->html;
129             }
130 1         9 return join("", @nodes);
131             }
132              
133             sub _is_regexp {
134 4   66 4   41 return ref($_[0]) eq 'Regexp' || ref(\$_[0]) eq 'Regexp';
135             }
136              
137             1;