File Coverage

blib/lib/Data/Format/Pretty/HTML.pm
Criterion Covered Total %
statement 79 82 96.3
branch 11 14 78.5
condition 7 10 70.0
subroutine 16 18 88.8
pod 1 3 33.3
total 114 127 89.7


line stmt bran cond sub pod time code
1             package Data::Format::Pretty::HTML;
2              
3 1     1   22432 use 5.010001;
  1         7  
4 1     1   10 use strict;
  1         4  
  1         37  
5 1     1   9 use warnings;
  1         4  
  1         46  
6 1     1   5129 use Log::ger;
  1         136  
  1         9  
7              
8 1     1   2691 use Data::Format::Pretty::Console 0.24;
  1         149540  
  1         61  
9 1     1   610 use HTML::Entities;
  1         7383  
  1         96  
10 1     1   12 use Scalar::Util qw(looks_like_number);
  1         2  
  1         61  
11 1     1   604 use URI::Find::Schemeless;
  1         50850  
  1         95  
12 1     1   14 use YAML::Any;
  1         11  
  1         11  
13              
14             require Exporter;
15             our @ISA = qw(Exporter Data::Format::Pretty::Console);
16             our @EXPORT_OK = qw(format_pretty);
17              
18             our $VERSION = '0.11'; # VERSION
19              
20 0     0 0 0 sub content_type { "text/html" }
21              
22             sub format_pretty {
23 5     5 1 4848 my ($data, $opts) = @_;
24 5   50     21 $opts //= {};
25 5         21 __PACKAGE__->new($opts)->_format($data);
26             }
27              
28             # OO interface is hidden
29             sub new {
30 9     9 0 6245 my ($class, $opts) = @_;
31 9         48 my $obj = $class->SUPER::new($opts);
32             #my $obj = Data::Format::Pretty::Console->new($opts);
33 9   50     270 $obj->{opts}{linkify_urls_in_text} //= 1;
34 9         23 $obj->{opts}{interactive} = 1;
35 9         21 $obj->{opts}{list_max_columns} = 1;
36             #bless $class, $obj;
37 9         37 $obj;
38             }
39              
40             sub _htmlify {
41 11     11   31 my ($self, $text) = @_;
42              
43 11         39 $text = encode_entities($text);
44 11 50       221 if ($self->{opts}{linkify_urls_in_text}) {
45             URI::Find::Schemeless->new(
46             sub {
47             #my $uri = encode_entities $_[0];
48             #my $uri = $_[0];
49 1     1   6346 my $uri = decode_entities $_[0];
50 1         11 return qq|<a href="$uri">$uri</a>|;
51 11         87 })->find(\$text);
52             }
53 11 100       4746 if ($text =~ /\R/) {
54 1         10 return "<pre>$text</pre>";
55             } else {
56 10         49 return $text;
57             }
58             }
59              
60             sub _render_table {
61 3     3   7752 my ($self, $t) = @_;
62 3         7 my @t = ("<table>\n");
63              
64 3         7 my $sh = $t->{at_opts}{show_header};
65 3 100 66     18 unless (defined($sh) && !$sh) {
66 2         4 push @t, " <thead>\n";
67 2         4 push @t, " <tr>";
68 2         4 for my $c (@{$t->{cols}}) {
  2         4  
69 3 50       15 push @t, (
70             "<th", (looks_like_number($c) ? ' class="number"':''), ">",
71             $self->_htmlify($c),
72             "</th>",
73             );
74             }
75 2         5 push @t, "</tr>\n";
76 2         5 push @t, " </thead>\n";
77             }
78              
79 3         5 push @t, " <tbody>\n";
80 3         15 for my $r (@{$t->{rows}}) {
  3         8  
81 5         10 push @t, " <tr>";
82 5         10 my $cidx = 0;
83 5         9 for my $c (@$r) {
84 7 100 100     31 if ($t->{html_cols} && $t->{html_cols}[$cidx]) {
85 2         5 push @t, "<td>", $c, "</td>";
86             } else {
87 5 100       31 push @t, (
88             "<td", (looks_like_number($c) ? ' class="number"':''), ">",
89             $self->_htmlify($c),
90             "</td>",
91             );
92             }
93 7         17 $cidx++;
94             }
95 5         11 push @t, "</tr>\n";
96             }
97 3         9 push @t, " </tbody>\n";
98 3         5 push @t, "</table>\n";
99 3         27 join "", @t;
100             }
101              
102             # format unknown structure, the default is to dump YAML structure
103             sub _format_unknown {
104 0     0   0 my ($self, $data) = @_;
105 0         0 $self->_htmlify(Dump $data);
106             }
107              
108             sub _format_scalar {
109 3     3   126 my ($self, $data) = @_;
110              
111 3 50       16 my $sdata = defined($data) ? "$data" : "";
112 3         14 $self->_htmlify($sdata);
113             }
114              
115             sub _format_hot {
116 1     1   131 my ($self, $data) = @_;
117 1         2 my @t;
118             # format as 2-column table of key/value
119 1         6 my $t = {cols=>[qw/key value/], html_cols=>[0, 1], rows=>[]};
120 1         5 for my $k (sort keys %$data) {
121 2         44 push @{ $t->{rows} }, [$k, $self->_format($data->{$k})];
  2         9  
122             }
123 1         3 $self->_render_table($t);
124             }
125              
126             1;
127             # ABSTRACT: Pretty-print data structure for HTML output
128              
129             __END__
130              
131             =pod
132              
133             =encoding UTF-8
134              
135             =head1 NAME
136              
137             Data::Format::Pretty::HTML - Pretty-print data structure for HTML output
138              
139             =head1 VERSION
140              
141             This document describes version 0.11 of Data::Format::Pretty::HTML (from Perl distribution Data-Format-Pretty-HTML), released on 2017-07-10.
142              
143             =head1 SYNOPSIS
144              
145             In your program:
146              
147             use Data::Format::Pretty::HTML qw(format_pretty);
148             ...
149             print format_pretty($result);
150              
151             Some example output:
152              
153             Scalar, format_pretty("foo & bar"):
154              
155             foo &amp; bar
156              
157             Scalar multiline, format_pretty("foo\nbar\nbaz"):
158              
159             <pre>foo
160             bar
161             baz</pre>
162              
163             List, format_pretty([qw/foo bar baz qux/]):
164              
165             <table>
166             <tr><td>foo</td></tr>
167             <tr><td>bar</td></tr>
168             <tr><td>baz</td></tr>
169             <tr><td>qux</td></tr>
170             </table>
171              
172             Hash, format_pretty({foo=>"data",bar=>"format",baz=>"pretty",qux=>"html"}):
173              
174             <table>
175             <tr><th>key</th><th>value</th></tr>
176             <tr><td>bar</td><td>format</td></tr>
177             <tr><td>baz</td><td>pretty</td></tr>
178             <tr><td>foo</td><td>data</td></tr>
179             <tr><td>qux</td><td>html</td></tr>
180             </table>
181              
182             2-dimensional array, format_pretty([ [1, 2, ""], [28, "bar", 3], ["foo", 3,
183             undef] ]):
184              
185             <table>
186             <tr><th>column0</th><th>column1</th><th>column2</th></tr>
187             <tr><td class="number">1</td><td class="number">2</td><td></td></tr>
188             <tr><td class="number">28</td><td>bar</td><td class="number">3</td></tr>
189             <tr><td>foo</td><td class="number">3</td><td></td></tr>
190             </table>
191              
192             An array of hashrefs, such as commonly found if you use DBI's fetchrow_hashref()
193             and friends, format_pretty([ {a=>1, b=>2}, {b=>2, c=>3}, {c=>4} ]):
194              
195             <table>
196             <tr><th>a</th><th>b</th><th>c</th></tr>
197             <tr><td class="number">1</td><td class="number">2</td><td></td></tr>
198             <tr><td></td><td class="number">2</td><td class="number">3</td></tr>
199             <tr><td></td><td></td><td class="number">4</td></tr>
200             </table>
201              
202             Some more complex data, format_pretty({summary => "Blah...", users =>
203             [{name=>"budi", domains=>["f.com", "b.com"], quota=>"1000"}, {name=>"arif",
204             domains=>["baz.com"], quota=>"2000"}], verified => 0}):
205              
206             <table>
207              
208             <tr>
209             <td>summary</td>
210             <td>Blah...</td>
211             </tr>
212              
213             <tr>
214             <td>users</td>
215             <td>
216             <table>
217             <tr><th>domains</th><th>name</th><th>quota</th></tr>
218             <tr><td>f.com, b.com</td><td>budi</td><td class="number">1000</td></tr>
219             <tr><td>baz.com</td><td>arif</td><td class="number">2000</td></tr>
220             </td>
221             </tr>
222              
223             <tr>
224             <td>verified</td>
225             <td class="number">0</td>
226             </tr>
227              
228             </table>
229              
230             Structures which can't be handled yet will simply be output as YAML,
231             format_pretty({a => {b=>1}}):
232              
233             <pre>a:
234             b: 1
235             </pre>
236              
237             =head1 DESCRIPTION
238              
239             This module has the same spirit as L<Data::Format::Pretty::Console> (and
240             currently implemented as its subclass). The idea is to throw it some data
241             structure and let it figure out how to best display the data in a pretty HTML
242             format.
243              
244             Differences with Data::Format::Pretty::Console:
245              
246             =over 4
247              
248             =item * hot (hash of table) structure is rendered as table of inner tables
249              
250             =back
251              
252             =for Pod::Coverage new
253              
254             =head1 FUNCTIONS
255              
256             =head2 format_pretty($data, \%opts)
257              
258             Return formatted data structure as HTML. Options:
259              
260             =over 4
261              
262             =item * table_column_orders => [[colname, colname], ...]
263              
264             See Data::Format::Pretty::Console for more details.
265              
266             =item * linkify_urls_in_text => BOOL
267              
268             Whether to convert 'http://foo' in text into '<a
269             href="http://foo">http://foo</a>'. Default is true.
270              
271             =back
272              
273             =head1 HOMEPAGE
274              
275             Please visit the project's homepage at L<https://metacpan.org/release/Data-Format-Pretty-HTML>.
276              
277             =head1 SOURCE
278              
279             Source repository is at L<https://github.com/perlancar/perl-Data-Format-Pretty-HTML>.
280              
281             =head1 BUGS
282              
283             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Format-Pretty-HTML>
284              
285             When submitting a bug or request, please include a test-file or a
286             patch to an existing test-file that illustrates the bug or desired
287             feature.
288              
289             =head1 SEE ALSO
290              
291             L<Data::Format::Pretty>
292              
293             =head1 AUTHOR
294              
295             perlancar <perlancar@cpan.org>
296              
297             =head1 COPYRIGHT AND LICENSE
298              
299             This software is copyright (c) 2017, 2015, 2014, 2013, 2012, 2011 by perlancar@cpan.org.
300              
301             This is free software; you can redistribute it and/or modify it under
302             the same terms as the Perl 5 programming language system itself.
303              
304             =cut