File Coverage

blib/lib/HTML/LoL.pm
Criterion Covered Total %
statement 107 123 86.9
branch 36 48 75.0
condition 19 36 52.7
subroutine 20 21 95.2
pod 4 11 36.3
total 186 239 77.8


line stmt bran cond sub pod time code
1             package HTML::LoL::Special;
2              
3             sub new {
4 5     5   10 my($type, $str) = @_;
5 5         17 bless \$str, $type;
6             }
7              
8             package HTML::LoL;
9              
10 1     1   7436 use strict;
  1         3  
  1         40  
11 1     1   5 use base 'Exporter';
  1         3  
  1         128  
12 1     1   6 use vars qw(@ISA @EXPORT $VERSION);
  1         7  
  1         82  
13              
14             $VERSION = '1.3';
15             @EXPORT = qw(hl hl_noquote hl_requote hl_entity hl_bool hl_preserve);
16              
17 1     1   4 use constant TABWIDTH => 8;
  1         2  
  1         68  
18              
19 1     1   1434 use HTML::Entities;
  1         8332  
  1         145  
20 1     1   1127 use HTML::Tagset;
  1         14108  
  1         5180  
21              
22             my $hl_bool_yes = new HTML::LoL::Special('bool_yes');
23             my $hl_bool_no = new HTML::LoL::Special('bool_no');
24             my $hl_noquote = new HTML::LoL::Special('noquote');
25             my $hl_requote = new HTML::LoL::Special('requote');
26             my $hl_preserve = new HTML::LoL::Special('preserve');
27              
28             sub is_bool_yes {
29 6     6 0 7 my $x = shift;
30 6   100     45 return UNIVERSAL::isa($x, 'HTML::LoL::Special') && ($$x eq 'bool_yes');
31             }
32              
33             sub is_bool_no {
34 5     5 0 7 my $x = shift;
35 5   66     44 return UNIVERSAL::isa($x, 'HTML::LoL::Special') && ($$x eq 'bool_no');
36             }
37              
38             sub is_noquote {
39 10     10 0 16 my $x = shift;
40 10   100     97 return UNIVERSAL::isa($x, 'HTML::LoL::Special') && ($$x eq 'noquote');
41             }
42              
43             sub is_requote {
44 8     8 0 11 my $x = shift;
45 8   66     277 return UNIVERSAL::isa($x, 'HTML::LoL::Special') && ($$x eq 'requote');
46             }
47              
48             sub is_preserve {
49 8     8 0 12 my $x = shift;
50 8   66     49 return UNIVERSAL::isa($x, 'HTML::LoL::Special') && ($$x eq 'preserve');
51             }
52              
53             # elements inside which it is OK to add whitespace
54             my %hl_wsok;
55             map { $hl_wsok{$_} = 1 } qw(area col colgroup frame frameset
56             head html object table tr);
57              
58             # elements whose layout should not be altered
59             my %hl_pre;
60             map { $hl_pre{$_} = 1 } qw(pre style script textarea);
61              
62             sub _emit {
63 35     35   120 my($cb, $str, $columnref) = @_;
64 35         336 my $result = &$cb($str);
65              
66 35 50       561 if ($str =~ /.*\n([^\n]*)$/s) {
67 0         0 $str = $1;
68 0         0 $$columnref = 0;
69             }
70 35         384 my @s = split(/\t/, $str);
71 35         260 foreach my $s (@s) {
72 35         75 $$columnref += length($s);
73             }
74 35 50       234 if (@s > 1) {
75 0         0 $$columnref += (TABWIDTH * (@s - 1));
76 0         0 $$columnref = int($$columnref / TABWIDTH);
77 0         0 ++$$columnref;
78 0         0 $$columnref *= TABWIDTH;
79             }
80              
81 35         96 return $result;
82             }
83              
84             sub _str {
85 9     9   17 my($cb, $str, $depth, $columnref, $wsokref, $pre, $noquote) = @_;
86              
87 9         8 my $result;
88              
89 9 100       37 $str = &encode_entities($str) unless $noquote;
90 9 100       91 if ($pre) {
91 1         4 $result = &_emit($cb, $str, $columnref);
92             } else {
93 8         21 my $leading_ws = ($str =~ /^\s/s);
94 8         16 my $trailing_ws = ($str =~ /\s$/s);
95              
96 8         14 $str =~ s/^\s+//s;
97 8         20 $str =~ s/\s+$//s;
98              
99 8         20 my @words = split(/\s+/, $str);
100              
101 8 50 0     16 if (@words) {
    0          
102 8   33     31 $$wsokref ||= $leading_ws;
103              
104 8         19 foreach my $word (@words) {
105 8 50       24 if ($$wsokref) {
106 0 0 0     0 if (($$columnref > 0)
107             && ((1 + length($word) + $$columnref) > 72)) {
108 0         0 $result = &_emit($cb, ("\n" . (' ' x ($depth + 1))), $columnref);
109             } else {
110 0         0 $result = &_emit($cb, ' ', $columnref);
111             }
112             }
113              
114 8         20 $result = &_emit($cb, $word, $columnref);
115              
116 8         39 $$wsokref = 1;
117             }
118             } elsif ($leading_ws || $trailing_ws) {
119 0         0 $result = &_emit($cb, ' ', $columnref);
120             }
121              
122 8         17 $$wsokref = $trailing_ws;
123             }
124              
125 9         20 return $result;
126             }
127              
128             sub _node {
129 10     10   16 my($cb, $node, $depth, $columnref, $wsokref, $pre, $noquote) = @_;
130              
131 10         13 my $result;
132              
133 10         113 my @node = @$node;
134 10         15 my $tag = $node[0];
135              
136 10         10 my $empty;
137              
138 10 100       19 if (&is_noquote($tag)) {
    50          
    100          
139 2         3 $noquote = 1;
140 2         4 undef $tag;
141             } elsif (&is_requote($tag)) {
142 0         0 $noquote = 0;
143 0         0 undef $tag;
144             } elsif (&is_preserve($tag)) {
145 1         2 $pre = 1;
146 1         2 undef $tag;
147             } else {
148 7         12 $tag = lc($tag);
149 7         15 $empty = $HTML::Tagset::emptyElement{$tag};
150 7   66     30 $pre ||= $hl_pre{$tag};
151             }
152              
153 10 50 33     136 if ($$wsokref && !$pre) {
154 0         0 $result = &_emit($cb, ("\n" . (' ' x $depth)), $columnref);
155             }
156              
157 10 100       22 if (defined($tag)) {
158 7         21 $result = &_emit($cb, "<$tag", $columnref);
159 7         16 foreach my $content (@node[1 .. $#node]) {
160 12 100       38 next unless ref($content) eq 'HASH';
161 5         15 foreach my $hashitem (keys %$content) {
162 6         11 my $val = $content->{$hashitem};
163              
164 6 100       10 if (&is_bool_yes($val)) {
    100          
    100          
165 1         4 $result = &_emit($cb, " $hashitem", $columnref);
166             } elsif (&is_bool_no($val)) {
167             # do nothing
168             } elsif (ref($val) eq 'ARRAY') {
169             # the caller wants the value interpolated literally
170 1         24 $result = &_emit($cb,
171             sprintf(' %s=%s', $hashitem, $val->[0]),
172             $columnref);
173             } else {
174 3         9 $result = &_emit($cb,
175             sprintf(' %s="%s"', $hashitem,
176             &encode_entities($val)),
177             $columnref);
178             }
179             }
180             }
181 7         14 $result = &_emit($cb, ">", $columnref);
182 7         14 $$wsokref = $hl_wsok{$tag};
183             }
184              
185 10         94 foreach my $content (@node[1 .. $#node]) {
186 15         21 my $ref = ref($content);
187 15 100       587 next if ($ref eq 'HASH');
188              
189 10 100       20 if ($ref eq 'ARRAY') {
190 1         9 $result = &_node($cb, $content, $depth + 1, $columnref, $wsokref,
191             $pre, $noquote);
192             } else {
193 9         23 $result = &_str($cb, $content, $depth + 1, $columnref, $wsokref,
194             $pre, $noquote);
195             }
196              
197 10 100 33     444 $$wsokref ||= $hl_wsok{$tag} if defined($tag);
198             }
199              
200 10 100 66     172 if (defined($tag) && !$empty) {
201 7 50       13 if ($$wsokref) {
202 0         0 $result = &_emit($cb, ("\n" . (' ' x $depth)), $columnref);
203             }
204 7         22 $result = &_emit($cb, "", $columnref);
205 7         11 $$wsokref = 0;
206             }
207              
208 10         35 return $result;
209             }
210              
211             sub hl {
212 9     9 0 918 my $cb = $_[0];
213              
214 9         11 my $column = 0;
215 9         10 my $wsok = 0;
216              
217 9         9 my $result;
218              
219 9         24 foreach my $elt (@_[1 .. $#_]) {
220 9 50       20 if (ref($elt)) {
221 9         30 $result = &_node($cb, $elt, 0, \$column, \$wsok, 0, 0);
222             } else {
223 0         0 $result = &_str($cb, $elt, 0, \$column, \$wsok, 0, 0);
224             }
225             }
226              
227 9         35 return $result;
228             }
229              
230 1     1 1 22 sub hl_noquote { [$hl_noquote => @_]; }
231 0     0 1 0 sub hl_requote { [$hl_requote => @_]; }
232 1     1 1 8 sub hl_preserve { [$hl_preserve => @_]; }
233 1     1 1 4 sub hl_entity { [$hl_noquote => map { "&$_;" } @_]; }
  1         37  
234              
235 2 100   2 0 92 sub hl_bool { $_[0] ? $hl_bool_yes : $hl_bool_no }
236              
237             1;
238              
239             __END__