File Coverage

blib/lib/Perinci/Result/Format/Lite.pm
Criterion Covered Total %
statement 248 356 69.6
branch 114 204 55.8
condition 62 113 54.8
subroutine 15 17 88.2
pod 1 2 50.0
total 440 692 63.5


line stmt bran cond sub pod time code
1             package Perinci::Result::Format::Lite;
2              
3             our $DATE = '2020-11-12'; # DATE
4             our $VERSION = '0.278'; # VERSION
5              
6 1     1   105028 use 5.010001;
  1         24  
7             #IFUNBUILT
8             # use strict;
9             # use warnings;
10             #END IFUNBUILT
11              
12 1     1   7 use List::Util qw(first max);
  1         2  
  1         73  
13              
14 1     1   6 use Exporter qw(import);
  1         3  
  1         1602  
15             our @EXPORT_OK = qw(format);
16              
17             # copy-pasted from List::MoreUtils::PP
18             sub firstidx (&@) {
19 40     40 0 58 my $f = shift;
20 40         79 foreach my $i ( 0 .. $#_ )
21             {
22 101         155 local *_ = \$_[$i];
23 101 100       173 return $i if $f->();
24             }
25 10         31 return -1;
26             }
27              
28             sub _json {
29 4     4   8 state $json = do {
30 1 50       2 if (eval { require Cpanel::JSON::XS; 1 }) { Cpanel::JSON::XS->new->canonical(1)->convert_blessed->allow_nonref }
  1 0       7  
  1 0       5  
  1         14  
31 0         0 elsif (eval { require JSON::Tiny::Subclassable; 1 }) { JSON::Tiny::Subclassable->new }
  0         0  
  0         0  
32 0         0 elsif (eval { require JSON::PP; 1 }) { JSON::PP->new->canonical(1)->convert_blessed->allow_nonref }
  0         0  
  0         0  
33 0         0 else { die "Can't find any JSON module" }
34             };
35 4         45 $json;
36             };
37              
38             sub __cleanse {
39 2     2   4 state $cleanser = do {
40 1         2 eval { require Data::Clean::JSON; 1 };
  1         1275  
  1         6970  
41 1 50       4 if ($@) {
42 0         0 undef;
43             } else {
44 1         7 Data::Clean::JSON->get_cleanser;
45             }
46             };
47 2 50       3788 if ($cleanser) {
48 2         15 $cleanser->clean_in_place($_[0]);
49             } else {
50 0         0 $_[0];
51             }
52             }
53              
54             sub __gen_table {
55 12     12   33 my ($data, $header_row, $resmeta, $format) = @_;
56              
57 12   100     36 $resmeta //= {};
58              
59             # column names
60 12         19 my @columns;
61 12 50       29 if ($header_row) {
62 12         21 @columns = @{$data->[0]};
  12         34  
63             } else {
64 0         0 @columns = map {"col$_"} 0..@{$data->[0]}-1;
  0         0  
  0         0  
65             }
66              
67 12         20 my $column_orders; # e.g. [col2, col1, col3, ...]
68             SET_COLUMN_ORDERS: {
69              
70             # find column orders from 'table_column_orders' in result metadata (or
71             # from env)
72 12         18 my $tcos;
  12         21  
73 12 50 33     75 if ($ENV{FORMAT_PRETTY_TABLE_COLUMN_ORDERS}) {
    50          
74 0         0 $tcos = _json->encode($ENV{FORMAT_PRETTY_TABLE_COLUMN_ORDERS});
75             } elsif (my $rfos = ($resmeta->{'cmdline.format_options'} //
76             $resmeta->{format_options})) {
77 0   0     0 my $rfo = $rfos->{'text-pretty'} // $rfos->{text} // $rfos->{any};
      0        
78 0 0       0 if ($rfo) {
79 0         0 $tcos = $rfo->{table_column_orders};
80             }
81             }
82 12 50       33 if ($tcos) {
83             # find an entry in tcos that @columns contains all the columns of
84             COLS:
85 0         0 for my $cols (@$tcos) {
86 0         0 for my $col (@$cols) {
87 0 0   0   0 next COLS unless first {$_ eq $col} @columns;
  0         0  
88             }
89 0         0 $column_orders = $cols;
90 0         0 last SET_COLUMN_ORDERS;
91             }
92             }
93              
94 12 100       28 if ($resmeta->{'table.field_orders'}) {
95 1         3 $column_orders = $resmeta->{'table.field_orders'};
96 1         3 last SET_COLUMN_ORDERS;
97             }
98              
99             # find column orders from table spec
100 11         22 $column_orders = $resmeta->{'table.fields'};
101             }
102              
103             # reorder each row according to requested column order
104 12 100       32 if ($column_orders) {
105 11         626 require Sort::BySpec;
106 11         1218 my $cmp = Sort::BySpec::cmp_by_spec(spec => $column_orders);
107             # 0->2, 1->0, ... (map column position from unordered to ordered)
108 57         4787 my @map0 = sort { $cmp->($a->[1], $b->[1]) }
109 11         267 map {[$_, $columns[$_]]} 0..$#columns;
  47         118  
110             #use DD; dd \@map0;
111 11         974 my @map;
112 11         32 for (0..$#map0) {
113 47         85 $map[$_] = $map0[$_][0];
114             }
115             #use DD; dd \@map;
116 11         22 my $newdata = [];
117 11         25 for my $row (@$data) {
118 42         58 my @newrow;
119 42         75 for (0..$#map) { $newrow[$_] = $row->[$map[$_]] }
  174         314  
120 42         89 push @$newdata, \@newrow;
121             }
122 11         20 $data = $newdata;
123 11         17 my @newcolumns;
124 11         19 for (@map) { push @newcolumns, $columns[$_] }
  47         78  
125 11         182 @columns = @newcolumns;
126             }
127              
128 12         21 my @field_idxs; # map column to index in table.fields
129             {
130 12 100       38 my $tff = $resmeta->{'table.fields'} or last;
131 10         25 for my $i (0..$#columns) {
132 40     101   139 $field_idxs[$i] = firstidx { $_ eq $columns[$i] } @$tff;
  101         292  
133             }
134             }
135              
136             # determine field labels
137             {
138 12 50 33     17 last unless $header_row && @$data;
  12         25  
  12         53  
139 12 100       34 my $tff = $resmeta->{'table.fields'} or last;
140 10         15 my $tfl = $resmeta->{'table.field_labels'};
141 10         20 my $tfu = $resmeta->{'table.field_units'};
142 10         20 for my $i (0..$#columns) {
143 40         52 my $field_idx = $field_idxs[$i];
144 40 100       104 next unless $field_idx >= 0;
145 30 100 100     125 if ($tfl && defined $tfl->[$field_idx]) {
    100 66        
146 2         5 $data->[0][$i] = $tfl->[$field_idx];
147             } elsif ($tfu && defined $tfu->[$field_idx]) {
148             # add field units as label suffix to header (" (UNIT)")
149 3         9 $data->[0][$i] .= " ($tfu->[$field_idx])";
150             }
151             }
152             }
153              
154             FORMAT_CELLS:
155             {
156 12         20 my $tffmt = $resmeta->{'table.field_formats'};
  12         20  
157 12         21 my $tffmt_code = $resmeta->{'table.field_format_code'};
158 12         25 my $tffmt_default = $resmeta->{'table.default_field_format'};
159 12 50 66     64 last unless $tffmt || $tffmt_code || $tffmt_default;
      66        
160              
161 3         8 my (@fmt_names, @fmt_opts); # key: column index
162 3         8 for my $i (0..$#columns) {
163 12         20 my $field_idx = $field_idxs[$i];
164 12 100       29 my $fmt = $tffmt_code ? $tffmt_code->($columns[$i]) : undef;
165 12 100 66     61 $fmt //= $tffmt->[$field_idx] if $field_idx >= 0;
166 12   100     34 $fmt //= $tffmt_default;
167 12 100       28 if (ref $fmt eq 'ARRAY') {
168 6         12 $fmt_names[$i] = $fmt->[0];
169 6   50     17 $fmt_opts [$i] = $fmt->[1] // {};
170             } else {
171 6         12 $fmt_names[$i] = $fmt;
172 6         13 $fmt_opts [$i] = {};
173             }
174             }
175              
176 3         7 my $nf;
177              
178 3         9 for my $i (0..$#{$data}) {
  3         10  
179 6 100 66     24 next if $i==0 && $header_row;
180 3         8 my $row = $data->[$i];
181 3         9 for my $j (0..$#columns) {
182 12 50       1054 next unless defined $row->[$j];
183 12         24 my $fmt_name = $fmt_names[$j];
184             #say "D:j=$j fmt_name=$fmt_name";
185 12 100       27 next unless $fmt_name;
186 10         16 my $fmt_opts = $fmt_opts [$j];
187 10 100 100     63 if ($fmt_name eq 'iso8601_datetime' || $fmt_name eq 'iso8601_date') {
    50          
    50          
    50          
    50          
    50          
188 4 50       31 if ($row->[$j] =~ /\A[0-9]+(\.[0-9]*)?\z/) {
189 4 50       18 my $frac = $1 ? "0$1"+0 : 0;
190 4         38 my @t = gmtime($row->[$j]);
191 4 100       14 if ($fmt_name eq 'iso8601_datetime') {
192 1 50       14 $row->[$j] = sprintf(
193             "%04d-%02d-%02dT%02d:%02d:".($frac ? "%06.3f" : "%02d")."Z",
194             $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]+$frac);
195             } else {
196 3         30 $row->[$j] = sprintf(
197             "%04d-%02d-%02d",
198             $t[5]+1900, $t[4]+1, $t[3]);
199             }
200             }
201             } elsif ($fmt_name eq 'boolstr') {
202 0 0       0 $row->[$j] = $row->[$j] ? "yes" : "no";
203             } elsif ($fmt_name eq 'filesize') {
204 0         0 require Format::Human::Bytes;
205 0         0 $row->[$j] = Format::Human::Bytes::base2($row->[$j], 0);
206             } elsif ($fmt_name eq 'sci2dec') {
207 0 0       0 if ($row->[$j] =~ /\A(?:[+-]?)(?:\d+\.|\d*\.(\d+))[eE]([+-]?\d+)\z/) {
208 0 0 0     0 my $n = length($1 || "") - $2; $n = 0 if $n < 0;
  0         0  
209 0         0 $row->[$j] = sprintf("%.${n}f", $row->[$j]);
210             }
211             } elsif ($fmt_name eq 'percent') {
212 0   0     0 my $fmt = $fmt_opts->{sprintf} // '%.2f%%';
213 0         0 $row->[$j] = sprintf($fmt, $row->[$j] * 100);
214             } elsif ($fmt_name eq 'number') {
215 6         30 require Number::Format::BigFloat;
216             $row->[$j] = Number::Format::BigFloat::format_number(
217             $row->[$j], {
218             thousands_sep => $fmt_opts->{thousands_sep} // ',',
219             decimal_point => $fmt_opts->{decimal_point} // '.',
220 6   50     62 decimal_digits => $fmt_opts->{precision} // 0,
      50        
      50        
221             # XXX decimal_fill
222             });
223             }
224             }
225             }
226             }
227              
228 12 50       420 if ($format eq 'text-pretty') {
    0          
    0          
229             ALIGN_COLUMNS:
230             {
231             # XXX we just want to turn off 'uninitialized' and 'negative repeat
232             # count does nothing' from the operator x
233 1     1   9 no warnings;
  1         2  
  1         959  
  12         22  
234              
235 12         27 my $tfa = $resmeta->{'table.field_aligns'};
236 12         21 my $tfa_code = $resmeta->{'table.field_align_code'};
237 12         23 my $tfa_default = $resmeta->{'table.default_field_align'};
238 12 50 66     57 last unless $tfa || $tfa_code || $tfa_default;
      66        
239 3 50       10 last unless @$data;
240              
241 3         7 for my $colidx (0..$#columns) {
242 12         20 my $field_idx = $field_idxs[$colidx];
243 12 100       29 my $align = $tfa_code ? $tfa_code->($columns[$colidx]) : undef;
244 12 100 33     53 $align //= $tfa->[$field_idx] if $field_idx >= 0;
245 12   100     32 $align //= $tfa_default;
246 12 100       27 next unless $align;
247              
248             # determine max widths
249 11         16 my $maxw;
250 11         18 my ($maxw_bd, $maxw_d, $maxw_ad); # before digit, digit, after d
251 11 100       22 if ($align eq 'number') {
252 3         6 my (@w_bd, @w_d, @w_ad);
253 3         4 for my $i (0..$#{$data}) {
  3         7  
254 15         22 my $row = $data->[$i];
255 15 50       30 if (@$row > $colidx) {
256 15         21 my $cell = $row->[$colidx];
257 15 100 66     90 if ($header_row && $i == 0) {
    100          
    50          
258 3         8 my $w = length($cell);
259 3         7 push @w_bd, 0;
260 3         7 push @w_bd, 0;
261 3         7 push @w_ad, 0;
262             } elsif ($cell =~ /\A([+-]?\d+)(\.?)(\d*)\z/) {
263             # decimal notation number
264 8         21 push @w_bd, length($1);
265 8         13 push @w_d , length($2);
266 8         27 push @w_ad, length($3);
267             } elsif ($cell =~ /\A([+-]?\d+\.?\d*)([eE])([+-]?\d+)\z/) {
268             # scientific notation number
269 4         9 push @w_bd, length($1);
270 4         6 push @w_d , length($2);
271 4         9 push @w_ad, length($3);
272             } else {
273             # not a number
274 0         0 push @w_bd, length($cell);
275 0         0 push @w_bd, 0;
276 0         0 push @w_ad, 0;
277             }
278             } else {
279 0         0 push @w_bd, 0;
280 0         0 push @w_d , 0;
281 0         0 push @w_ad, 0;
282             }
283             }
284 3         9 $maxw_bd = max(@w_bd);
285 3         19 $maxw_d = max(@w_d);
286 3         8 $maxw_ad = max(@w_ad);
287 3 50       9 if ($header_row) {
288 3         6 my $w = length($data->[0][$colidx]);
289 3 100 66     12 if ($maxw_d == 0 && $maxw_ad == 0) {
290 1         4 $maxw_bd = $w;
291             }
292             }
293             }
294              
295             $maxw = max(map {
296 11 50       21 @$_ > $colidx ? length($_->[$colidx]) : 0
  55         119  
297             } @$data);
298              
299             # do the alignment
300 11         20 for my $i (0..$#{$data}) {
  11         24  
301 55         82 my $row = $data->[$i];
302 55         72 for my $i (0..$#{$data}) {
  55         104  
303 275         364 my $row = $data->[$i];
304 275 50       515 next unless @$row > $colidx;
305 275         387 my $cell = $row->[$colidx];
306 275 50       465 next unless defined($cell);
307 275 100 100     666 if ($align eq 'number') {
    100          
    100          
308 75         110 my ($bd, $d, $ad);
309 75 100 66     436 if ($header_row && $i == 0) {
    100          
    100          
310             } elsif (($bd, $d, $ad) = $cell =~ /\A([+-]?\d+)(\.?)(\d*)\z/) {
311 8         27 $cell = join(
312             '',
313             (' ' x ($maxw_bd - length($bd))), $bd,
314             $d , (' ' x ($maxw_d - length($d ))),
315             $ad, (' ' x ($maxw_ad - length($ad))),
316             );
317             } elsif (($bd, $d, $ad) = $cell =~ /\A([+-]?\d+\.?\d*)([eE])([+-]?\d+)\z/) {
318 4         12 $cell = join(
319             '',
320             (' ' x ($maxw_bd - length($bd))), $bd,
321             $d , (' ' x ($maxw_d - length($d ))),
322             $ad, (' ' x ($maxw_ad - length($ad))),
323             );
324             }
325 75         114 my $w = length($cell);
326 75 100       142 $cell = (' ' x ($maxw - $w)) . $cell
327             if $maxw > $w;
328             } elsif ($align eq 'right') {
329 75         138 $cell = (' ' x ($maxw - length($cell))) . $cell;
330             } elsif ($align eq 'middle' || $align eq 'center') {
331 50         73 my $w = length($cell);
332 50         80 my $n = int(($maxw-$w)/2);
333 50         99 $cell = (' ' x $n) . $cell . (' ' x ($maxw-$w-$n));
334             } else {
335             # assumed left
336 75         121 $cell .= (' ' x ($maxw - length($cell)));
337              
338             }
339 275         516 $row->[$colidx] = $cell;
340             }
341             }
342             } # for $colidx
343             } # END align columns
344              
345 12         21 my $fres;
346 12         26 my $backend = $ENV{FORMAT_PRETTY_TABLE_BACKEND};
347 12 50 0     32 $backend //= "Text::Table::Org" if $ENV{INSIDE_EMACS};
348 12 50       27 if ($backend) {
349 0         0 require Text::Table::Any;
350 0         0 $fres = Text::Table::Any::table(rows=>$data, header_row=>$header_row, backend=>$backend);
351             } else {
352 12         603 require Text::Table::Tiny;
353 12         29752 $fres = Text::Table::Tiny::table(rows=>$data, header_row=>$header_row);
354             }
355 12 50 33     9999 $fres .= "\n" unless $fres =~ /\R\z/ || !length($fres);
356 12         159 $fres;
357             } elsif ($format eq 'csv') {
358 1     1   9 no warnings 'uninitialized';
  1         2  
  1         167  
359             join(
360             "",
361             map {
362 0         0 my $row = $_;
  0         0  
363             join(
364             ",",
365             map {
366 0         0 my $cell = $_;
  0         0  
367 0         0 $cell =~ s/(["\\])/\\$1/g;
368 0         0 qq("$cell");
369             } @$row)."\n";
370             } @$data
371             );
372             } elsif ($format eq 'html') {
373 1     1   8 no warnings 'uninitialized';
  1         3  
  1         361  
374 0         0 require HTML::Entities;
375              
376 0         0 my $tfa = $resmeta->{'table.field_aligns'};
377              
378 0         0 my @res;
379             push @res, "<table".($resmeta->{'table.html_class'} ?
380             " class=\"".HTML::Entities::encode_entities(
381 0 0       0 $resmeta->{'table.html_class'})."\"" : "").
382             ">\n";
383 0         0 for my $i (0..$#{$data}) {
  0         0  
384 0 0       0 my $data_elem = $i == 0 ? "th" : "td";
385 0 0       0 push @res, "<thead>\n" if $i == 0;
386 0 0       0 push @res, "<tbody>\n" if $i == 1;
387 0         0 push @res, " <tr>\n";
388 0         0 my $row = $data->[$i];
389 0         0 for my $j (0..$#{$row}) {
  0         0  
390 0         0 my $field_idx = $field_idxs[$j];
391 0         0 my $align;
392 0 0 0     0 if ($field_idx >= 0 && $tfa->[$field_idx]) {
393 0         0 $align = $tfa->[$field_idx];
394 0 0       0 $align = "right" if $align eq 'number';
395 0 0       0 $align = "middle" if $align eq 'center';
396             }
397 0 0       0 push @res, " <$data_elem",
398             ($align ? " align=\"$align\"" : ""),
399             ">", HTML::Entities::encode_entities($row->[$j]),
400             "</$data_elem>\n";
401             }
402 0         0 push @res, " </tr>\n";
403 0 0       0 push @res, "</thead>\n" if $i == 0;
404             }
405 0         0 push @res, "</tbody>\n";
406 0         0 push @res, "</table>\n";
407 0         0 join '', @res;
408             } else {
409 1     1   8 no warnings 'uninitialized';
  1         2  
  1         441  
410 0 0       0 shift @$data if $header_row;
411 0         0 join("", map {join("\t", @$_)."\n"} @$data);
  0         0  
412             }
413             }
414              
415             sub format {
416 18     18 1 95200 my ($res, $format, $is_naked, $cleanse) = @_;
417              
418 18 100       276 if ($format =~ /\A(text|text-simple|text-pretty|csv|html)\z/) {
419 16 0       57 $format = $format eq 'text' ?
    50          
420             ((-t STDOUT) ? 'text-pretty' : 'text-simple') : $format;
421 1     1   8 no warnings 'uninitialized';
  1         3  
  1         646  
422 16 100 66     117 if ($res->[0] !~ /^(2|304)/) {
    50          
423 1         4 my $fres = "ERROR $res->[0]: $res->[1]";
424 1 50       5 if (my $prev = $res->[3]{prev}) {
425 0         0 $fres .= " ($prev->[0]: $prev->[1])";
426             }
427 1         6 return "$fres\n";
428             } elsif ($res->[3] && $res->[3]{"x.hint.result_binary"}) {
429 0         0 return $res->[2];
430             } else {
431 15         691 require Data::Check::Structure;
432 15         1621 my $data = $res->[2];
433 15         29 my $max = 1000;
434 15 100 66     132 if (!ref($data)) {
    50          
    50          
    50          
    100          
    50          
435 3   100     12 $data //= "";
436 3 100 100     19 $data .= "\n" unless !length($data) || $data =~ /\n\z/;
437 3         20 return $data;
438             } elsif (ref($data) eq 'ARRAY' && !@$data) {
439 0         0 return "";
440             } elsif (Data::Check::Structure::is_aos($data, {max=>$max})) {
441 0         0 return join("", map {"$_\n"} @$data);
  0         0  
442             } elsif (Data::Check::Structure::is_aoaos($data, {max=>$max})) {
443 0         0 my $header_row = 0;
444 0         0 my $data = $data;
445 0 0       0 if ($res->[3]{'table.fields'}) {
446 0         0 $data = [$res->[3]{'table.fields'}, @$data];
447 0         0 $header_row = 1;
448             }
449 0         0 return __gen_table($data, $header_row, $res->[3], $format);
450             } elsif (Data::Check::Structure::is_hos($data, {max=>$max})) {
451 1         43 $data = [map {[$_, $data->{$_}]} sort keys %$data];
  1         4  
452 1         5 unshift @$data, ["key", "value"];
453 1         6 return __gen_table($data, 1, $res->[3], $format);
454             } elsif (Data::Check::Structure::is_aohos($data, {max=>$max})) {
455             # collect all mentioned fields
456 11         1662 my @fieldnames;
457 11 100 66     76 if ($res->[3] && $res->[3]{'table.fields'} &&
      100        
458             $res->[3]{'table.hide_unknown_fields'}) {
459 1         3 @fieldnames = @{ $res->[3]{'table.fields'} };
  1         3  
460             } else {
461 10         19 my %fieldnames;
462 10         26 for my $row (@$data) {
463 28         96 $fieldnames{$_}++ for keys %$row;
464             }
465 10         69 @fieldnames = sort keys %fieldnames;
466             }
467 11         25 my $newdata = [];
468 11         26 for my $row (@$data) {
469 31         62 push @$newdata, [map {$row->{$_}} @fieldnames];
  127         264  
470             }
471 11         32 unshift @$newdata, \@fieldnames;
472 11         37 return __gen_table($newdata, 1, $res->[3], $format);
473             } else {
474 0         0 $format = 'json-pretty';
475             }
476             }
477             }
478              
479 2         8 my $tff = $res->[3]{'table.fields'};
480 2 50       8 $res = $res->[2] if $is_naked;
481              
482 2 50       8 if ($format eq 'perl') {
483 0   0     0 my $use_color = $ENV{COLOR} // (-t STDOUT);
484 0 0 0     0 if ($use_color && eval { require Data::Dump::Color; 1 }) {
  0 0       0  
  0         0  
485 0         0 return Data::Dump::Color::dump($res);
486 0         0 } elsif (eval { require Data::Dump; 1 }) {
  0         0  
487 0         0 return Data::Dump::dump($res);
488             } else {
489 1     1   9 no warnings 'once';
  1         2  
  1         496  
490 0         0 require Data::Dumper;
491 0         0 local $Data::Dumper::Terse = 1;
492 0         0 local $Data::Dumper::Indent = 1;
493 0         0 local $Data::Dumper::Useqq = 1;
494 0         0 local $Data::Dumper::Deparse = 1;
495 0         0 local $Data::Dumper::Quotekeys = 0;
496 0         0 local $Data::Dumper::Sortkeys = 1;
497 0         0 local $Data::Dumper::Trailingcomma = 1;
498 0         0 return Data::Dumper::Dumper($res);
499             }
500             }
501              
502 2 100       12 unless ($format =~ /\Ajson(-pretty)?\z/) {
503 1         78 warn "Unknown format '$format', fallback to json-pretty";
504 1         6 $format = 'json-pretty';
505             }
506 2 50 50     21 __cleanse($res) if ($cleanse//1);
507 2 50       269 if ($format =~ /json/) {
508 2 0 33     11 if ($tff && _json->can("sort_by") &&
      33        
509 0         0 eval { require Sort::ByExample; 1}) {
  0         0  
510 0         0 my $cmp = Sort::ByExample->cmp($tff);
511 0     0   0 _json->sort_by(sub { $cmp->($JSON::PP::a, $JSON::PP::b) });
  0         0  
512             }
513              
514 2 50       8 if ($format eq 'json') {
515 0         0 return _json->encode($res) . "\n";
516             } else {
517 2         8 _json->pretty(1);
518 2         5 return _json->encode($res);
519             }
520             }
521             }
522              
523             1;
524             # ABSTRACT: Format enveloped result
525              
526             __END__
527              
528             =pod
529              
530             =encoding UTF-8
531              
532             =head1 NAME
533              
534             Perinci::Result::Format::Lite - Format enveloped result
535              
536             =head1 VERSION
537              
538             This document describes version 0.278 of Perinci::Result::Format::Lite (from Perl distribution Perinci-Result-Format-Lite), released on 2020-11-12.
539              
540             =head1 SYNOPSIS
541              
542             =head1 DESCRIPTION
543              
544             =for Pod::Coverage ^(firstidx)$
545              
546             =head1 FUNCTIONS
547              
548             =head2 format($res, $format[ , $is_naked=0, $cleanse=1 ]) => str
549              
550             =head1 ENVIRONMENT
551              
552             =head2 FORMAT_PRETTY_TABLE_BACKEND => str
553              
554             If this is set, will render text table using L<Text::Table::Any> (with
555             C<backend> set to the value of this environment variable) instead of the default
556             L<Text::Table::Tiny>. This is useful if you want to output text table in a
557             different format, for example to generate Org tables (make sure
558             L<Text::Table::Org> backend is already installed):
559              
560             % FORMAT_PRETTY_TABLE_BACKEND=Text::Table::Org lcpan rdeps Getopt::Lucid
561              
562             For convenience, a default is chosen for you under certain condition. When
563             inside Emacs (environment C<INSIDE_EMACS> is set), C<Text::Table::Org> is used
564             as default.
565              
566             =head2 FORMAT_PRETTY_TABLE_COLUMN_ORDERS => array (json)
567              
568             Set the default of C<table_column_orders> in C<format_options> in result
569             metadata, similar to what's implemented in L<Perinci::Result::Format> and
570             L<Data::Format::Pretty::Console>.
571              
572             =head2 COLOR => bool
573              
574             =head1 HOMEPAGE
575              
576             Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Result-Format-Lite>.
577              
578             =head1 SOURCE
579              
580             Source repository is at L<https://github.com/perlancar/perl-Perinci-Result-Format-Lite>.
581              
582             =head1 BUGS
583              
584             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Result-Format-Lite>
585              
586             When submitting a bug or request, please include a test-file or a
587             patch to an existing test-file that illustrates the bug or desired
588             feature.
589              
590             =head1 SEE ALSO
591              
592             L<Perinci::Result::Format>, a more heavyweight version of this module.
593              
594             L<Perinci::CmdLine::Lite> uses this module to format enveloped result.
595              
596             =head1 AUTHOR
597              
598             perlancar <perlancar@cpan.org>
599              
600             =head1 COPYRIGHT AND LICENSE
601              
602             This software is copyright (c) 2020, 2018, 2017, 2016, 2015 by perlancar@cpan.org.
603              
604             This is free software; you can redistribute it and/or modify it under
605             the same terms as the Perl 5 programming language system itself.
606              
607             =cut