File Coverage

lib/Text/ASCIITable/EasyTable.pm
Criterion Covered Total %
statement 80 114 70.1
branch 19 34 55.8
condition 9 16 56.2
subroutine 14 17 82.3
pod 1 5 20.0
total 123 186 66.1


line stmt bran cond sub pod time code
1             package Text::ASCIITable::EasyTable;
2              
3 1     1   799 use strict;
  1         2  
  1         28  
4 1     1   5 use warnings;
  1         1  
  1         24  
5              
6 1     1   645 use Data::Dumper;
  1         7076  
  1         65  
7 1     1   693 use JSON;
  1         8490  
  1         4  
8 1     1   143 use List::Util qw(pairs);
  1         2  
  1         97  
9 1     1   7 use Scalar::Util qw(reftype);
  1         1  
  1         95  
10 1     1   571 use Text::ASCIITable;
  1         7418  
  1         62  
11              
12 1     1   19 use parent qw(Exporter);
  1         2  
  1         11  
13              
14             our @EXPORT = qw(easy_table); ## no critic (ProhibitAutomaticExportation)
15              
16             our $VERSION = '1.004';
17              
18             ########################################################################
19             {
20             ## no critic (RequireArgUnpacking)
21              
22 8     8 0 13 sub is_array { push @_, 'ARRAY'; goto &_is_type; }
  8         21  
23 5     5 0 9 sub is_hash { push @_, 'HASH'; goto &_is_type; }
  5         11  
24 13   33 13   87 sub _is_type { return ref $_[0] && reftype( $_[0] ) eq $_[1]; }
25             }
26             ########################################################################
27              
28             ########################################################################
29             sub uncamel {
30             ########################################################################
31 0     0 0 0 my ($str) = @_;
32              
33 0         0 while ( $str =~ s/^(.)(.*?)([[:upper:]])/\l$1$2_\l$3/xsmg ) { }
34              
35 0         0 return $str;
36             }
37              
38             ########################################################################
39             sub wordify {
40             ########################################################################
41 0     0 0 0 my ($str) = @_;
42              
43 0         0 $str = uncamel($str);
44              
45 0         0 $str =~ s/_(.)/ \u$1/xsmg;
46              
47 0         0 return ucfirst $str;
48             }
49              
50             ########################################################################
51             sub easy_table {
52             ########################################################################
53 5     5 1 27846 my (%options) = @_;
54              
55             die "'data' must be ARRAY\n"
56 5 50       11 if !is_array $options{data};
57              
58 5         6 my @columns;
59              
60 5 50 33     19 if ( $options{columns} && !$options{index} ) {
    100          
    50          
61             die "'columns' must be an ARRAY\n"
62 0 0       0 if !is_array $options{columns};
63              
64 0         0 @columns = @{ $options{columns} };
  0         0  
65             }
66             elsif ( $options{rows} ) {
67             die "'rows' must be ARRAY\n"
68 3 50       7 if !is_array $options{rows};
69              
70             die "'rows' must be key/value pairs\n"
71 3 50       4 if @{ $options{rows} } % 2;
  3         16  
72              
73 3         13 @columns = map { $_->[0] } pairs @{ $options{rows} };
  6         19  
  3         22  
74             }
75             elsif ( $options{index} ) {
76              
77 0         0 @columns = map { $_->[0] } pairs @{ $options{index} };
  0         0  
  0         0  
78              
79 0         0 my %index = @{ $options{index} };
  0         0  
80              
81             $options{rows} = [
82             map {
83 0     0   0 ( $_ => sub { return shift->{ $index{ shift() } } } )
  0         0  
84 0         0 } @columns
85             ];
86             }
87             else {
88 2         15 @columns = keys %{ $options{data}->[0] };
  2         8  
89             }
90              
91 5         16 $options{columns} = \@columns;
92              
93 5         17 my $data = _render_data( %options, columns => \@columns, );
94              
95             return _render_table( %options, data => $data )
96 5 50       19 if !$options{json};
97              
98             # return an array of hashes
99 0         0 my @json_data;
100              
101 0         0 foreach my $row ( @{$data} ) {
  0         0  
102 0         0 my %hashed_row = map { $_ => shift @{$row} } @columns;
  0         0  
  0         0  
103 0         0 push @json_data, \%hashed_row;
104             }
105              
106 0         0 return JSON->new->pretty->encode( \@json_data );
107             }
108              
109             ########################################################################
110             sub _render_table {
111             ########################################################################
112 5     5   13 my (%options) = @_;
113              
114             # build a table...
115 5         13 my $table_options = $options{table_options};
116 5   100     20 $table_options //= {};
117              
118 5 50       11 die "'table_options' must be HASH\n"
119             if !is_hash $table_options;
120              
121 5   100     22 $table_options->{headingText} //= 'Table';
122              
123 5         24 my $t = Text::ASCIITable->new($table_options);
124              
125 5         111 my @columns = @{ $options{columns} };
  5         12  
126              
127 5 50       10 if ( $options{fix_headings} ) {
128 0         0 @columns = map { wordify $_ } @columns;
  0         0  
129             }
130              
131 5         14 $t->setCols(@columns);
132              
133 5         281 for ( @{ $options{data} } ) {
  5         9  
134 15         828 $t->addRow( @{$_} );
  15         83  
135             }
136              
137 5         401 return $t;
138             }
139              
140             ########################################################################
141             sub _render_data {
142             ########################################################################
143 5     5   14 my (%options) = @_;
144              
145             my ( $data, $rows, $columns, $sort_key )
146 5         12 = @options{qw(data rows columns sort_key)};
147              
148 5         5 my @sorted_data;
149              
150 5 50       8 if ($sort_key) {
151 0 0       0 if ( reftype($sort_key) eq 'CODE' ) {
152 0         0 @sorted_data = $sort_key->( @{$data} );
  0         0  
153             }
154             else {
155             @sorted_data
156 0         0 = sort { lc $a->{$sort_key} cmp lc $b->{$sort_key} } @{$data};
  0         0  
  0         0  
157             }
158             }
159             else {
160 5         6 @sorted_data = @{$data};
  5         10  
161             }
162              
163 5 100       9 my %row_lu = $rows ? @{$rows} : ();
  3         17  
164              
165 5         18 my @rendered_data;
166              
167 5         6 my $row_count = 0;
168              
169 5         6 for my $row ( @{$data} ) {
  5         9  
170             last
171 15 50 33     49 if defined $options{max_rows} && ++$row_count > $options{max_rows};
172              
173 15 100       19 if ($rows) {
174             push @rendered_data, [
175             map {
176             ref $row_lu{$_}
177             && reftype( $row_lu{$_} ) eq 'CODE' ? $row_lu{$_}->( $row, $_ )
178             : $row_lu{$_} ? $row->{ $row_lu{$_} }
179 18 50 66     107 : $row->{$_}
    100          
180 9         10 } @{$columns},
  9         13  
181             ];
182             }
183             else {
184 6         7 push @rendered_data, [ @{$row}{ @{$columns} } ];
  6         13  
  6         8  
185             }
186             }
187              
188 5         21 return \@rendered_data;
189             }
190              
191             1;
192              
193             ## no critic (RequirePodSections)
194              
195             __END__