diff options
Diffstat (limited to 'lib/Text/SimpleTable')
-rw-r--r-- | lib/Text/SimpleTable/AutoWidth.pm | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/lib/Text/SimpleTable/AutoWidth.pm b/lib/Text/SimpleTable/AutoWidth.pm new file mode 100644 index 0000000..3287f04 --- /dev/null +++ b/lib/Text/SimpleTable/AutoWidth.pm @@ -0,0 +1,276 @@ +use strict; +use warnings; + +package Text::SimpleTable::AutoWidth; +$Text::SimpleTable::AutoWidth::VERSION = '0.09'; +use Moo; + +# ABSTRACT: Text::SimpleTable::AutoWidth - Simple eyecandy ASCII tables with auto-width selection + + +has 'fixed_width' => ( is => 'rw', default => 0 ); # isa => 'Int' +has 'max_width' => ( is => 'rw', default => 0 ); # isa => 'Int' + +has 'captions' => ( is => 'rw' ); # isa => 'ArrayRef[Str]' +has 'rows' => ( is => 'rw' ); # isa => 'ArrayRef[ArrayRef[Str]]' + +our $WIDTH_LIMIT = 200; # default maximum width + + +sub row { + my ( $self, @texts ) = @_; + + if ( $self->rows ) { + push( @{ $self->rows }, [@texts] ); + } + else { + $self->rows( [ [@texts] ] ); + } + + return $self; +} + + +use List::Util; +use Text::SimpleTable; + +sub draw { + my $self = shift; + + # count of columns will be same as count of captions, or same + # as count of columns in first row, if there is no captions + my $columns = + ( $self->captions && @{ $self->captions } ) + || ( $self->rows && @{ $self->rows->[0] } ) + || 0; + + return unless $columns; + + # table will not be wider than limits + my $limit = + $self->max_width ? $self->max_width + : $self->fixed_width ? $self->fixed_width + : $WIDTH_LIMIT; + + # by default, each column should have at least 2 symbols: + # one informative and one for '-' (if we'll need to wrap) + my @max_width = (2) x $columns; + + # calculate max width of each column + for my $row ( ( $self->captions ? $self->captions : () ), @{ $self->rows } ) { + my @row_width = map { length } @$row; + $#row_width = $columns - 1 if $#row_width >= $columns; + + # find new width + # we will do this in two passes + my @new_width = @max_width; + + # first pass: + # find new width for all columns, that we can + # make wider without need to wrap anything + for my $idx ( 0 .. $#row_width ) { + if ( $max_width[$idx] < $row_width[$idx] ) { + $new_width[$idx] = $row_width[$idx]; + + # check for limits + my $total = $columns + 1 # for each '|' + + $columns * 2 # for spaces around each value + + List::Util::reduce { $a + $b } @new_width; + + # restore old value, if new value will lead to wrap + $new_width[$idx] = $max_width[$idx] + if $total > $limit; + } + } + + # second pass: + # find new width for all columns, that we can + # make wider and need to wrap something + for my $idx ( 0 .. $#row_width ) { + if ( $new_width[$idx] < $row_width[$idx] ) { + my $total = $columns + 1 # for each '|' + + $columns * 2 # for spaces around each value + + List::Util::reduce { $a + $b } @new_width; + + $new_width[$idx] += $limit - $total; + last; + } + } + + # save new result + @max_width = @new_width; + + # check for limits + my $total = $columns + 1 # for each '|' + + $columns * 2 # for spaces around each value + + List::Util::reduce { $a + $b } @max_width; + + last if $total >= $limit; + } + + # check for fixed_width + if ( $self->fixed_width ) { + my $total = $columns + 1 # for each '|' + + $columns * 2 # for spaces around each value + + List::Util::reduce { $a + $b } @max_width; + + $max_width[-1] += $self->fixed_width - $total + unless $total == $self->fixed_width; + } + + # prepare drawer + my @params = @max_width; + + if ( $self->captions ) { + my $idx = 0; + for (@params) { + $_ = [ $_, $self->captions->[ $idx++ ] ]; + } + } + my $tab = Text::SimpleTable->new(@params); + + # put rows into drawer + $tab->row(@$_) for @{ $self->rows }; + + return $tab->draw(); +} + +__PACKAGE__->meta->make_immutable(); + + +1; # End of Text::SimpleTable::AutoWidth + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Text::SimpleTable::AutoWidth - Text::SimpleTable::AutoWidth - Simple eyecandy ASCII tables with auto-width selection + +=head1 VERSION + +version 0.09 + +=head1 SYNOPSIS + + use Text::SimpleTable::AutoWidth; + + my $t1 = Text::SimpleTable::AutoWidth->new(); + $t1->row( 'foobarbaz', 'yadayadayada' ); + print $t1->draw; + + .-----------+--------------. + | foobarbaz | yadayadayada | + '-----------+--------------' + + + my $t2 = Text::SimpleTable::AutoWidth->new(); + $t2->captions( 'Foo', 'Bar' ); + $t2->row( 'foobarbaz', 'yadayadayada' ); + $t2->row( 'barbarbarbarbar', 'yada' ); + print $t2->draw; + + .-----------------+--------------. + | Foo | Bar | + +-----------------+--------------+ + | foobarbaz | yadayadayada | + | barbarbarbarbar | yada | + '-----------------+--------------' + +=head1 DESCRIPTION + +Simple eyecandy ASCII tables with auto-selection columns width, +as seen in L<Catalyst>. + +=head1 METHODS + +=head2 new(@attrs) + +Inherited constructor from Moo. +You can set following attributes: + +=head3 fixed_width + +Set fixed width for resulting table. By default it's 0, +that's mean "don't fix width", so width of result table +will depend on input data. + +Be warned, that fixed_width will include not only width of your data, +but also all surronding characters, like spaces across values, +table drawings (like '|') and hypen (if wrapping is needed). + +=head3 max_width + +Set maximum width for resulting table. By default it's 0, +that's mean "use default value". Default value is stored in +$Text::SimpleTable::AutoWidth::WIDTH_LIMIT, and can be changed +at any moment. Default value for WIDTH_LIMIT is 200. + +Be warned, that max_width will include not only width of your data, +but also all surronding characters, like spaces across values, +table drawings (like '|') and hypen (if wrapping is needed). + +NB: if you set fixed_width and max_width at same time, then you'll +get table with fixed width, but not wider than max_width characters. + +=head3 captions + +ArrayRef[Str] for captions in resulting table. + +=head3 rows + +ArrayRef[ArrayRef[Str]] for values in each row. +You can use next method to add individual rows into table. + +=head2 row(@texts) + +Add new row to table. Return $self, so you can write something like this: + + print Text::SimpleTable::AutoWidth + ->new( max_width => 55, captions => [qw/ Name Age /] ) + ->row( 'Mother', 59 ) + ->row( 'Dad', 58 ) + ->row( 'me', 32 ) + ->draw(); + +=head2 draw() + +Draw table. Really, just calculate column width, and then call Text::SimpleTable->draw(). + +=head1 GIT REPOSITORY + +git clone git://github.com/cub-uanic/Text-SimpleTable-AutoWidth.git + +=head1 SEE ALSO + +L<Text::SimpleTable>, L<Moo>, L<Catalyst> + +=head1 AUTHOR + +Oleg Kostyuk, C<< <cub#cpan.org> >> + +=head1 COPYRIGHT & LICENSE + +Copyright by Oleg Kostyuk. + +This program is free software; you can redistribute it and/or modify it +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. + +See http://dev.perl.org/licenses/ for more information. + +=head1 AUTHOR + +Oleg Kostyuk <cub.uanic@gmail.com> + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2015 by Oleg Kostyuk. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut |