File Coverage

blib/lib/Aozora2Epub/XHTML/Tree.pm
Criterion Covered Total %
statement 61 63 96.8
branch 7 8 87.5
condition n/a
subroutine 19 19 100.0
pod 0 5 0.0
total 87 95 91.5


line stmt bran cond sub pod time code
1             package Aozora2Epub::XHTML::Tree;
2 6     6   34 use strict;
  6         36  
  6         215  
3 6     6   46 use warnings;
  6         10  
  6         330  
4 6     6   36 use utf8;
  6         11  
  6         45  
5 6     6   3393 use HTML::TreeBuilder::XPath;
  6         446480  
  6         69  
6 6     6   3558 use HTML::Selector::XPath qw/selector_to_xpath/;
  6         23229  
  6         4724  
7              
8             our $VERSION = '0.05';
9              
10             sub new {
11 40     40 0 111 my ($class, $str) = @_;
12              
13 40         378 my $tree= HTML::TreeBuilder::XPath->new;
14 40         12964 $tree->ignore_unknown(0);
15 40         626 $tree->store_comments(1);
16 40         1173 $tree->parse($str);
17 40         50450 $tree->eof;
18 40         7617 my $dummy_node = HTML::Element->new_from_lol(['dummy', $tree->guts]);
19 40         12090 my $obj = bless {tree=>$tree, result=>$dummy_node}, $class;
20             }
21              
22             sub _selector {
23 600     600   947 my $selector = shift;
24 600 100       3375 if ($selector =~ m{(?:/|id\()}) {
25             # XPath
26 80         379 $selector =~ s{^/([^/])}{/dummy/$1};
27 80         212 return $selector;
28             }
29 520         1565 return selector_to_xpath($selector);
30             }
31              
32             sub _select {
33 600     600   1188 my ($self, $selector) = @_;
34 600         1318 $selector = _selector($selector);
35 600         68797 return [ $self->_result->findnodes($selector) ];
36             }
37              
38             sub _apply(&$) { ## no critic (ProhibitSubroutinePrototypes)
39 216     216   1617 _apply0(@_);
40             }
41              
42             sub _apply0 {
43 253     253   514 my ($sub, $elem) = @_;
44 253 100       1123 if ($elem->isa('HTML::Element')) {
45 211         409 return $sub->($elem);
46             }
47 42         176 return $elem;
48             }
49              
50             sub _map_apply(&@) { ## no critic (ProhibitSubroutinePrototypes)
51 40     40   161 my ($sub, @nodes) = @_;
52 40         99 return map { _apply0($sub, $_) } @nodes;
  37         122  
53             }
54              
55             sub _result {
56 760     760   107921 my ($self, $nodes) = @_;
57 760 100       3690 return $self->{result} unless $nodes;
58 80     117   478 _apply { $_->detach } $_ for @$nodes;
  117         324  
59 80         1658 $self->{result} = HTML::Element->new_from_lol(['dummy', @$nodes]);
60             }
61              
62              
63             sub select {
64 40     40 0 170 my ($self, $selector) = @_;
65 40         126 $self->_result($self->_select($selector));
66 40         4941 return $self;
67             }
68              
69             sub process {
70 560     560 0 1365 my ($self, $selector, $sub) = @_;
71 560         813 my $nodes;
72 560 50       1369 if (ref $selector eq 'CODE') {
73 0         0 $sub = $selector;
74 0         0 $nodes = $self->_result;
75             } else {
76 560         1385 $nodes = $self->_select($selector);
77             }
78 560     57   767378 _apply { $sub->($_) } $_ for @$nodes;
  57         215  
79 560         4483 return $self;
80             }
81              
82             sub children {
83 40     40 0 92 my $self = shift;
84 40         126 my @nodes = $self->_result->content_list;
85 40     37   437 $self->_result([_map_apply { $_->content_list } @nodes]);
  37         103  
86 40         4938 return $self;
87             }
88              
89             sub as_list {
90 40     40 0 83 my $self = shift;
91 40         137 return $self->_result->content_list;
92             }
93              
94             1;
95              
96              
97             __END__