File Coverage

blib/lib/Map/Tube/Text/Table/Utils.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Map::Tube::Text::Table::Utils;
2              
3             # Pragmas.
4 3     3   25653 use base qw(Exporter);
  3         5  
  3         250  
5 3     3   12 use strict;
  3         3  
  3         92  
6 3     3   12 use warnings;
  3         6  
  3         84  
7              
8             # Modules.
9 3     3   10 use List::Util qw(sum);
  3         6  
  3         257  
10 3     3   1510 use Readonly;
  3         7192  
  3         131  
11 3     3   1379 use Text::UnicodeBox;
  0            
  0            
12             use Text::UnicodeBox::Control qw(:all);
13              
14             # Constants.
15             Readonly::Array our @EXPORT_OK => qw(table);
16             Readonly::Scalar our $EMPTY_STR => q{};
17             Readonly::Scalar our $SPACE => q{ };
18             Readonly::Scalar our $SPACE_ON_END_COUNT => 1;
19              
20             # Version.
21             our $VERSION = 0.04;
22              
23             # Print table.
24             sub table {
25             my ($title, $data_len_ar, $header_ar, $data_ar) = @_;
26              
27             # Check data.
28             if (! @{$data_ar}) {
29             return $EMPTY_STR;
30             }
31              
32             my $t = Text::UnicodeBox->new;
33              
34             # Table title.
35             my $pipes_in_count = @{$data_len_ar} * 2 - 2;
36             $t->add_line(
37             BOX_START('bottom' => 'light', 'top' => 'light'),
38             _column_left($title, sum(map { $_ + $SPACE_ON_END_COUNT }
39             @{$data_len_ar}) + $pipes_in_count),
40             BOX_END(),
41             );
42              
43             # Legend.
44             if (defined $header_ar) {
45             $t->add_line(
46             BOX_START('bottom' => 'light', 'top' => 'light'),
47             _columns($header_ar, $data_len_ar),
48             );
49             }
50              
51             # Data.
52             while (my $row_ar = shift @{$data_ar}) {
53             $t->add_line(
54             BOX_START(
55             @{$data_ar} == 0 ? ('bottom' => 'light') : (),
56             ),
57             _columns($row_ar, $data_len_ar),
58             );
59             }
60              
61             # Render to output.
62             return $t->render;
63             }
64              
65             # Column text with left align.
66             sub _column_left {
67             my ($text, $width) = @_;
68             my $text_len = length $text;
69             return $SPACE.$text.($SPACE x ($width - $text_len));
70             }
71              
72             # Get Text::UnicodeBox columns.
73             sub _columns {
74             my ($data_ar, $data_len_ar) = @_;
75             my @ret;
76             my $i = 0;
77             foreach my $item (@{$data_ar}) {
78             push @ret, _column_left($item, $data_len_ar->[$i++]
79             + $SPACE_ON_END_COUNT);
80             if (@{$data_ar} > $i) {
81             push @ret, BOX_RULE;
82             } else {
83             push @ret, BOX_END;
84             }
85             }
86             return @ret;
87             }
88              
89             1;
90              
91             __END__
92              
93             =pod
94              
95             =encoding utf8
96              
97             =head1 NAME
98              
99             Map::Tube::Text::Table::Utils - Utilities for Map::Tube::Text::Table.
100              
101             =head1 SYNOPSIS
102              
103             use Map::Tube::Text::Table::Utils qw(table);
104             my $table = table($title, $data_len_ar, $header_ar, $data_ar);
105              
106             =head1 SUBROUTINES
107              
108             =over 8
109              
110             =item C<table($title, $data_len_ar, $header_ar, $data_ar)>
111              
112             Print table.
113             Returns text.
114              
115             =back
116              
117             =head1 EXAMPLE1
118              
119             # Pragmas.
120             use strict;
121             use warnings;
122              
123             # Module.
124             use Encode qw(encode_utf8);
125             use Map::Tube::Text::Table::Utils qw(table);
126              
127             # Get table.
128             my $table = table('Title', [1, 2, 3], ['A', 'BB', 'CCC'], [
129             ['E', 'A', 'A'],
130             ['A', 'Ga', 'Acv'],
131             ]);
132              
133             # Print table.
134             print encode_utf8($table);
135              
136             # Output:
137             # ┌──────────────┐
138             # │ Title │
139             # ├───┬────┬─────┤
140             # │ A │ BB │ CCC │
141             # ├───┼────┼─────┤
142             # │ E │ A │ A │
143             # │ A │ Ga │ Acv │
144             # └───┴────┴─────┘
145              
146             =head1 DEPENDENCIES
147              
148             L<Exporter>,
149             L<List::Util>,
150             L<Readonly>,
151             L<Text::UnicodeBox>,
152             L<Text::UnicodeBox::Control>.
153              
154             =head1 SEE ALSO
155              
156             L<Map::Tube>,
157             L<Map::Tube::Text::Table>,
158             L<Task::Map::Tube>.
159              
160             =head1 REPOSITORY
161              
162             L<https://github.com/tupinek/Map-Tube-Text-Table>
163              
164             =head1 AUTHOR
165              
166             Michal Å paček L<mailto:skim@cpan.org>
167              
168             L<http://skim.cz>
169              
170             =head1 LICENSE AND COPYRIGHT
171              
172             © 2014-2015 Michal Å paček
173             Artistic License
174             BSD 2-Clause License
175              
176             =head1 VERSION
177              
178             0.04
179              
180             =cut