File Coverage

blib/lib/HTML/Untidy.pm
Criterion Covered Total %
statement 71 71 100.0
branch 12 12 100.0
condition 3 3 100.0
subroutine 16 16 100.0
pod 7 10 70.0
total 109 112 97.3


line stmt bran cond sub pod time code
1             package HTML::Untidy;
2             # ABSTRACT: yet another way to write HTML quickly and programmatically
3             $HTML::Untidy::VERSION = '0.01';
4              
5 1     1   183789 use strict;
  1         8  
  1         28  
6 1     1   4 use warnings;
  1         2  
  1         29  
7 1     1   273 use parent 'Exporter';
  1         235  
  1         3  
8 1     1   351 use HTML::Escape 'escape_html';
  1         474  
  1         200  
9              
10             my @BASE = qw(element class attr prop text raw note);
11              
12             # source: https://developer.mozilla.org/en-US/docs/Web/HTML/Element
13             my @TAGS = qw(
14             a abbr address area article aside audio
15             b base bdi bdo blockquote body br button
16             canvas caption cite code col colgroup
17             data datalist dd del details dfn dialog div dl dt
18             em embed
19             fieldset figcaption figure footer form
20             h1 h2 h3 h4 h5 h6 head header hgroup hr html
21             i iframe img input ins
22             kbd
23             label legend li link
24             main map mark menu menuitem meta meter
25             nav noframes noscript
26             object ol optgroup option output
27             p param picture pre progress
28             q
29             rp rt rtc ruby
30             s samp script section select slot small source span strong style sub summary sup
31             table tbody td template textarea tfoot th thead time title tr track
32             u ul
33             var video
34             wbr
35             );
36              
37             my @COMMON = qw(
38             html head body title meta link script style
39             h1 h2 h3 h4 h5 h6
40             div p hr pre nav code img a b i u em strong sup sub small
41             table tbody thead tr th td
42             ul dl ol li dd dt
43             form input textarea select option button label
44             canvas
45             );
46              
47             our @EXPORT_OK = (@BASE, @TAGS);
48              
49             our %EXPORT_TAGS = (
50             base => [@BASE],
51             common => [@BASE, @COMMON],
52             all => [@BASE, @TAGS],
53             );
54              
55             our @CLASS;
56             our @ATTR;
57             our @PROP;
58             our @BODY;
59             our $INDENT = 0;
60              
61             my $DEPTH = 0;
62              
63             sub install_sub{
64 1     1   6 no strict 'refs';
  1         2  
  1         667  
65 115     115 0 151 my ($name, $code) = @_;
66 115         113 *{"${name}"} = $code;
  115         323  
67             }
68              
69             sub e ($){
70 42     42 0 195 goto \&escape_html;
71             }
72              
73             sub indent {
74 56     56 0 216 return ' ' x ($DEPTH * $INDENT);
75             }
76              
77             sub element ($&){
78 15     15 1 37 my ($tag, $code) = @_;
79              
80 15         20 my $html = do {
81 15         21 local @CLASS;
82 15         24 local @ATTR;
83 15         22 local @PROP;
84 15         19 local @BODY;
85              
86 15         23 ++$DEPTH;
87 15         35 my $inner_html = $code->();
88 15         38 --$DEPTH;
89              
90 15 100       31 if ($inner_html) {
91 6         16 push @BODY, $inner_html;
92             }
93              
94 15         19 my @attrs;
95 15         38 for (my $i = 0; $i < @ATTR; $i += 2) {
96 2         9 push @attrs, qq{$ATTR[$i]="$ATTR[$i + 1]"};
97             }
98              
99 15 100       22 my $attr = ''; $attr = ' ' . join ' ', @attrs if @attrs;
  15         33  
100 15 100       21 my $prop = ''; $prop = ' ' . join ' ', @PROP if @PROP;
  15         39  
101 15 100       23 my $class = ''; $class = sprintf ' class="%s"', join ' ', @CLASS if @CLASS;
  15         32  
102              
103 15 100       29 if (@BODY) {
104 12         28 my $open = sprintf '%s<%s%s%s%s>', indent, $tag, $class, $attr, $prop;
105 12         25 my $close = sprintf '%s', indent, $tag;
106 12         51 join("\n", $open, join("\n", @BODY), $close);
107             }
108             else {
109 3         7 sprintf q{%s<%s%s%s%s>}, indent, $tag, $class, $attr, $prop, $tag;
110             }
111             };
112              
113 15         35 my $void = !defined wantarray;
114              
115             # At root of tag stack or called in non-void context
116 15 100 100     55 if ($DEPTH == 0 || !$void) {
117 10         41 return $html;
118             }
119             # Inner-tag body call in void context
120             else {
121 5         9 push @BODY, $html;
122 5         14 return;
123             }
124             }
125              
126 4     4 1 5735 sub class (@){ push @CLASS, map{ e $_ } map{ split /\s+/, $_ } @_; return; }
  8         20  
  7         26  
  4         16  
127 4     4 1 5626 sub prop (@){ push @PROP, map{ e $_ } @_; return; }
  8         14  
  4         16  
128 10     10 1 7847 sub text (@){ push @BODY, map{ indent . e $_ } @_; return; }
  14         31  
  10         35  
129 3     3 1 6305 sub raw (@){ push @BODY, map{ indent . $_ } @_; return; }
  7         11  
  3         13  
130 4     4 1 6414 sub note (@){ push @BODY, map{ indent . '' } @_; return }
  8         19  
  4         18  
131              
132             sub attr (@){
133 2     2 1 13 for (my $i = 0; $i < @_; $i += 2) {
134 2         6 push @ATTR, e $_[$i], e $_[$i + 1];
135             }
136              
137 2         6 return;
138             }
139              
140             foreach my $tag (@TAGS){
141 15     15   3611 install_sub($tag, sub(&){ unshift @_, $tag; goto \&element; });
  15         72  
142             }
143              
144             1;
145              
146             __END__