File Coverage

lib/Data/HTML/TreeDumper.pm
Criterion Covered Total %
statement 107 108 99.0
branch 29 34 85.2
condition 12 18 66.6
subroutine 24 24 100.0
pod 8 8 100.0
total 180 192 93.7


line stmt bran cond sub pod time code
1             package Data::HTML::TreeDumper;
2 2     2   89570 use 5.010;
  2         66  
3 2     2   13 use strict;
  2         4  
  2         83  
4 2     2   22 use warnings;
  2         7  
  2         131  
5 2     2   16 use utf8;
  2         9  
  2         28  
6 2     2   1587 use Encode;
  2         24135  
  2         145  
7 2     2   13 use Carp qw(croak);
  2         6  
  2         150  
8 2     2   509 use YAML::Syck qw(Load LoadFile Dump DumpFile);
  2         1988  
  2         153  
9 2     2   1102 use Ref::Util qw(is_ref is_scalarref is_arrayref is_hashref);
  2         3567  
  2         159  
10 2     2   943 use Const::Fast;
  2         5125  
  2         13  
11 2     2   1108 use HTML::Entities;
  2         12298  
  2         144  
12 2     2   1007 use HTML::AutoTag;
  2         5024  
  2         70  
13              
14 2     2   1035 use version 0.77; our $VERSION = version->declare("v0.0.4");
  2         3968  
  2         15  
15              
16             $YAML::Syck::ImplicitUnicode = 1;
17             $YAML::Syck::ImplicitTyping = 1;
18             $YAML::Syck::Headless = 1;
19              
20             const my %default => (
21             ClassKey => 'trdKey',
22             ClassValue => 'trdValue',
23             ClassOrderedList => 'trdOL',
24             ClassUnorderedList => 'trdUL',
25             StartOrderedList => 0,
26             MaxDepth => 32,
27             );
28              
29             my $autoTag = HTML::AutoTag->new( encode => 0, sorted => 1 );
30              
31             #region Class methods
32              
33             sub new {
34 2     2 1 3024 my $class = shift;
35             my $args = {
36             %default,
37             MaxDepth => 8,
38 2 50       25 ( is_hashref( $_[0] ) ? %{ $_[0] } : @_ ),
  0         0  
39             };
40 2         5 my $self = {};
41 2         5 bless $self, $class;
42 2         11 $self->ClassKey( $args->{ClassKey} );
43 2         7 $self->ClassValue( $args->{ClassValue} );
44 2         7 $self->ClassOrderedList( $args->{ClassOrderedList} );
45 2         8 $self->ClassUnorderedList( $args->{ClassUnorderedList} );
46 2         9 $self->StartOrderedList( $args->{StartOrderedList} );
47 2         6 $self->MaxDepth( $args->{MaxDepth} );
48 2         7 return $self;
49             }
50              
51             #endregion
52              
53             #region Instance properties
54              
55             sub ClassKey {
56 52     52 1 82 my $self = shift;
57 52 100       144 if (@_) {
58 2         9 $self->{ClassKey} = shift;
59             }
60 52         169 return $self->{ClassKey};
61             }
62              
63             sub ClassValue {
64 46     46 1 171 my $self = shift;
65 46 100       96 if (@_) {
66 2         11 $self->{ClassValue} = shift;
67             }
68 46         168 return $self->{ClassValue};
69             }
70              
71             sub ClassOrderedList {
72 16     16 1 211 my $self = shift;
73 16 100       36 if (@_) {
74 2         5 $self->{ClassOrderedList} = shift;
75             }
76 16         44 return $self->{ClassOrderedList};
77             }
78              
79             sub ClassUnorderedList {
80 22     22 1 320 my $self = shift;
81 22 100       70 if (@_) {
82 2         5 $self->{ClassUnorderedList} = shift;
83             }
84 22         85 return $self->{ClassUnorderedList};
85             }
86              
87             sub StartOrderedList {
88 16     16 1 21 my $self = shift;
89 16 100       31 if (@_) {
90 2         4 $self->{StartOrderedList} = shift;
91             }
92 16         65 return $self->{StartOrderedList};
93             }
94              
95             sub MaxDepth {
96 38     38 1 51 my $self = shift;
97 38 100       78 if (@_) {
98 2         4 my $value = shift;
99             $self->{MaxDepth}
100             = $value < 0 ? 0
101             : $value > $default{MaxDepth} ? $default{MaxDepth}
102 2 50       10 : $value;
    50          
103             }
104 38         85 return $self->{MaxDepth};
105             }
106              
107             #endregion
108              
109             #region Instance methods
110              
111             sub dump {
112 67     67 1 22471 my $self = shift;
113 67   100     156 my $x = shift // return $self->_dumpRaw('[undef]');
114 64         130 my $name = $self->_normalizeName( $x, shift );
115 64   100     159 my $depth = shift || 0;
116             my $result
117             = !is_ref($x) ? $self->_dumpRaw( $x, $name )
118 64 50       213 : is_scalarref($x) ? $self->dump( ${$x}, $name, $depth + 1 )
  6 100       19  
    100          
    100          
119             : is_arrayref($x) ? $self->_dumpArray( $x, $name, $depth + 1 )
120             : is_hashref($x) ? $self->_dumpHash( $x, $name, $depth + 1 )
121             : $self->_dumpRaw( $x, $name );
122 64         5651 return $result;
123             }
124              
125             sub _normalizeName {
126 142     142   184 my $self = shift;
127 142         187 my $x = shift;
128 142         186 my $name = shift;
129 142   100     408 return $name || ref($x) || 'unnamed';
130             }
131              
132             sub _dumpRaw {
133 42     42   62 my $self = shift;
134 42   50     71 my $x = shift // '';
135 42         81 my $name = $self->_normalizeName( $x, shift );
136 42   50     115 my $depth = shift || 0;
137 42         98 return $autoTag->tag(
138             tag => 'span',
139             attr => { class => $self->ClassValue(), },
140             cdata => encode_entities($x),
141             );
142             }
143              
144             sub _dumpArray {
145 15     15   19 my $self = shift;
146 15   50     30 my $x = shift // '';
147 15         29 my $name = $self->_normalizeName( $x, shift );
148 15   50     32 my $depth = shift || 0;
149 15 100       28 if ( $depth > $self->MaxDepth() ) {
150 1         7 return $autoTag->tag(
151             tag => 'span',
152             attr => { class => $self->ClassKey(), },
153             cdata => encode_entities($name),
154             )
155             . ': '
156             . $autoTag->tag(
157             tag => 'span',
158             attr => { class => $self->ClassValue(), },
159             cdata => '[...]',
160             );
161             }
162 14         23 my $inner = [ map { { tag => 'li', cdata => $self->dump( $_, undef, $depth ) } } @{$x} ];
  24         55  
  14         38  
163 14         100 return $autoTag->tag(
164             tag => 'details',
165             cdata => [
166             { tag => 'summary',
167             attr => { class => $self->ClassKey(), },
168             cdata => encode_entities($name),
169             },
170             { tag => 'ol',
171             attr => { class => $self->ClassOrderedList(), start => $self->StartOrderedList() },
172             cdata => $inner,
173             },
174             ],
175             );
176             }
177              
178             sub _dumpHash {
179 21     21   33 my $self = shift;
180 21   50     45 my $x = shift // '';
181 21         47 my $name = $self->_normalizeName( $x, shift );
182 21   50     45 my $depth = shift || 0;
183 21 100       38 if ( $depth > $self->MaxDepth() ) {
184 1         7 return $autoTag->tag(
185             tag => 'span',
186             attr => { class => $self->ClassKey(), },
187             cdata => encode_entities($name),
188             )
189             . ': '
190             . $autoTag->tag(
191             tag => 'span',
192             attr => { class => $self->ClassValue(), },
193             cdata => '{...}',
194             );
195             }
196             my $inner = [
197             map {
198             is_arrayref( $x->{$_} )
199             ? { tag => 'li', cdata => $self->_dumpArray( $x->{$_}, $_, $depth + 1 ) }
200             : is_hashref( $x->{$_} )
201             ? { tag => 'li', cdata => $self->_dumpHash( $x->{$_}, $_, $depth + 1 ) }
202             : {
203             tag => 'li',
204             cdata => $autoTag->tag(
205             tag => 'span',
206             attr => { class => $self->ClassKey(), },
207             cdata => encode_entities($_)
208             )
209             . ': '
210 31 100       1205 . $self->dump( $x->{$_}, $_, $depth + 1 )
    50          
211             }
212 20         29 } sort( keys( %{$x} ) )
  20         61  
213             ];
214 20         1595 return $autoTag->tag(
215             tag => 'details',
216             cdata => [
217             { tag => 'summary',
218             attr => { class => $self->ClassKey(), },
219             cdata => encode_entities($name),
220             },
221             { tag => 'ul',
222             attr => { class => $self->ClassUnorderedList(), },
223             cdata => $inner,
224             },
225             ],
226             );
227             }
228              
229             #endregion
230              
231             1;
232              
233             __END__