line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Data::Format::Pretty::Console; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $DATE = '2017-07-10'; # DATE |
4
|
|
|
|
|
|
|
our $VERSION = '0.38'; # VERSION |
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
117919
|
use 5.010001; |
|
1
|
|
|
|
|
5
|
|
7
|
1
|
|
|
1
|
|
9
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
33
|
|
8
|
1
|
|
|
1
|
|
9
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
41
|
|
9
|
1
|
|
|
1
|
|
8
|
use experimental 'smartmatch'; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
8
|
|
10
|
1
|
|
|
1
|
|
5167
|
use Log::ger; |
|
1
|
|
|
|
|
128
|
|
|
1
|
|
|
|
|
7
|
|
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
1951
|
use Scalar::Util qw(blessed); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
74
|
|
13
|
1
|
|
|
1
|
|
859
|
use Text::ANSITable; |
|
1
|
|
|
|
|
100571
|
|
|
1
|
|
|
|
|
36
|
|
14
|
1
|
|
|
1
|
|
381
|
use YAML::Any; |
|
1
|
|
|
|
|
904
|
|
|
1
|
|
|
|
|
5
|
|
15
|
1
|
|
|
1
|
|
3599
|
use JSON::MaybeXS; |
|
1
|
|
|
|
|
5513
|
|
|
1
|
|
|
|
|
2517
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my $json = JSON::MaybeXS->new->allow_nonref; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
require Exporter; |
20
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
21
|
|
|
|
|
|
|
our @EXPORT_OK = qw(format_pretty); |
22
|
|
|
|
|
|
|
|
23
|
0
|
|
|
0
|
0
|
0
|
sub content_type { "text/plain" } |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub format_pretty { |
26
|
23
|
|
|
23
|
1
|
40849
|
my ($data, $opts) = @_; |
27
|
23
|
|
50
|
|
|
139
|
$opts //= {}; |
28
|
23
|
|
|
|
|
118
|
__PACKAGE__->new($opts)->_format($data); |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# OO interface is nto documented, we use it just to subclass |
32
|
|
|
|
|
|
|
# Data::Format::Pretty::HTML |
33
|
|
|
|
|
|
|
sub new { |
34
|
44
|
|
|
44
|
0
|
115504
|
my ($class, $opts) = @_; |
35
|
44
|
|
100
|
|
|
253
|
$opts //= {}; |
36
|
44
|
|
33
|
|
|
412
|
$opts->{interactive} //= $ENV{INTERACTIVE} // (-t STDOUT); |
|
|
|
66
|
|
|
|
|
37
|
|
|
|
|
|
|
$opts->{table_column_orders} //= $json->decode( |
38
|
|
|
|
|
|
|
$ENV{FORMAT_PRETTY_TABLE_COLUMN_ORDERS}) |
39
|
44
|
50
|
0
|
|
|
179
|
if defined($ENV{FORMAT_PRETTY_TABLE_COLUMN_ORDERS}); |
40
|
|
|
|
|
|
|
$opts->{table_column_formats} //= $json->decode( |
41
|
|
|
|
|
|
|
$ENV{FORMAT_PRETTY_TABLE_COLUMN_FORMATS}) |
42
|
44
|
50
|
0
|
|
|
159
|
if defined($ENV{FORMAT_PRETTY_TABLE_COLUMN_FORMATS}); |
43
|
|
|
|
|
|
|
$opts->{table_column_types} //= $json->decode( |
44
|
|
|
|
|
|
|
$ENV{FORMAT_PRETTY_TABLE_COLUMN_TYPES}) |
45
|
44
|
50
|
0
|
|
|
189
|
if defined($ENV{FORMAT_PRETTY_TABLE_COLUMN_TYPES}); |
46
|
44
|
|
33
|
|
|
321
|
$opts->{list_max_columns} //= $ENV{FORMAT_PRETTY_LIST_MAX_COLUMNS}; |
47
|
44
|
|
|
|
|
270
|
bless {opts=>$opts}, $class; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub _is_cell_or_format_cell { |
51
|
147
|
|
|
147
|
|
415
|
my ($self, $data, $is_format) = @_; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# XXX currently hardcoded limits |
54
|
147
|
|
|
|
|
329
|
my $maxlen = 1000; |
55
|
|
|
|
|
|
|
|
56
|
147
|
100
|
66
|
|
|
633
|
if (!ref($data) || blessed($data)) { |
|
|
100
|
|
|
|
|
|
57
|
135
|
100
|
|
|
|
412
|
if (!defined($data)) { |
58
|
8
|
50
|
|
|
|
70
|
return "" if $is_format; |
59
|
0
|
|
|
|
|
0
|
return 1; |
60
|
|
|
|
|
|
|
} |
61
|
127
|
50
|
|
|
|
398
|
if (length($data) > $maxlen) { |
62
|
0
|
|
|
|
|
0
|
return; |
63
|
|
|
|
|
|
|
} |
64
|
127
|
100
|
|
|
|
505
|
return "$data" if $is_format; |
65
|
85
|
|
|
|
|
360
|
return 1; |
66
|
|
|
|
|
|
|
} elsif (ref($data) eq 'ARRAY') { |
67
|
9
|
50
|
|
|
|
28
|
if (grep {ref($_) && !blessed($_)} @$data) { |
|
21
|
50
|
|
|
|
94
|
|
68
|
0
|
|
|
|
|
0
|
return; |
69
|
|
|
|
|
|
|
} |
70
|
9
|
50
|
|
|
|
26
|
my $s = join(", ", map {defined($_) ? "$_":""} @$data); |
|
21
|
|
|
|
|
87
|
|
71
|
9
|
50
|
|
|
|
35
|
if (length($s) > $maxlen) { |
72
|
0
|
|
|
|
|
0
|
return; |
73
|
|
|
|
|
|
|
} |
74
|
9
|
100
|
|
|
|
39
|
return $s if $is_format; |
75
|
6
|
|
|
|
|
29
|
return 1; |
76
|
|
|
|
|
|
|
} else { |
77
|
3
|
|
|
|
|
16
|
return; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# return a string when data can be represented as a cell, otherwise undef. what |
82
|
|
|
|
|
|
|
# can be put in a table cell? a string (or stringified object) or array of |
83
|
|
|
|
|
|
|
# strings (stringified objects) that is quite "short". |
84
|
53
|
|
|
53
|
|
165
|
sub _format_cell { _is_cell_or_format_cell(@_, 1) } |
85
|
|
|
|
|
|
|
|
86
|
94
|
|
|
94
|
|
289
|
sub _is_cell { _is_cell_or_format_cell(@_, 0) } |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub _detect_struct { |
89
|
72
|
|
|
72
|
|
300
|
my ($self, $data) = @_; |
90
|
72
|
|
|
|
|
162
|
my $struct; |
91
|
72
|
|
|
|
|
178
|
my $struct_meta = {}; |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# XXX perhaps, use Data::Schema later? |
94
|
|
|
|
|
|
|
CHECK_FORMAT: |
95
|
|
|
|
|
|
|
{ |
96
|
72
|
|
|
|
|
173
|
CHECK_SCALAR: |
97
|
|
|
|
|
|
|
{ |
98
|
72
|
100
|
100
|
|
|
148
|
if (!ref($data) || blessed($data)) { |
|
72
|
|
|
|
|
485
|
|
99
|
27
|
|
|
|
|
70
|
$struct = "scalar"; |
100
|
27
|
|
|
|
|
78
|
last CHECK_FORMAT; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
CHECK_AOA: |
105
|
|
|
|
|
|
|
{ |
106
|
45
|
100
|
|
|
|
123
|
if (ref($data) eq 'ARRAY') { |
|
45
|
|
|
|
|
185
|
|
107
|
24
|
|
|
|
|
62
|
my $numcols; |
108
|
24
|
|
|
|
|
79
|
for my $row (@$data) { |
109
|
27
|
100
|
|
|
|
129
|
last CHECK_AOA unless ref($row) eq 'ARRAY'; |
110
|
10
|
100
|
100
|
|
|
58
|
last CHECK_AOA if defined($numcols) && $numcols != @$row; |
111
|
8
|
50
|
|
|
|
25
|
last CHECK_AOA if grep { !$self->_is_cell($_) } @$row; |
|
18
|
|
|
|
|
56
|
|
112
|
8
|
|
|
|
|
27
|
$numcols = @$row; |
113
|
|
|
|
|
|
|
} |
114
|
5
|
|
|
|
|
15
|
$struct = "aoa"; |
115
|
5
|
|
|
|
|
16
|
last CHECK_FORMAT; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
CHECK_AOH: |
120
|
|
|
|
|
|
|
{ |
121
|
40
|
100
|
|
|
|
96
|
if (ref($data) eq 'ARRAY') { |
|
40
|
|
|
|
|
149
|
|
122
|
19
|
|
|
|
|
74
|
$struct_meta->{columns} = {}; |
123
|
19
|
|
|
|
|
62
|
for my $row (@$data) { |
124
|
27
|
100
|
|
|
|
101
|
last CHECK_AOH unless ref($row) eq 'HASH'; |
125
|
20
|
|
|
|
|
94
|
for my $k (keys %$row) { |
126
|
47
|
50
|
|
|
|
168
|
last CHECK_AOH if !$self->_is_cell($row->{$k}); |
127
|
47
|
|
|
|
|
179
|
$struct_meta->{columns}{$k} = 1; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
} |
130
|
12
|
|
|
|
|
38
|
$struct = "aoh"; |
131
|
12
|
|
|
|
|
37
|
last CHECK_FORMAT; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# list of scalars/cells |
136
|
|
|
|
|
|
|
CHECK_LIST: |
137
|
|
|
|
|
|
|
{ |
138
|
28
|
100
|
|
|
|
62
|
if (ref($data) eq 'ARRAY') { |
|
28
|
|
|
|
|
97
|
|
139
|
7
|
|
|
|
|
23
|
for (@$data) { |
140
|
16
|
50
|
|
|
|
53
|
last CHECK_LIST unless $self->_is_cell($_); |
141
|
|
|
|
|
|
|
} |
142
|
7
|
|
|
|
|
18
|
$struct = "list"; |
143
|
7
|
|
|
|
|
20
|
last CHECK_FORMAT; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# hash which contains at least one "table" (list/aoa/aoh) |
148
|
|
|
|
|
|
|
CHECK_HOT: |
149
|
|
|
|
|
|
|
{ |
150
|
21
|
50
|
|
|
|
47
|
last CHECK_HOT if $self->{opts}{skip_hot}; |
|
21
|
|
|
|
|
78
|
|
151
|
21
|
50
|
|
|
|
73
|
last CHECK_HOT unless ref($data) eq 'HASH'; |
152
|
21
|
|
|
|
|
47
|
my $has_t; |
153
|
21
|
|
|
|
|
105
|
while (my ($k, $v) = each %$data) { |
154
|
24
|
|
|
|
|
124
|
my ($s2, $sm2) = $self->_detect_struct($v, {skip_hot=>1}); |
155
|
24
|
50
|
|
|
|
97
|
last CHECK_HOT unless $s2; |
156
|
24
|
100
|
|
|
|
200
|
$has_t = 1 if $s2 =~ /^(?:list|aoa|aoh|hash)$/; |
157
|
|
|
|
|
|
|
} |
158
|
21
|
100
|
|
|
|
74
|
last CHECK_HOT unless $has_t; |
159
|
7
|
|
|
|
|
19
|
$struct = "hot"; |
160
|
7
|
|
|
|
|
16
|
last CHECK_FORMAT; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# hash of scalars/cells |
164
|
|
|
|
|
|
|
CHECK_HASH: |
165
|
|
|
|
|
|
|
{ |
166
|
14
|
50
|
|
|
|
33
|
if (ref($data) eq 'HASH') { |
|
14
|
|
|
|
|
55
|
|
167
|
14
|
|
|
|
|
46
|
for (values %$data) { |
168
|
13
|
100
|
|
|
|
49
|
last CHECK_HASH unless $self->_is_cell($_); |
169
|
|
|
|
|
|
|
} |
170
|
11
|
|
|
|
|
29
|
$struct = "hash"; |
171
|
11
|
|
|
|
|
33
|
last CHECK_FORMAT; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
72
|
|
|
|
|
293
|
($struct, $struct_meta); |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# t (table) is a structure like this: {cols=>["colName1", "colName2", ...]}, |
181
|
|
|
|
|
|
|
# rows=>[ [row1.1, row1.2, ...], [row2.1, row2.2, ...], ... ], at_opts=>{...}, |
182
|
|
|
|
|
|
|
# col_widths=>{colName1=>5, ...}}. the job of this routine is to render it |
183
|
|
|
|
|
|
|
# (currently uses Text::ANSITable). |
184
|
|
|
|
|
|
|
sub _render_table { |
185
|
12
|
|
|
12
|
|
47
|
my ($self, $t) = @_; |
186
|
|
|
|
|
|
|
|
187
|
12
|
|
|
|
|
35
|
my $colfmts; |
188
|
12
|
|
|
|
|
41
|
my $tcff = $self->{opts}{table_column_formats}; |
189
|
12
|
100
|
|
|
|
52
|
if ($tcff) { |
190
|
2
|
|
|
|
|
10
|
for my $tcf (@$tcff) { |
191
|
2
|
|
|
|
|
7
|
my $match = 1; |
192
|
2
|
|
|
|
|
7
|
my @tcols = @{ $t->{cols} }; |
|
2
|
|
|
|
|
11
|
|
193
|
2
|
|
|
|
|
14
|
for my $scol (keys %$tcf) { |
194
|
3
|
50
|
|
|
|
19
|
do { $match = 0; last } unless $scol ~~ @tcols; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
195
|
|
|
|
|
|
|
} |
196
|
2
|
50
|
|
|
|
11
|
if ($match) { |
197
|
2
|
|
|
|
|
4
|
$colfmts = $tcf; |
198
|
2
|
|
|
|
|
8
|
last; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
12
|
|
|
|
|
30
|
my $coltypes; |
204
|
12
|
|
|
|
|
35
|
my $tctt = $self->{opts}{table_column_types}; |
205
|
12
|
50
|
|
|
|
46
|
if ($tctt) { |
206
|
0
|
|
|
|
|
0
|
for my $tct (@$tctt) { |
207
|
0
|
|
|
|
|
0
|
my $match = 1; |
208
|
0
|
|
|
|
|
0
|
my @tcols = @{ $t->{cols} }; |
|
0
|
|
|
|
|
0
|
|
209
|
0
|
|
|
|
|
0
|
for my $scol (keys %$tct) { |
210
|
0
|
0
|
|
|
|
0
|
do { $match = 0; last } unless $scol ~~ @tcols; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
211
|
|
|
|
|
|
|
} |
212
|
0
|
0
|
|
|
|
0
|
if ($match) { |
213
|
0
|
|
|
|
|
0
|
$coltypes = $tct; |
214
|
0
|
|
|
|
|
0
|
last; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# render using Text::ANSITable |
220
|
12
|
|
|
|
|
408
|
my $at = Text::ANSITable->new; |
221
|
12
|
|
|
|
|
126824
|
$at->columns($t->{cols}); |
222
|
12
|
|
|
|
|
525
|
$at->rows($t->{rows}); |
223
|
12
|
100
|
|
|
|
360
|
if ($t->{at_opts}) { |
224
|
7
|
|
|
|
|
22
|
$at->{$_} = $t->{at_opts}{$_} for keys %{ $t->{at_opts} }; |
|
7
|
|
|
|
|
42
|
|
225
|
|
|
|
|
|
|
} |
226
|
12
|
100
|
|
|
|
58
|
if ($colfmts) { |
227
|
|
|
|
|
|
|
$at->set_column_style($_ => formats => $colfmts->{$_}) |
228
|
2
|
|
|
|
|
26
|
for keys %$colfmts; |
229
|
|
|
|
|
|
|
} |
230
|
12
|
50
|
|
|
|
212
|
if ($coltypes) { |
231
|
|
|
|
|
|
|
$at->set_column_style($_ => type => $coltypes->{$_}) |
232
|
0
|
|
|
|
|
0
|
for keys %$coltypes; |
233
|
|
|
|
|
|
|
} |
234
|
12
|
50
|
|
|
|
57
|
if ($t->{col_widths}) { |
235
|
|
|
|
|
|
|
$at->set_column_style($_ => width => $t->{col_widths}{$_}) |
236
|
0
|
|
|
|
|
0
|
for keys %{ $t->{col_widths} }; |
|
0
|
|
|
|
|
0
|
|
237
|
|
|
|
|
|
|
} |
238
|
12
|
|
|
|
|
76
|
$at->draw; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# format unknown structure, the default is to dump YAML structure |
242
|
|
|
|
|
|
|
sub _format_unknown { |
243
|
2
|
|
|
2
|
|
6
|
my ($self, $data) = @_; |
244
|
2
|
|
|
|
|
15
|
Dump($data); |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
sub _format_scalar { |
248
|
8
|
|
|
8
|
|
36
|
my ($self, $data) = @_; |
249
|
|
|
|
|
|
|
|
250
|
8
|
100
|
|
|
|
29
|
my $sdata = defined($data) ? "$data" : ""; |
251
|
8
|
100
|
|
|
|
34
|
return "" if !length($sdata); |
252
|
6
|
100
|
|
|
|
51
|
return $sdata =~ /\n\z/s ? $sdata : "$sdata\n"; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub _format_list { |
256
|
3
|
|
|
3
|
|
12
|
my ($self, $data) = @_; |
257
|
3
|
50
|
|
|
|
16
|
if ($self->{opts}{interactive}) { |
258
|
|
|
|
|
|
|
|
259
|
3
|
|
|
|
|
33
|
require List::Util; |
260
|
3
|
|
|
|
|
791
|
require POSIX; |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# format list as as columns (a la 'ls' output) |
263
|
|
|
|
|
|
|
|
264
|
3
|
|
|
|
|
7525
|
my @rows = map { $self->_format_cell($_) } @$data; |
|
7
|
|
|
|
|
28
|
|
265
|
|
|
|
|
|
|
|
266
|
3
|
|
50
|
|
|
13
|
my $maxwidth = List::Util::max(map { length } @rows) // 0; |
|
7
|
|
|
|
|
33
|
|
267
|
3
|
|
|
|
|
10
|
my ($termcols, $termrows); |
268
|
3
|
50
|
|
|
|
17
|
if ($ENV{COLUMNS}) { |
|
|
50
|
|
|
|
|
|
269
|
0
|
|
|
|
|
0
|
$termcols = $ENV{COLUMNS}; |
270
|
3
|
|
|
|
|
601
|
} elsif (eval { require Term::Size; 1 }) { |
|
3
|
|
|
|
|
801
|
|
271
|
3
|
|
|
|
|
60
|
($termcols, $termrows) = Term::Size::chars(); |
272
|
|
|
|
|
|
|
} else { |
273
|
|
|
|
|
|
|
# sane default, on windows we need to offset by 1 because printing |
274
|
|
|
|
|
|
|
# at the rightmost column will cause cursor to move down one line. |
275
|
0
|
0
|
|
|
|
0
|
$termcols = $^O =~ /Win/ ? 79 : 80; |
276
|
|
|
|
|
|
|
} |
277
|
3
|
|
|
|
|
11
|
my $numcols = 1; |
278
|
3
|
50
|
|
|
|
14
|
if ($maxwidth) { |
279
|
|
|
|
|
|
|
# | some-text-some | some-text-some... | |
280
|
|
|
|
|
|
|
# 2/\__maxwidth__/\3/\__maxwidth__/...\2 |
281
|
|
|
|
|
|
|
# |
282
|
|
|
|
|
|
|
# table width = (2+maxwidth) + (3+maxwidth)*(numcols-1) + 2 |
283
|
|
|
|
|
|
|
# |
284
|
|
|
|
|
|
|
# so with a bit of algrebra, solve for numcols: |
285
|
3
|
|
|
|
|
17
|
$numcols = int( (($termcols-1)-$maxwidth-6)/(3+$maxwidth) + 1 ); |
286
|
3
|
50
|
|
|
|
14
|
$numcols = @rows if $numcols > @rows; |
287
|
3
|
50
|
|
|
|
16
|
$numcols = 1 if $numcols < 1; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
$numcols = $self->{opts}{list_max_columns} |
290
|
|
|
|
|
|
|
if defined($self->{opts}{list_max_columns}) && |
291
|
3
|
50
|
33
|
|
|
31
|
$numcols > $self->{opts}{list_max_columns}; |
292
|
3
|
|
|
|
|
26
|
my $numrows = POSIX::ceil(@rows/$numcols); |
293
|
3
|
50
|
|
|
|
13
|
if ($numrows) { |
294
|
|
|
|
|
|
|
# reduce number of columns to avoid empty columns |
295
|
3
|
|
|
|
|
15
|
$numcols = POSIX::ceil(@rows/$numrows); |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
#say "D: $numcols x $numrows"; |
298
|
|
|
|
|
|
|
|
299
|
3
|
|
|
|
|
22
|
my $t = {rows=>[], at_opts=>{show_header=>0}}; |
300
|
3
|
|
|
|
|
13
|
$t->{cols} = [map { "c$_" } 1..$numcols]; |
|
3
|
|
|
|
|
22
|
|
301
|
3
|
50
|
|
|
|
15
|
if ($numcols > 1) { |
302
|
0
|
|
|
|
|
0
|
$t->{col_widths}{"c$_"} = $maxwidth for 1..$numcols; |
303
|
|
|
|
|
|
|
} |
304
|
3
|
|
|
|
|
14
|
for my $r (1..$numrows) { |
305
|
7
|
|
|
|
|
16
|
my @trow; |
306
|
7
|
|
|
|
|
21
|
for my $c (1..$numcols) { |
307
|
7
|
|
|
|
|
20
|
my $idx = ($c-1)*$numrows + ($r-1); |
308
|
7
|
50
|
|
|
|
37
|
push @trow, $idx < @rows ? $rows[$idx] : ''; |
309
|
|
|
|
|
|
|
} |
310
|
7
|
|
|
|
|
17
|
push @{$t->{rows}}, \@trow; |
|
7
|
|
|
|
|
26
|
|
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
3
|
|
|
|
|
17
|
return $self->_render_table($t); |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
} else { |
316
|
0
|
|
|
|
|
0
|
my @rows; |
317
|
0
|
|
|
|
|
0
|
for my $row (@$data) { |
318
|
0
|
|
0
|
|
|
0
|
push @rows, ($row // "") . "\n"; |
319
|
|
|
|
|
|
|
} |
320
|
0
|
|
|
|
|
0
|
return join("", @rows); |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
sub _format_hash { |
325
|
3
|
|
|
3
|
|
13
|
my ($self, $data) = @_; |
326
|
|
|
|
|
|
|
# format hash as two-column table |
327
|
3
|
50
|
|
|
|
14
|
if ($self->{opts}{interactive}) { |
328
|
3
|
|
|
|
|
25
|
my $t = {cols=>[qw/key value/], rows=>[], |
329
|
|
|
|
|
|
|
at_opts=>{}}; |
330
|
3
|
|
|
|
|
18
|
for my $k (sort keys %$data) { |
331
|
4
|
|
|
|
|
10
|
push @{ $t->{rows} }, [$k, $self->_format_cell($data->{$k})]; |
|
4
|
|
|
|
|
22
|
|
332
|
|
|
|
|
|
|
} |
333
|
3
|
|
|
|
|
15
|
return $self->_render_table($t); |
334
|
|
|
|
|
|
|
} else { |
335
|
0
|
|
|
|
|
0
|
my @t; |
336
|
0
|
|
|
|
|
0
|
for my $k (sort keys %$data) { |
337
|
0
|
|
0
|
|
|
0
|
push @t, $k, "\t", ($data->{$k} // ""), "\n"; |
338
|
|
|
|
|
|
|
} |
339
|
0
|
|
|
|
|
0
|
return join("", @t); |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
sub _format_aoa { |
344
|
3
|
|
|
3
|
|
11
|
my ($self, $data) = @_; |
345
|
|
|
|
|
|
|
# show aoa as table |
346
|
3
|
100
|
|
|
|
22
|
if ($self->{opts}{interactive}) { |
347
|
2
|
100
|
|
|
|
8
|
if (@$data) { |
348
|
1
|
|
|
|
|
7
|
my $t = {rows=>[], at_opts=>{}}; |
349
|
1
|
|
|
|
|
4
|
$t->{cols} = [map { "column$_" } 0..@{ $data->[0] }-1]; |
|
2
|
|
|
|
|
11
|
|
|
1
|
|
|
|
|
5
|
|
350
|
1
|
|
|
|
|
6
|
for my $i (0..@$data-1) { |
351
|
2
|
|
|
|
|
7
|
push @{ $t->{rows} }, |
352
|
2
|
|
|
|
|
5
|
[map {$self->_format_cell($_)} @{ $data->[$i] }]; |
|
4
|
|
|
|
|
14
|
|
|
2
|
|
|
|
|
6
|
|
353
|
|
|
|
|
|
|
} |
354
|
1
|
|
|
|
|
6
|
return $self->_render_table($t); |
355
|
|
|
|
|
|
|
} else { |
356
|
1
|
|
|
|
|
5
|
return ""; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
} else { |
359
|
|
|
|
|
|
|
# tab-separated |
360
|
1
|
|
|
|
|
4
|
my @t; |
361
|
1
|
|
|
|
|
4
|
for my $row (@$data) { |
362
|
2
|
|
|
|
|
7
|
push @t, join("\t", map { $self->_format_cell($_) } @$row) . |
|
4
|
|
|
|
|
15
|
|
363
|
|
|
|
|
|
|
"\n"; |
364
|
|
|
|
|
|
|
} |
365
|
1
|
|
|
|
|
8
|
return join("", @t); |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
sub _format_aoh { |
370
|
6
|
|
|
6
|
|
22
|
my ($self, $data, $struct_meta) = @_; |
371
|
|
|
|
|
|
|
# show aoh as table |
372
|
6
|
|
|
|
|
16
|
my @cols = @{ $self->_order_table_columns( |
373
|
6
|
|
|
|
|
17
|
[keys %{$struct_meta->{columns}}]) }; |
|
6
|
|
|
|
|
57
|
|
374
|
6
|
100
|
|
|
|
36
|
if ($self->{opts}{interactive}) { |
375
|
5
|
|
|
|
|
34
|
my $t = {cols=>\@cols, rows=>[]}; |
376
|
5
|
|
|
|
|
28
|
for my $i (0..@$data-1) { |
377
|
8
|
|
|
|
|
25
|
my $row = $data->[$i]; |
378
|
8
|
|
|
|
|
19
|
push @{ $t->{rows} }, [map {$self->_format_cell($row->{$_})} @cols]; |
|
8
|
|
|
|
|
31
|
|
|
25
|
|
|
|
|
94
|
|
379
|
|
|
|
|
|
|
} |
380
|
5
|
|
|
|
|
28
|
return $self->_render_table($t); |
381
|
|
|
|
|
|
|
} else { |
382
|
|
|
|
|
|
|
# tab-separated |
383
|
1
|
|
|
|
|
4
|
my @t; |
384
|
1
|
|
|
|
|
4
|
for my $row (@$data) { |
385
|
3
|
|
|
|
|
9
|
my @row = map {$self->_format_cell($row->{$_})} @cols; |
|
9
|
|
|
|
|
33
|
|
386
|
3
|
|
|
|
|
19
|
push @t, join("\t", @row) . "\n"; |
387
|
|
|
|
|
|
|
} |
388
|
1
|
|
|
|
|
10
|
return join("", @t); |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub _format_hot { |
393
|
2
|
|
|
2
|
|
8
|
my ($self, $data) = @_; |
394
|
|
|
|
|
|
|
# show hot as paragraphs: |
395
|
|
|
|
|
|
|
# |
396
|
|
|
|
|
|
|
# key: |
397
|
|
|
|
|
|
|
# value (table) |
398
|
|
|
|
|
|
|
# |
399
|
|
|
|
|
|
|
# key2: |
400
|
|
|
|
|
|
|
# value ... |
401
|
2
|
|
|
|
|
6
|
my @t; |
402
|
2
|
|
|
|
|
11
|
for my $k (sort keys %$data) { |
403
|
4
|
|
|
|
|
4704
|
push @t, "$k:\n", $self->_format($data->{$k}), "\n"; |
404
|
|
|
|
|
|
|
} |
405
|
2
|
|
|
|
|
7808
|
return join("", @t); |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub _format { |
409
|
27
|
|
|
27
|
|
90
|
my ($self, $data) = @_; |
410
|
|
|
|
|
|
|
|
411
|
27
|
|
|
|
|
105
|
my ($struct, $struct_meta) = $self->_detect_struct($data); |
412
|
|
|
|
|
|
|
|
413
|
27
|
100
|
|
|
|
211
|
if (!$struct) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
414
|
2
|
|
|
|
|
9
|
return $self->_format_unknown($data, $struct_meta); |
415
|
|
|
|
|
|
|
} elsif ($struct eq 'scalar') { |
416
|
8
|
|
|
|
|
30
|
return $self->_format_scalar($data, $struct_meta); |
417
|
|
|
|
|
|
|
} elsif ($struct eq 'list') { |
418
|
3
|
|
|
|
|
19
|
return $self->_format_list($data, $struct_meta); |
419
|
|
|
|
|
|
|
} elsif ($struct eq 'hash') { |
420
|
3
|
|
|
|
|
15
|
return $self->_format_hash($data, $struct_meta); |
421
|
|
|
|
|
|
|
} elsif ($struct eq 'aoa') { |
422
|
3
|
|
|
|
|
13
|
return $self->_format_aoa($data, $struct_meta); |
423
|
|
|
|
|
|
|
} elsif ($struct eq 'aoh') { |
424
|
6
|
|
|
|
|
38
|
return $self->_format_aoh($data, $struct_meta); |
425
|
|
|
|
|
|
|
} elsif ($struct eq 'hot') { |
426
|
2
|
|
|
|
|
11
|
return $self->_format_hot($data, $struct_meta); |
427
|
|
|
|
|
|
|
} else { |
428
|
0
|
|
|
|
|
0
|
die "BUG: Unknown format `$struct`"; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
sub _order_table_columns { |
433
|
|
|
|
|
|
|
#$log->tracef('=> _order_table_columns(%s)', \@_); |
434
|
6
|
|
|
6
|
|
22
|
my ($self, $cols) = @_; |
435
|
|
|
|
|
|
|
|
436
|
6
|
|
|
|
|
19
|
my $found; # whether we found an ordering in table_column_orders |
437
|
6
|
|
|
|
|
22
|
my $tco = $self->{opts}{table_column_orders}; |
438
|
6
|
|
|
|
|
21
|
my %orders; # colname => idx |
439
|
6
|
100
|
|
|
|
33
|
if ($tco) { |
440
|
2
|
50
|
|
|
|
13
|
die "table_column_orders should be an arrayref" |
441
|
|
|
|
|
|
|
unless ref($tco) eq 'ARRAY'; |
442
|
|
|
|
|
|
|
CO: |
443
|
2
|
|
|
|
|
8
|
for my $co (@$tco) { |
444
|
2
|
50
|
|
|
|
12
|
die "table_column_orders elements must all be arrayrefs" |
445
|
|
|
|
|
|
|
unless ref($co) eq 'ARRAY'; |
446
|
2
|
|
|
|
|
10
|
for (@$co) { |
447
|
7
|
100
|
|
|
|
39
|
next CO unless $_ ~~ @$cols; |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
|
450
|
1
|
|
|
|
|
4
|
$found++; |
451
|
1
|
|
|
|
|
6
|
for (my $i=0; $i<@$co; $i++) { |
452
|
3
|
|
|
|
|
14
|
$orders{$co->[$i]} = $i; |
453
|
|
|
|
|
|
|
} |
454
|
1
|
|
|
|
|
3
|
$found++; |
455
|
1
|
|
|
|
|
4
|
last CO; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
6
|
|
|
|
|
17
|
my @ocols; |
460
|
6
|
100
|
|
|
|
24
|
if ($found) { |
461
|
|
|
|
|
|
|
@ocols = sort { |
462
|
1
|
|
|
|
|
8
|
(defined($orders{$a}) && defined($orders{$b}) ? |
463
|
10
|
100
|
100
|
|
|
62
|
$orders{$a} <=> $orders{$b} : 0) |
|
|
50
|
|
|
|
|
|
464
|
|
|
|
|
|
|
|| $a cmp $b |
465
|
|
|
|
|
|
|
} (sort @$cols); |
466
|
|
|
|
|
|
|
} else { |
467
|
5
|
|
|
|
|
33
|
@ocols = sort @$cols; |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
6
|
|
|
|
|
41
|
\@ocols; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
1; |
474
|
|
|
|
|
|
|
# ABSTRACT: Pretty-print data structure for console output |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
__END__ |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=pod |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=encoding UTF-8 |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head1 NAME |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
Data::Format::Pretty::Console - Pretty-print data structure for console output |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=head1 VERSION |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
This document describes version 0.38 of Data::Format::Pretty::Console (from Perl distribution Data-Format-Pretty-Console), released on 2017-07-10. |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=head1 SYNOPSIS |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
In your program: |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
use Data::Format::Pretty::Console qw(format_pretty); |
495
|
|
|
|
|
|
|
... |
496
|
|
|
|
|
|
|
print format_pretty($result); |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
Some example output: |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
Scalar, format_pretty("foo"): |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
foo |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
List, format_pretty([1..21]): |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
.------------------------------------------------------. |
507
|
|
|
|
|
|
|
| 1 | 3 | 5 | 7 | 9 | 11 | 13 | 15 | 17 | 19 | 21 | |
508
|
|
|
|
|
|
|
| 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | | |
509
|
|
|
|
|
|
|
'----+----+----+----+----+----+----+----+----+----+----' |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
The same list, when program output is being piped (that is, (-t STDOUT) is |
512
|
|
|
|
|
|
|
false): |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
1 |
515
|
|
|
|
|
|
|
2 |
516
|
|
|
|
|
|
|
3 |
517
|
|
|
|
|
|
|
4 |
518
|
|
|
|
|
|
|
5 |
519
|
|
|
|
|
|
|
6 |
520
|
|
|
|
|
|
|
7 |
521
|
|
|
|
|
|
|
8 |
522
|
|
|
|
|
|
|
9 |
523
|
|
|
|
|
|
|
10 |
524
|
|
|
|
|
|
|
11 |
525
|
|
|
|
|
|
|
12 |
526
|
|
|
|
|
|
|
14 |
527
|
|
|
|
|
|
|
15 |
528
|
|
|
|
|
|
|
16 |
529
|
|
|
|
|
|
|
17 |
530
|
|
|
|
|
|
|
18 |
531
|
|
|
|
|
|
|
19 |
532
|
|
|
|
|
|
|
20 |
533
|
|
|
|
|
|
|
21 |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
Hash, format_pretty({foo=>"data",bar=>"format",baz=>"pretty",qux=>"console"}): |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
+-----+---------+ |
538
|
|
|
|
|
|
|
| bar | format | |
539
|
|
|
|
|
|
|
| baz | pretty | |
540
|
|
|
|
|
|
|
| foo | data | |
541
|
|
|
|
|
|
|
| qux | console | |
542
|
|
|
|
|
|
|
'-----+---------' |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
2-dimensional array, format_pretty([ [1, 2, ""], [28, "bar", 3], ["foo", 3, |
545
|
|
|
|
|
|
|
undef] ]): |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
+---------+---------+---------+ |
548
|
|
|
|
|
|
|
| 1 | 2 | | |
549
|
|
|
|
|
|
|
| 28 | bar | 3 | |
550
|
|
|
|
|
|
|
| foo | 3 | | |
551
|
|
|
|
|
|
|
'---------+---------+---------' |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
An array of hashrefs, such as commonly found if you use DBI's fetchrow_hashref() |
554
|
|
|
|
|
|
|
and friends, format_pretty([ {a=>1, b=>2}, {b=>2, c=>3}, {c=>4} ]): |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
.-----------. |
557
|
|
|
|
|
|
|
| a | b | c | |
558
|
|
|
|
|
|
|
+---+---+---+ |
559
|
|
|
|
|
|
|
| 1 | 2 | | |
560
|
|
|
|
|
|
|
| | 2 | 3 | |
561
|
|
|
|
|
|
|
| | | 4 | |
562
|
|
|
|
|
|
|
'---+---+---' |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
Some more complex data, format_pretty({summary => "Blah...", users => |
565
|
|
|
|
|
|
|
[{name=>"budi", domains=>["foo.com", "bar.com"], quota=>"1000"}, {name=>"arif", |
566
|
|
|
|
|
|
|
domains=>["baz.com"], quota=>"2000"}], verified => 0}): |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
summary: |
569
|
|
|
|
|
|
|
Blah... |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
users: |
572
|
|
|
|
|
|
|
.---------------------------------. |
573
|
|
|
|
|
|
|
| domains | name | quota | |
574
|
|
|
|
|
|
|
+------------------+------+-------+ |
575
|
|
|
|
|
|
|
| foo.com, bar.com | budi | 1000 | |
576
|
|
|
|
|
|
|
| baz.com | arif | 2000 | |
577
|
|
|
|
|
|
|
'------------------+------+-------' |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
verified: |
580
|
|
|
|
|
|
|
0 |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
Structures which can't be handled yet will simply be output as YAML, |
583
|
|
|
|
|
|
|
format_pretty({a {b=>1}}): |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
--- |
586
|
|
|
|
|
|
|
a: |
587
|
|
|
|
|
|
|
b: 1 |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=head1 DESCRIPTION |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
This module is meant to output data structure in a "pretty" or "nice" format, |
592
|
|
|
|
|
|
|
suitable for console programs. The idea of this module is that for you to just |
593
|
|
|
|
|
|
|
merrily dump data structure to the console, and this module will figure out how |
594
|
|
|
|
|
|
|
to best display your data to the end-user. |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
Currently this module tries to display the data mostly as a nice text table (or |
597
|
|
|
|
|
|
|
a series of text tables), and failing that, display it as YAML. |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
This module takes piping into consideration, and will output a simpler, more |
600
|
|
|
|
|
|
|
suitable format when your user pipes your program's output into some other |
601
|
|
|
|
|
|
|
program. |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
Most of the time, you don't have to configure anything, but some options are |
604
|
|
|
|
|
|
|
provided to tweak the output. |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
=for Pod::Coverage ^(content_type)$ |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=head1 FUNCTIONS |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
=for Pod::Coverage new |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
=head2 format_pretty($data, \%opts) |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
Return formatted data structure. Options: |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
=over |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
=item * interactive => BOOL (optional, default undef) |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
If set, will override interactive terminal detection (-t STDOUT). Simpler |
621
|
|
|
|
|
|
|
formatting will be done if terminal is non-interactive (e.g. when output is |
622
|
|
|
|
|
|
|
piped). Using this option will force simpler/full formatting. |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=item * list_max_columns => INT |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
When displaying list as columns, specify maximum number of columns. This can be |
627
|
|
|
|
|
|
|
used to force fewer columns (for example, single column) instead of using the |
628
|
|
|
|
|
|
|
whole available terminal width. |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
=item * table_column_orders => [[COLNAME1, COLNAME2], ...] |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
Specify column orders when drawing a table. If a table has all the columns, then |
633
|
|
|
|
|
|
|
the column names will be ordered according to the specification. For example, |
634
|
|
|
|
|
|
|
when table_column_orders is [[qw/foo bar baz/]], this table's columns will not |
635
|
|
|
|
|
|
|
be reordered because it doesn't have all the mentioned columns: |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
|foo|quux| |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
But this table will: |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
|apple|bar|baz|foo|quux| |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
into: |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
|apple|foo|bar|baz|quux| |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=item * table_column_formats => [{COLNAME=>FMT, ...}, ...] |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
Specify formats for columns. Each table format specification is a hashref |
650
|
|
|
|
|
|
|
{COLNAME=>FMT, COLNAME2=>FMT2, ...}. It will be applied to a table if the table |
651
|
|
|
|
|
|
|
has all the columns. FMT is a format specification according to |
652
|
|
|
|
|
|
|
L<Data::Unixish::Apply>, it's basically either a name of a dux function (e.g. |
653
|
|
|
|
|
|
|
C<"date">) or an array of function name + arguments (e.g. C<< [['date', [align |
654
|
|
|
|
|
|
|
=> {align=>'middle'}]] >>). This will be fed to L<Text::ANSITable>'s C<formats> |
655
|
|
|
|
|
|
|
column style. |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
=item * table_column_types => [{COLNAME=>TYPE, ...}, ...] |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
Specify types for columns. Each table format specification is a hashref |
660
|
|
|
|
|
|
|
{COLNAME=>TYPE, COLNAME2=>TYPE2, ...}. It will be applied to a table if the |
661
|
|
|
|
|
|
|
table has all the columns. TYPE is type name according to L<Sah> schema. This |
662
|
|
|
|
|
|
|
will be fed to L<Text::ANSITable>'s C<type> column style to give hints on how to |
663
|
|
|
|
|
|
|
format the column. Sometimes this is the simpler alternative to |
664
|
|
|
|
|
|
|
C<table_column_formats>. |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=back |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
=head1 ENVIRONMENT |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=over |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=item * INTERACTIVE => BOOL |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
To set default for C<interactive> option (overrides automatic detection). |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=item * FORMAT_PRETTY_LIST_MAX_COLUMNS => INT |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
To set C<list_max_columns> option. |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=item * FORMAT_PRETTY_TABLE_COLUMN_FORMATS => ARRAY (JSON) |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
To set C<table_column_formats> option, interpreted as JSON. |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
=item * FORMAT_PRETTY_TABLE_COLUMN_TYPES => ARRAY (JSON) |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
To set C<table_column_types> option, interpreted as JSON. |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=item * FORMAT_PRETTY_TABLE_COLUMN_ORDERS => ARRAY (JSON) |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
To set C<table_column_orders> option, interpreted as JSON. |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
=item * COLUMNS => INT |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
To override terminal width detection. |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=back |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
=head1 HOMEPAGE |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
Please visit the project's homepage at L<https://metacpan.org/release/Data-Format-Pretty-Console>. |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=head1 SOURCE |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
Source repository is at L<https://github.com/perlancar/perl-Data-Format-Pretty-Console>. |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=head1 BUGS |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data-Format-Pretty-Console> |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
When submitting a bug or request, please include a test-file or a |
711
|
|
|
|
|
|
|
patch to an existing test-file that illustrates the bug or desired |
712
|
|
|
|
|
|
|
feature. |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=head1 SEE ALSO |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
Modules used for formatting: L<Text::ANSITable>, L<YAML>. |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
L<Data::Format::Pretty> |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
=head1 AUTHOR |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
perlancar <perlancar@cpan.org> |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
This software is copyright (c) 2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010 by perlancar@cpan.org. |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
729
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
=cut |