File Coverage

blib/lib/Text/SimpleTable/AutoWidth.pm
Criterion Covered Total %
statement 59 61 96.7
branch 24 26 92.3
condition 1 2 50.0
subroutine 9 11 81.8
pod 2 2 100.0
total 95 102 93.1


line stmt bran cond sub pod time code
1             package Text::SimpleTable::AutoWidth;
2              
3 2     2   1214 use strict;
  2         3  
  2         74  
4 2     2   11 use warnings;
  2         2  
  2         65  
5 2     2   1156 use Moo;
  2         27787  
  2         12  
6              
7             our $VERSION = '0.06';
8              
9             =head1 NAME
10              
11             Text::SimpleTable::AutoWidth - Simple eyecandy ASCII tables with auto-width selection
12              
13             =head1 VERSION
14              
15             Version is 0.06
16              
17             =head1 SYNOPSIS
18              
19             use Text::SimpleTable::AutoWidth;
20              
21             my $t1 = Text::SimpleTable::AutoWidth->new();
22             $t1->row( 'foobarbaz', 'yadayadayada' );
23             print $t1->draw;
24              
25             .-----------+--------------.
26             | foobarbaz | yadayadayada |
27             '-----------+--------------'
28              
29              
30             my $t2 = Text::SimpleTable::AutoWidth->new();
31             $t2->captions( 'Foo', 'Bar' );
32             $t2->row( 'foobarbaz', 'yadayadayada' );
33             $t2->row( 'barbarbarbarbar', 'yada' );
34             print $t2->draw;
35              
36             .-----------------+--------------.
37             | Foo | Bar |
38             +-----------------+--------------+
39             | foobarbaz | yadayadayada |
40             | barbarbarbarbar | yada |
41             '-----------------+--------------'
42              
43              
44             =head1 DESCRIPTION
45              
46             Simple eyecandy ASCII tables with auto-selection columns width,
47             as seen in L.
48              
49             =head1 METHODS
50              
51             =head2 new(@attrs)
52              
53             Inherited constructor from Moo.
54             You can set following attributes:
55              
56             =head3 fixed_width
57              
58             Set fixed width for resulting table. By default it's 0,
59             that's mean "don't fix width", so width of result table
60             will depend on input data.
61              
62             Be warned, that fixed_width will include not only width of your data,
63             but also all surronding characters, like spaces across values,
64             table drawings (like '|') and hypen (if wrapping is needed).
65              
66             =head3 max_width
67              
68             Set maximum width for resulting table. By default it's 0,
69             that's mean "use default value". Default value is stored in
70             $Text::SimpleTable::AutoWidth::WIDTH_LIMIT, and can be changed
71             at any moment. Default value for WIDTH_LIMIT is 200.
72              
73             Be warned, that max_width will include not only width of your data,
74             but also all surronding characters, like spaces across values,
75             table drawings (like '|') and hypen (if wrapping is needed).
76              
77             NB: if you set fixed_width and max_width at same time, then you'll
78             get table with fixed width, but not wider than max_width characters.
79              
80             =head3 captions
81              
82             ArrayRef[Str] for captions in resulting table.
83              
84             =head3 rows
85              
86             ArrayRef[ArrayRef[Str]] for values in each row.
87             You can use next method to add individual rows into table.
88              
89             =cut
90              
91             has 'fixed_width' => ( is => 'rw', default => 0 ); # isa => 'Int'
92             has 'max_width' => ( is => 'rw', default => 0 ); # isa => 'Int'
93              
94             has 'captions' => ( is => 'rw' ); # isa => 'ArrayRef[Str]'
95             has 'rows' => ( is => 'rw' ); # isa => 'ArrayRef[ArrayRef[Str]]'
96              
97             our $WIDTH_LIMIT = 200; # default maximum width
98              
99             =head2 row(@texts)
100              
101             Add new row to table. Return $self, so you can write something like this:
102              
103             print Text::SimpleTable::AutoWidth
104             ->new( max_width => 55, captions => [qw/ Name Age /] )
105             ->row( 'Mother', 59 )
106             ->row( 'Dad', 58 )
107             ->row( 'me', 32 )
108             ->draw();
109              
110             =cut
111              
112             sub row {
113 6     6 1 2912 my ( $self, @texts ) = @_;
114              
115 6 100       19 if ( $self->rows ) {
116 2         2 push( @{ $self->rows }, [@texts] );
  2         9  
117             }
118             else {
119 4         11 $self->rows( [ [@texts] ] );
120             }
121              
122 6         9 return $self;
123             }
124              
125             =head2 draw()
126              
127             Draw table. Really, just calculate column width, and then call Text::SimpleTable->draw().
128              
129             =cut
130              
131 2     2   3319 use List::Util;
  2         3  
  2         134  
132 2     2   878 use Text::SimpleTable;
  2         3429  
  2         1102  
133              
134             sub draw {
135 4     4 1 13 my $self = shift;
136              
137             # count of columns will be same as count of captions, or same
138             # as count of columns in first row, if there is no captions
139             my $columns =
140             ( $self->captions && @{ $self->captions } )
141 4   50     24 || ( $self->rows && @{ $self->rows->[0] } )
142             || 0;
143              
144 4 50       9 return unless $columns;
145              
146             # table will not be wider than limits
147 4 100       17 my $limit =
    100          
148             $self->max_width ? $self->max_width
149             : $self->fixed_width ? $self->fixed_width
150             : $WIDTH_LIMIT;
151              
152             # by default, each column should have at least 2 symbols:
153             # one informative and one for '-' (if we'll need to wrap)
154 4         8 my @max_width = (2) x $columns;
155              
156             # calculate max width of each column
157 4 100       9 for my $row ( ( $self->captions ? $self->captions : () ), @{ $self->rows } ) {
  4         9  
158 7         10 my @row_width = map { length } @$row;
  15         22  
159 7 100       14 $#row_width = $columns - 1 if $#row_width >= $columns;
160              
161             # find new width
162             # we will do this in two passes
163 7         8 my @new_width = @max_width;
164              
165             # first pass:
166             # find new width for all columns, that we can
167             # make wider without need to wrap anything
168 7         16 for my $idx ( 0 .. $#row_width ) {
169 14 100       22 if ( $max_width[$idx] < $row_width[$idx] ) {
170 12         12 $new_width[$idx] = $row_width[$idx];
171              
172             # check for limits
173             my $total = $columns + 1 # for each '|'
174             + $columns * 2 # for spaces around each value
175 12     16   187 + List::Util::reduce { $a + $b } @new_width;
  16         18  
176              
177             # restore old value, if new value will lead to wrap
178 12 100       42 $new_width[$idx] = $max_width[$idx]
179             if $total > $limit;
180             }
181             }
182              
183             # second pass:
184             # find new width for all columns, that we can
185             # make wider and need to wrap something
186 7         12 for my $idx ( 0 .. $#row_width ) {
187 14 100       27 if ( $new_width[$idx] < $row_width[$idx] ) {
188             my $total = $columns + 1 # for each '|'
189             + $columns * 2 # for spaces around each value
190 1     0   5 + List::Util::reduce { $a + $b } @new_width;
  0         0  
191              
192 1         4 $new_width[$idx] += $limit - $total;
193 1         1 last;
194             }
195             }
196              
197             # save new result
198 7         11 @max_width = @new_width;
199              
200             # check for limits
201             my $total = $columns + 1 # for each '|'
202             + $columns * 2 # for spaces around each value
203 7     7   27 + List::Util::reduce { $a + $b } @max_width;
  7         10  
204              
205 7 100       22 last if $total >= $limit;
206             }
207              
208             # check for fixed_width
209 4 100       12 if ( $self->fixed_width ) {
210             my $total = $columns + 1 # for each '|'
211             + $columns * 2 # for spaces around each value
212 1     0   5 + List::Util::reduce { $a + $b } @max_width;
  0         0  
213              
214 1 50       6 $max_width[-1] += $self->fixed_width - $total
215             unless $total == $self->fixed_width;
216             }
217              
218             # prepare drawer
219 4         6 my @params = @max_width;
220              
221 4 100       10 if ( $self->captions ) {
222 1         2 my $idx = 0;
223 1         3 for (@params) {
224 3         12 $_ = [ $_, $self->captions->[ $idx++ ] ];
225             }
226             }
227 4         35 my $tab = Text::SimpleTable->new(@params);
228              
229             # put rows into drawer
230 4         126 $tab->row(@$_) for @{ $self->rows };
  4         20  
231              
232 4         250 return $tab->draw();
233             }
234              
235             __PACKAGE__->meta->make_immutable();
236              
237             =head1 GIT REPOSITORY
238              
239             git clone git://github.com/cub-uanic/Text-SimpleTable-AutoWidth.git
240              
241             =head1 SEE ALSO
242              
243             L, L, L
244              
245             =head1 AUTHOR
246              
247             Oleg Kostyuk, C<< >>
248              
249             =head1 COPYRIGHT & LICENSE
250              
251             Copyright by Oleg Kostyuk.
252              
253             This program is free software; you can redistribute it and/or modify it
254             under the terms of either: the GNU General Public License as published
255             by the Free Software Foundation; or the Artistic License.
256              
257             See http://dev.perl.org/licenses/ for more information.
258              
259             =cut
260              
261             1; # End of Text::SimpleTable::AutoWidth
262