File Coverage

blib/lib/App/LTSVUtils.pm
Criterion Covered Total %
statement 36 62 58.0
branch 7 22 31.8
condition 0 7 0.0
subroutine 6 8 75.0
pod 3 4 75.0
total 52 103 50.4


line stmt bran cond sub pod time code
1             package App::LTSVUtils;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2020-05-03'; # DATE
5             our $DIST = 'App-LTSVUtils'; # DIST
6             our $VERSION = '0.002'; # VERSION
7              
8 1     1   105246 use 5.010001;
  1         13  
9 1     1   6 use strict;
  1         2  
  1         43  
10 1     1   7 use warnings;
  1         2  
  1         926  
11              
12             our %SPEC;
13              
14             my %args_common = (
15             );
16              
17             my %arg_filename_0 = (
18             filename => {
19             summary => 'Input LTSV file',
20             schema => 'filename*',
21             description => <<'_',
22              
23             Use `-` to read from stdin.
24              
25             _
26             req => 1,
27             pos => 0,
28             cmdline_aliases => {f=>{}},
29             },
30             );
31              
32             my %arg_filename_1 = (
33             filename => {
34             summary => 'Input LTSV file',
35             description => <<'_',
36              
37             Use `-` to read from stdin.
38              
39             _
40             schema => 'filename*',
41             req => 1,
42             pos => 1,
43             cmdline_aliases => {f=>{}},
44             },
45             );
46              
47             $SPEC{ltsvutil} = {
48             v => 1.1,
49             summary => 'Perform action on a LTSV file',
50             'x.no_index' => 1,
51             args => {
52             %args_common,
53             action => {
54             schema => ['str*', in=>[
55             'dump',
56             '2csv',
57             ]],
58             req => 1,
59             pos => 0,
60             cmdline_aliases => {a=>{}},
61             },
62             %arg_filename_1,
63             },
64             args_rels => {
65             },
66             };
67             sub ltsvutil {
68 1     1 0 3 my %args = @_;
69 1         2 my $action = $args{action};
70              
71 1         2 my $res = "";
72 1         2 my $i = 0;
73              
74 1         2 my $fh;
75 1 50       4 if ($args{filename} eq '-') {
76 0         0 $fh = *STDIN;
77             } else {
78             open $fh, "<", $args{filename} or
79 1 50       41 return [500, "Can't open input filename '$args{filename}': $!"];
80             }
81 1         15 binmode $fh, ":encoding(utf8)";
82              
83             my $code_getline = sub {
84 3     3   46 my $row0 = <$fh>;
85 3 100       25 return undef unless defined $row0;
86 2         6 chomp($row0);
87 2         3 my $row = {};
88 2         11 for my $col0 (split /\t/, $row0) {
89 4 50       20 $col0 =~ /(.+?):(.*)/ or die "Row $i: Invalid column '$col0': must be in LABEL:VAL format\n";
90 4         16 $row->{$1} = $2;
91             }
92 2         7 $row;
93 1         59 };
94              
95 1         2 my $rows = [];
96 1         2 my %col_idxs;
97              
98 1         3 while (my $row = $code_getline->()) {
99 2         3 $i++;
100 2 50 0     6 if ($action eq 'dump') {
    0          
101 2         6 push @$rows, $row;
102             } elsif ($action eq '2csv' || $action eq '2tsv') {
103 0         0 push @$rows, $row;
104 0         0 for my $k (sort keys %$row) {
105 0 0       0 next if defined $col_idxs{$k};
106 0         0 $col_idxs{$k} = keys(%col_idxs);
107             }
108             } else {
109 0         0 return [400, "Unknown action '$action'"];
110             }
111             } # while getline()
112              
113 1         5 my @cols = sort { $col_idxs{$a} <=> $col_idxs{$b} } keys %col_idxs;
  0         0  
114              
115 1 50       4 if ($action eq 'dump') {
    0          
    0          
116 1         26 return [200, "OK", $rows];
117             } elsif ($action eq '2csv') {
118 0         0 require Text::CSV_XS;
119 0         0 my $csv = Text::CSV_XS->new({binary=>1});
120 0         0 $csv->print(\*STDOUT, \@cols);
121 0         0 print "\n";
122 0         0 for my $row (@$rows) {
123 0   0     0 $csv->print(\*STDOUT, [map {$row->{$_} // ''} @cols]);
  0         0  
124 0         0 print "\n";
125             }
126             } elsif ($action eq '2tsv') {
127 0 0       0 if (@cols) {
128 0         0 print join("\t", @cols) . "\n";
129 0         0 for my $row (@$rows) {
130 0   0     0 print join("\t", map { $row->{$_} // '' } @cols) . "\n";
  0         0  
131             }
132             }
133             } else {
134 0         0 return [500, "Unknown action '$action'"];
135             }
136              
137 0         0 [200, "OK", $res, {"cmdline.skip_format"=>1}];
138             } # ltsvutil
139              
140             $SPEC{ltsv_dump} = {
141             v => 1.1,
142             summary => 'Dump LTSV as data structure (array of hashes)',
143             args => {
144             %args_common,
145             %arg_filename_0,
146             },
147             };
148             sub ltsv_dump {
149 1     1 1 2393 my %args = @_;
150 1         5 ltsvutil(%args, action=>'dump');
151             }
152              
153             $SPEC{ltsv2csv} = {
154             v => 1.1,
155             summary => 'Convert LTSV to CSV',
156             args => {
157             %args_common,
158             %arg_filename_0,
159             },
160             };
161             sub ltsv2csv {
162 0     0 1   my %args = @_;
163 0           ltsvutil(%args, action=>'2csv');
164             }
165              
166             $SPEC{ltsv2tsv} = {
167             v => 1.1,
168             summary => 'Convert LTSV to TSV',
169             args => {
170             %args_common,
171             %arg_filename_0,
172             },
173             };
174             sub ltsv2tsv {
175 0     0 1   my %args = @_;
176 0           ltsvutil(%args, action=>'2tsv');
177             }
178              
179             1;
180             # ABSTRACT: CLI utilities related to LTSV
181              
182             __END__
183              
184             =pod
185              
186             =encoding UTF-8
187              
188             =head1 NAME
189              
190             App::LTSVUtils - CLI utilities related to LTSV
191              
192             =head1 VERSION
193              
194             This document describes version 0.002 of App::LTSVUtils (from Perl distribution App-LTSVUtils), released on 2020-05-03.
195              
196             =head1 DESCRIPTION
197              
198             This distribution contains the following CLI utilities:
199              
200             =over
201              
202             =item * L<dump-ltsv>
203              
204             =item * L<ltsv-dump>
205              
206             =item * L<ltsv2csv>
207              
208             =item * L<ltsv2tsv>
209              
210             =back
211              
212             =head1 FUNCTIONS
213              
214              
215             =head2 ltsv2csv
216              
217             Usage:
218              
219             ltsv2csv(%args) -> [status, msg, payload, meta]
220              
221             Convert LTSV to CSV.
222              
223             This function is not exported.
224              
225             Arguments ('*' denotes required arguments):
226              
227             =over 4
228              
229             =item * B<filename>* => I<filename>
230              
231             Input LTSV file.
232              
233             Use C<-> to read from stdin.
234              
235              
236             =back
237              
238             Returns an enveloped result (an array).
239              
240             First element (status) is an integer containing HTTP status code
241             (200 means OK, 4xx caller error, 5xx function error). Second element
242             (msg) is a string containing error message, or 'OK' if status is
243             200. Third element (payload) is optional, the actual result. Fourth
244             element (meta) is called result metadata and is optional, a hash
245             that contains extra information.
246              
247             Return value: (any)
248              
249              
250              
251             =head2 ltsv2tsv
252              
253             Usage:
254              
255             ltsv2tsv(%args) -> [status, msg, payload, meta]
256              
257             Convert LTSV to TSV.
258              
259             This function is not exported.
260              
261             Arguments ('*' denotes required arguments):
262              
263             =over 4
264              
265             =item * B<filename>* => I<filename>
266              
267             Input LTSV file.
268              
269             Use C<-> to read from stdin.
270              
271              
272             =back
273              
274             Returns an enveloped result (an array).
275              
276             First element (status) is an integer containing HTTP status code
277             (200 means OK, 4xx caller error, 5xx function error). Second element
278             (msg) is a string containing error message, or 'OK' if status is
279             200. Third element (payload) is optional, the actual result. Fourth
280             element (meta) is called result metadata and is optional, a hash
281             that contains extra information.
282              
283             Return value: (any)
284              
285              
286              
287             =head2 ltsv_dump
288              
289             Usage:
290              
291             ltsv_dump(%args) -> [status, msg, payload, meta]
292              
293             Dump LTSV as data structure (array of hashes).
294              
295             This function is not exported.
296              
297             Arguments ('*' denotes required arguments):
298              
299             =over 4
300              
301             =item * B<filename>* => I<filename>
302              
303             Input LTSV file.
304              
305             Use C<-> to read from stdin.
306              
307              
308             =back
309              
310             Returns an enveloped result (an array).
311              
312             First element (status) is an integer containing HTTP status code
313             (200 means OK, 4xx caller error, 5xx function error). Second element
314             (msg) is a string containing error message, or 'OK' if status is
315             200. Third element (payload) is optional, the actual result. Fourth
316             element (meta) is called result metadata and is optional, a hash
317             that contains extra information.
318              
319             Return value: (any)
320              
321             =for Pod::Coverage ^(ltsvutil)$
322              
323             =head1 FAQ
324              
325             =head1 HOMEPAGE
326              
327             Please visit the project's homepage at L<https://metacpan.org/release/App-LTSVUtils>.
328              
329             =head1 SOURCE
330              
331             Source repository is at L<https://github.com/perlancar/perl-App-LTSVUtils>.
332              
333             =head1 BUGS
334              
335             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-LTSVUtils>
336              
337             When submitting a bug or request, please include a test-file or a
338             patch to an existing test-file that illustrates the bug or desired
339             feature.
340              
341             =head1 SEE ALSO
342              
343             L<https://ltsv.org>
344              
345             L<App::TSVUtils>
346              
347             L<App::CSVUtils>
348              
349             L<App::SerializeUtils>
350              
351             =head1 AUTHOR
352              
353             perlancar <perlancar@cpan.org>
354              
355             =head1 COPYRIGHT AND LICENSE
356              
357             This software is copyright (c) 2020, 2019 by perlancar@cpan.org.
358              
359             This is free software; you can redistribute it and/or modify it under
360             the same terms as the Perl 5 programming language system itself.
361              
362             =cut