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.02';
4              
5 1     1   170207 use strict;
  1         6  
  1         24  
6 1     1   4 use warnings;
  1         2  
  1         21  
7 1     1   224 use parent 'Exporter';
  1         226  
  1         4  
8 1     1   261 use HTML::Escape 'escape_html';
  1         618  
  1         320  
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   9 no strict 'refs';
  1         4  
  1         1459  
65 115     115 0 291 my ($name, $code) = @_;
66 115         214 *{"${name}"} = $code;
  115         587  
67             }
68              
69             sub e ($){
70 42     42 0 240 goto \&escape_html;
71             }
72              
73             sub indent {
74 56     56 0 261 return ' ' x ($DEPTH * $INDENT);
75             }
76              
77             sub element ($&){
78 15     15 1 45 my ($tag, $code) = @_;
79              
80 15         31 my $html = do {
81 15         30 local @CLASS;
82 15         29 local @ATTR;
83 15         27 local @PROP;
84 15         26 local @BODY;
85              
86 15         26 ++$DEPTH;
87 15         36 my $inner_html = $code->();
88 15         45 --$DEPTH;
89              
90 15 100       44 if ($inner_html) {
91 6         14 push @BODY, $inner_html;
92             }
93              
94 15         31 my @attrs;
95 15         47 for (my $i = 0; $i < @ATTR; $i += 2) {
96 2         11 push @attrs, qq{$ATTR[$i]="$ATTR[$i + 1]"};
97             }
98              
99 15 100       31 my $attr = ''; $attr = ' ' . join ' ', @attrs if @attrs;
  15         43  
100 15 100       35 my $prop = ''; $prop = ' ' . join ' ', @PROP if @PROP;
  15         40  
101 15 100       28 my $class = ''; $class = sprintf ' class="%s"', join ' ', @CLASS if @CLASS;
  15         42  
102              
103 15 100       40 if (@BODY) {
104 12         28 my $open = sprintf '%s<%s%s%s%s>', indent, $tag, $class, $attr, $prop;
105 12         35 my $close = sprintf '%s', indent, $tag;
106 12         76 join("\n", $open, join("\n", @BODY), $close);
107             }
108             else {
109 3         9 sprintf q{%s<%s%s%s%s>}, indent, $tag, $class, $attr, $prop, $tag;
110             }
111             };
112              
113 15         41 my $void = !defined wantarray;
114              
115             # At root of tag stack or called in non-void context
116 15 100 100     66 if ($DEPTH == 0 || !$void) {
117 10         47 return $html;
118             }
119             # Inner-tag body call in void context
120             else {
121 5         14 push @BODY, $html;
122 5         17 return;
123             }
124             }
125              
126 4     4 1 5296 sub class (@){ push @CLASS, map{ e $_ } map{ split /\s+/, $_ } @_; return; }
  8         19  
  7         43  
  4         28  
127 4     4 1 6132 sub prop (@){ push @PROP, map{ e $_ } @_; return; }
  8         37  
  4         22  
128 10     10 1 10055 sub text (@){ push @BODY, map{ indent . e $_ } @_; return; }
  14         41  
  10         52  
129 3     3 1 6701 sub raw (@){ push @BODY, map{ indent . $_ } @_; return; }
  7         21  
  3         21  
130 4     4 1 3802 sub note (@){ push @BODY, map{ indent . '' } @_; return }
  8         16  
  4         15  
131              
132             sub attr (@){
133 2     2 1 17 for (my $i = 0; $i < @_; $i += 2) {
134 2         9 push @ATTR, e $_[$i], e $_[$i + 1];
135             }
136              
137 2         7 return;
138             }
139              
140             foreach my $tag (@TAGS){
141 15     15   4374 install_sub($tag, sub(&){ unshift @_, $tag; goto \&element; });
  15         62  
142             }
143              
144             1;
145              
146             __END__