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   21 use strict;
  3         4  
  3         104  
3 3     3   15 use warnings;
  3         4  
  3         82  
4              
5 3     3   15 use List::Util;
  3         6  
  3         355  
6              
7             use overload
8 0     0   0 '""' => sub { shift->html },
9 0     0   0 'bool' => sub { 1 },
10 3     3   22 fallback => 1;
  3         5  
  3         33  
11              
12             sub new {
13 29     29 0 67 my ($class, $nodes) = @_;
14 29 50 33     127 $nodes = [] if (!$nodes || ref($nodes) ne 'ARRAY');
15 29         153 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 72302 sub length { scalar(@{shift()}); }
  256         1104  
25              
26             sub first {
27 3     3 0 9 my ($self, $callback) = (shift, shift);
28 3 100       13 return $self->[0] if (!$callback);
29 2 100   4   5 return List::Util::first { $_ =~ $callback } @$self if (_is_regexp($callback));
  4         81  
30 1     4   8 return List::Util::first { $_->$callback(@_) } @$self;
  4         27  
31             }
32              
33 1     1 0 6 sub last { shift->[-1] }
34 47     47 0 7812 sub item { shift->[shift] }
35 2     2 0 6 sub array { [@{shift()}] }
  2         12  
36              
37             sub slice {
38 17     17 0 49 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     81 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       26 $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       22 $length = $max_length + $length if ($length < 0);
54            
55             # limit available length
56 11 100       25 $length = $max_length if ($length > $max_length);
57            
58             # validate length
59 11 100       25 return HTML5::DOM::Collection->new([]) if ($length <= 0);
60            
61             # return requested slice
62 10         43 return HTML5::DOM::Collection->new([@$self[$offset..$offset + $length - 1]]);
63             }
64              
65             sub head {
66 4     4 0 12 my ($self, $length) = @_;
67 4         13 return $self->slice(0, $length);
68             }
69              
70             sub tail {
71 4     4 0 11 my ($self, $length) = @_;
72 4         21 return $self->slice(-$length);
73             }
74              
75             sub each {
76 1     1 0 314 my ($self, $callback) = (shift, shift);
77 1         3 my $index = 0;
78 1         3 for my $node (@$self) {
79 5         15 $callback->($node, $index++, @_);
80             }
81 1         3 return $self;
82             }
83              
84             sub uniq {
85 2     2 0 6 my ($self, $callback) = (shift, shift);
86 2         4 my %used;
87 2 100       23 return HTML5::DOM::Collection->new([grep { my $id = $_->$callback(@_); !$used{defined($id) ? $id : ''}++ } @$self]) if ($callback);
  5 100       11  
  5         39  
88 1         1100 return HTML5::DOM::Collection->new([grep { !$used{$_->hash}++ } @$self]);
  5         37  
89             }
90              
91             sub grep {
92 2     2 0 7 my ($self, $callback) = (shift, shift);
93 2 100       8 return HTML5::DOM::Collection->new([grep { $_ =~ $callback } @$self]) if (_is_regexp($callback));
  5         34  
94 1         4 return HTML5::DOM::Collection->new([grep { $_->$callback(@_) } @$self]);
  5         36  
95             }
96              
97             sub reverse {
98 1     1 0 4 my ($self) = @_;
99 1         8 return HTML5::DOM::Collection->new([reverse @$self]);
100             }
101              
102             sub shuffle {
103 1     1 0 5 my ($self) = @_;
104 1         68 return HTML5::DOM::Collection->new([List::Util::shuffle @$self]);
105             }
106              
107             sub map {
108 6     6 0 383 my ($self, $callback) = (shift, shift);
109 6 100       17 if (ref($callback) eq 'CODE') {
110 1         2 my $index = 0;
111 1         4 return HTML5::DOM::Collection->new([map { $_->$callback($index++, @_) } @$self]);
  5         12  
112             } else {
113 5         13 return HTML5::DOM::Collection->new([map { $_->$callback(@_) } @$self]);
  21         91  
114             }
115             }
116              
117             sub text {
118 22     22 0 36 my @nodes;
119 22         35 for my $node (@{shift()}) {
  22         47  
120 49         182 push @nodes, $node->text;
121             }
122 22         139 return join("", @nodes);
123             }
124              
125             sub html {
126 1     1 0 3 my @nodes;
127 1         2 for my $node (@{shift()}) {
  1         4  
128 5         31 push @nodes, $node->html;
129             }
130 1         9 return join("", @nodes);
131             }
132              
133             sub _is_regexp {
134 4   66 4   37 return ref($_[0]) eq 'Regexp' || ref(\$_[0]) eq 'Regexp';
135             }
136              
137             1;