File Coverage

blib/lib/Vote/Count/TextTableTiny.pm
Criterion Covered Total %
statement 127 127 100.0
branch 56 58 96.5
condition 18 20 90.0
subroutine 20 20 100.0
pod 0 1 0.0
total 221 226 97.7


line stmt bran cond sub pod time code
1             $Vote::Count::TextTableTiny::VERSION = '2.02'; # TRIAL
2             use 5.024;
3 50     50   1137087 use strict;
  50         297  
4 50     50   278 use warnings;
  50         100  
  50         1120  
5 50     50   252 use utf8;
  50         106  
  50         1420  
6 50     50   6878 use parent 'Exporter';
  50         273  
  50         436  
7 50     50   5790 use Carp qw/ croak /;
  50         3302  
  50         394  
8 50     50   3640 use Ref::Util 0.202 qw/ is_arrayref /;
  50         109  
  50         3207  
9 50     50   24427 use String::TtyLength 0.02 qw/ tty_width /;
  50         81591  
  50         4048  
10 50     50   21595  
  50         349192  
  50         94793  
11             our @EXPORT_OK = qw/ generate_table /;
12              
13             # Legacy package globals, that can be used to customise the look.
14             # These are only used in the "classic" style.
15             # I wish I could drop them, but I don't want to break anyone's code.
16             our $COLUMN_SEPARATOR = '|';
17             our $ROW_SEPARATOR = '-';
18             our $CORNER_MARKER = '+';
19             our $HEADER_ROW_SEPARATOR = '=';
20             our $HEADER_CORNER_MARKER = 'O';
21              
22             my %arguments = (
23             rows => "the rows, including a possible header row, of the table",
24             header_row => "if true, indicates that the first row is a header row",
25             separate_rows => "if true, a separate rule will be drawn between each row",
26             top_and_tail => "if true, miss out top and bottom edges of table",
27             align => "either single alignment, or an array per of alignments per col",
28             style => "styling of table, one of classic, boxrule, or norule",
29             indent => "indent every row of the table a certain number of spaces",
30             compact => "narrow columns (no space either side of content)",
31             );
32              
33             my %charsets = (
34             classic => { TLC => '+', TT => '+', TRC => '+', HR => '-', VR => '|', FHR => '=', LT => '+', RT => '+', FLT => 'O', FRT => 'O', HC => '+', FHC => 'O', BLC => '+', BT => '+', BRC => '+' },
35             boxrule => { TLC => '┌', TT => '┬', TRC => '┐', HR => '─', VR => '│', FHR => '═', LT => '├', RT => '┤', FLT => '╞', FRT => '╡', HC => '┼', FHC => '╪', BLC => '└', BT => '┴', BRC => '┘' },
36             norule => { TLC => ' ', TT => ' ', TRC => ' ', HR => ' ', VR => ' ', FHR => ' ', LT => ' ', RT => ' ', FLT => ' ', FRT => ' ', HC => ' ', FHC => ' ', BLC => ' ', BT => ' ', BRC => ' ' },
37             markdown => {
38             TLC => '|', TT => ' ', TRC => '|', HR => '-',
39             VR => '|', FHR => ' ', LT => '|', RT => '|',
40             FLT => ' ', FRT => ' ', HC => '|', FHC => ' ',
41             BLC => '|', BT => ' ', BRC => '|',
42             },
43             );
44              
45             {
46             my %param = @_;
47              
48 718     718 0 29698 foreach my $arg (keys %param) {
49             croak "unknown argument '$arg'" if not exists $arguments{$arg};
50 718         1829 }
51 1229 100       3446  
52             my $rows = $param{rows} or croak "you must pass the 'rows' argument!";
53             my @rows = @$rows;
54 717 100       2160 my @widths = _calculate_widths($rows);
55 716         1953  
56 716         1677 $param{style} //= 'classic';
57              
58 716   100     2588 $param{indent} //= '';
59             $param{indent} = ' ' x $param{indent} if $param{indent} =~ /^[0-9]+$/;
60 716   100     3195  
61 716 100       1800 my $style = $param{style};
62             croak "unknown style '$style'" if not exists($charsets{ $style });
63 716         1285 my $char = $charsets{$style};
64 716 50       1809  
65 716         1296 if ($style eq 'classic') {
66             $char->{TLC} = $char->{TRC} = $char->{TT} = $char->{LT} = $char->{RT} = $char->{HC} = $char->{BLC} = $char->{BT} = $char->{BRC} = $CORNER_MARKER;
67 716 100       2054 $char->{HR} = $ROW_SEPARATOR;
    100          
68 309         1324 $char->{VR} = $COLUMN_SEPARATOR;
69 309         593 $char->{FLT} = $char->{FRT} = $char->{FHC} = $HEADER_CORNER_MARKER;
70 309         574 $char->{FHR} = $HEADER_ROW_SEPARATOR;
71 309         648 } elsif ( $style eq 'markdown') {
72 309         569 _md_validate_data( $rows );
73             $param{'header_row'} = 1;
74 403         1115 $param{'top_and_tail'} = 1;
75 400         911 $param{'separate_rows'} = 0;
76 400         768 $param{'indent'} = '';
77 400         720 }
78 400         710  
79             my $header;
80             my @align;
81 713         1261 if (defined $param{align}) {
82             @align = is_arrayref($param{align})
83 713 100       1527 ? @{ $param{align} }
84             : ($param{align}) x int(@widths)
85 6         20 ;
86 13 100       57 }
87             else {
88             @align = ('l') x int(@widths);
89             }
90 700         2092  
91             $header = shift @rows if $param{header_row};
92              
93 713 100       1881 my $table = _top_border(\%param, \@widths, $char)
94             ._header_row(\%param, $header, \@widths, \@align, $char)
95 713         1821 ._header_rule(\%param, \@widths, $char, \@align)
96             ._body(\%param, \@rows, \@widths, \@align, $char)
97             ._bottom_border(\%param, \@widths, $char);
98             chop($table);
99              
100 713         2350 return $table;
101             }
102 713         6957  
103             {
104             my ($param, $widths, $char) = @_;
105              
106             return '' if $param->{top_and_tail};
107 713     713   1532 return _rule_row($param, $widths, $char->{TLC}, $char->{HR}, $char->{TT}, $char->{TRC});
108             }
109 713 100       2375  
110 309         951 {
111             my ($param, $widths, $char) = @_;
112              
113             return '' if $param->{top_and_tail};
114             return _rule_row($param, $widths, $char->{BLC}, $char->{HR}, $char->{BT}, $char->{BRC});
115 713     713   1650 }
116              
117 713 100       2224 {
118 309         951 my ($param, $widths, $le, $hr, $cross, $re) = @_;
119             my $pad = $param->{compact} ? '' : $hr;
120              
121             return $param->{indent}
122             .$le
123 1040     1040   2838 .join($cross, map { $pad.($hr x $_).$pad } @$widths)
124 1040 50       2243 .$re
125             ."\n"
126             ;
127             }
128 1040         2582  
  3717         12873  
129             {
130             my ($param, $row, $widths, $align, $char) = @_;
131             return '' unless $param->{header_row};
132              
133             return _text_row($param, $row, $widths, $align, $char);
134             }
135              
136 713     713   1651 my $rows = shift @_;
137 713 100       2293 for my $row ( @{$rows}) {
138             if ("@{$row}" =~ m/[^\\]\|/ ){
139 417         1030 die "Unescaped | will produce invalid Markdown!\n@{$row}";
140             }
141             }
142             }
143 403     403   719  
144 403         628 my ($param, $widthref, $alignref ) = @_;
  403         807  
145 2170 100       3013 my $coladj = $param->{'compact'} ? -2 : 0;
  2170         6198  
146 3         9 my @align = @{$alignref};
  3         40  
147             my @width = @{$widthref};
148             my $rule = '|';
149             while ( @width) {
150             my $colwidth = $coladj + shift( @width);
151             my $colalign = shift( @align);
152 7     7   1588 my $DASHES = '-' x ($colwidth ) ;
153 7 100       23 $rule .= ":$DASHES-|" if ( $colalign eq 'l') ;
154 7         37 $rule .= "-$DASHES:|" if ( $colalign eq 'r') ;
  7         21  
155 7         15 $rule .= ":$DASHES:|" if ( $colalign eq 'c') ;
  7         35  
156 7         16 }
157 7         20 return "$rule\n" ;
158 27         43 }
159 27         41  
160 27         52 {
161 27 100       100 my ($param, $widths, $char, $align) = @_;
162 27 100       61 if ( $param->{'style'} eq 'markdown' ) {
163 27 100       77 # the default unaligned markdown header_rule
164             # is similar to other styles. the aligned
165 7         36 # header_rule is unique.
166             return _md_header_rule($param, $widths, $align) if $param->{'align'};
167             }
168             return '' unless $param->{header_row};
169             my $fancy = $param->{separate_rows} ? 'F' : '';
170 713     713   1592  
171 713 100       1810 return _rule_row($param, $widths, $char->{"${fancy}LT"}, $char->{"${fancy}HR"}, $char->{"${fancy}HC"}, $char->{"${fancy}RT"});
172             }
173              
174             {
175 400 100       970 my ($param, $rows, $widths, $align, $char) = @_;
176             my $divider = $param->{separate_rows} ? _rule_row($param, $widths, $char->{LT}, $char->{HR}, $char->{HC}, $char->{RT}) : '';
177 709 100       2132  
178 413 100       1002 return join($divider, map { _text_row($param, $_, $widths, $align, $char) } @$rows);
179             }
180 413         1722  
181             {
182             my ($param, $row, $widths, $align, $char) = @_;
183             my @columns = @$row;
184             my $text = $param->{indent}.$char->{VR};
185 713     713   1545  
186 713 100       1631 for (my $i = 0; $i < @$widths; $i++) {
187             $text .= _format_column($columns[$i] // '', $widths->[$i], $align->[$i] // 'l', $param, $char);
188 713         1319 $text .= $char->{VR};
  10189         17206  
189             }
190             $text .= "\n";
191              
192             return $text;
193 10606     10606   17539 }
194 10606         20320  
195 10606         19607 {
196             my ($text, $width, $align, $param, $char) = @_;
197 10606         20910 my $pad = $param->{compact} ? '' : ' ';
198 47121   100     121464  
      50        
199 47121         597050 if ($align eq 'r' || $align eq 'right') {
200             return $pad.' ' x ($width - tty_width($text)).$text.$pad;
201 10606         14389 }
202             elsif ($align eq 'c' || $align eq 'center' || $align eq 'centre') {
203 10606         28938 my $total_spaces = $width - tty_width($text);
204             my $left_spaces = int($total_spaces / 2);
205             my $right_spaces = $left_spaces;
206             $right_spaces++ if $total_spaces % 2 == 1;
207             return $pad.(' ' x $left_spaces).$text.(' ' x $right_spaces).$pad;
208 47121     47121   80127 }
209 47121 100       77156 else {
210             return $pad.$text.' ' x ($width - tty_width($text)).$pad;
211 47121 100 100     214515 }
    100 100        
      66        
212 86         169 }
213              
214             {
215 29         57 my $rows = shift;
216 29         372 my @widths;
217 29         41 foreach my $row (@$rows) {
218 29 100       64 my @columns = @$row;
219 29         95 for (my $i = 0; $i < @columns; $i++) {
220             next unless defined($columns[$i]);
221              
222 47006         94841 my $width = tty_width($columns[$i]);
223              
224             $widths[$i] = $width if !defined($widths[$i])
225             || $width > $widths[$i];
226             }
227             }
228 716     716   1270 return @widths;
229 716         1058 }
230 716         1334  
231 10618         20826 # Back-compat: 'table' is an alias for 'generate_table', but isn't exported
232 10618         19780 *table = \&generate_table;
233 43867 100       74416  
234             1;
235 43820         74263  
236              
237 43820 100 100     594339 =pod
238              
239             =encoding utf8
240              
241 716         1852 =head1 NAME
242              
243             Vote::Count::TextTableTiny
244              
245             =head1 SYNOPSIS
246              
247             Don't use this module. It is a fork from a pending Pull Request, and will be withdrawn when the PR merges.
248              
249             =head1 REPOSITORY
250              
251             L<https://github.com/neilb/Text-Table-Tiny>
252              
253             =head1 AUTHOR
254              
255             Neil Bowers <neilb@cpan.org>
256              
257             The original version was written by Creighton Higgins <chiggins@chiggins.com>,
258             but the module was entirely rewritten for 0.05_01.
259              
260             =head1 COPYRIGHT AND LICENSE
261              
262             This software is copyright (c) 2020 by Neil Bowers.
263              
264             This is free software; you can redistribute it and/or modify it under
265             the same terms as the Perl 5 programming language system itself.
266              
267             =cut
268              
269             #FOOTER
270              
271             =pod
272              
273             BUG TRACKER
274              
275             L<https://github.com/brainbuz/Vote-Count/issues>
276              
277             AUTHOR
278              
279             John Karr (BRAINBUZ) brainbuz@cpan.org
280              
281             CONTRIBUTORS
282              
283             Copyright 2019-2021 by John Karr (BRAINBUZ) brainbuz@cpan.org.
284              
285             LICENSE
286              
287             This module is released under the GNU Public License Version 3. See license file for details. For more information on this license visit L<http://fsf.org>.
288              
289             SUPPORT
290              
291             This software is provided as is, per the terms of the GNU Public License. Professional support and customisation services are available from the author.
292              
293             =cut
294