File Coverage

blib/lib/App/CSVUtils/csv_delete_fields.pm
Criterion Covered Total %
statement 11 11 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 15 15 100.0


line stmt bran cond sub pod time code
1             package App::CSVUtils::csv_delete_fields;
2              
3 1     1   5008 use 5.010001;
  1         4  
4 1     1   5 use strict;
  1         2  
  1         25  
5 1     1   5 use warnings;
  1         2  
  1         69  
6              
7             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
8             our $DATE = '2023-04-01'; # DATE
9             our $DIST = 'App-CSVUtils'; # DIST
10             our $VERSION = '1.024'; # VERSION
11              
12 1         443 use App::CSVUtils qw(
13             gen_csv_util
14 1     1   6 );
  1         2  
15              
16             gen_csv_util(
17             name => 'csv_delete_fields',
18             summary => 'Delete one or more fields from CSV file',
19             add_args => {
20             %App::CSVUtils::argspecsopt_field_selection,
21             },
22             tags => ['category:munging','deletes-fields'],
23              
24             examples => [
25             {
26             summary => 'Delete a single field from CSV',
27             argv => ['file.csv', '-f', 'f1'],
28             test => 0,
29             'x.doc.show_result' => 0,
30             },
31             {
32             summary => 'Delete several fields from CSV',
33             argv => ['file.csv', '-f', 'f1', '-f', 'f2', '-f', 'f3'],
34             test => 0,
35             'x.doc.show_result' => 0,
36             },
37             {
38             summary => 'Delete fields matching regex from CSV',
39             argv => ['file.csv', '--include-field-pat', '/^extra_/'],
40             test => 0,
41             'x.doc.show_result' => 0,
42             },
43             {
44             summary => 'Delete all fields except specified from CSV',
45             argv => ['file.csv', '-a', '-f', 'f1', '-f', 'f2'],
46             test => 0,
47             'x.doc.show_result' => 0,
48             },
49             {
50             summary => 'Only show what fields would be included, then exit',
51             argv => ['file.csv', '--include-field-pat', '/^extra_/', '--show-selected-fields'],
52             test => 0,
53             'x.doc.show_result' => 0,
54             },
55             ],
56              
57             on_input_data_row => sub {
58             my $r = shift;
59              
60             # we add the following keys to the stash
61             unless ($r->{selected_fields_idx_array_sorted}) {
62             my $res = App::CSVUtils::_select_fields($r->{input_fields}, $r->{input_fields_idx}, $r->{util_args});
63             die $res unless $res->[0] == 100;
64             my $selected_fields = $res->[2][0];
65             my $selected_fields_idx_array = $res->[2][1];
66             die [412, "At least one field must remain"]
67             if @{ $selected_fields } == @{ $r->{input_fields} };
68             $r->{selected_fields_idx_array_sorted} = [sort { $b <=> $a } @$selected_fields_idx_array];
69              
70             # set ouput fields
71             $r->{output_fields} = [@{ $r->{input_fields} }];
72             for (@{ $r->{selected_fields_idx_array_sorted} }) {
73             splice @{ $r->{output_fields} }, $_, 1;
74             }
75              
76             if ($r->{util_args}{show_selected_fields}) {
77             $r->{wants_skip_files}++;
78             $r->{result} = [200, "OK", $selected_fields];
79             return;
80             }
81             }
82              
83             for (@{ $r->{selected_fields_idx_array_sorted} }) {
84             splice @{ $r->{input_row} }, $_, 1;
85             }
86              
87             $r->{code_print_row}->($r->{input_row});
88             },
89             );
90              
91             1;
92             # ABSTRACT: Delete one or more fields from CSV file
93              
94             __END__
95              
96             =pod
97              
98             =encoding UTF-8
99              
100             =head1 NAME
101              
102             App::CSVUtils::csv_delete_fields - Delete one or more fields from CSV file
103              
104             =head1 VERSION
105              
106             This document describes version 1.024 of App::CSVUtils::csv_delete_fields (from Perl distribution App-CSVUtils), released on 2023-04-01.
107              
108             =head1 FUNCTIONS
109              
110              
111             =head2 csv_delete_fields
112              
113             Usage:
114              
115             csv_delete_fields(%args) -> [$status_code, $reason, $payload, \%result_meta]
116              
117             Delete one or more fields from CSV file.
118              
119             Examples:
120              
121             =over
122              
123             =item * Delete a single field from CSV:
124              
125             csv_delete_fields(input_filename => "file.csv", include_fields => ["f1"]);
126              
127             =item * Delete several fields from CSV:
128              
129             csv_delete_fields(input_filename => "file.csv", include_fields => ["f1", "f2", "f3"]);
130              
131             =item * Delete fields matching regex from CSV:
132              
133             csv_delete_fields(input_filename => "file.csv", include_field_pat => "/^extra_/");
134              
135             =item * Delete all fields except specified from CSV:
136              
137             csv_delete_fields(
138             input_filename => "file.csv",
139             include_field_pat => ".*",
140             include_fields => ["f1", "f2"]
141             );
142              
143             =item * Only show what fields would be included, then exit:
144              
145             csv_delete_fields(
146             input_filename => "file.csv",
147             include_field_pat => "/^extra_/",
148             show_selected_fields => 1
149             );
150              
151             =back
152              
153             (No description)
154              
155             This function is not exported.
156              
157             Arguments ('*' denotes required arguments):
158              
159             =over 4
160              
161             =item * B<exclude_field_pat> => I<re>
162              
163             Field regex pattern to exclude, takes precedence over --field-pat.
164              
165             =item * B<exclude_fields> => I<array[str]>
166              
167             Field names to exclude, takes precedence over --fields.
168              
169             =item * B<ignore_unknown_fields> => I<bool>
170              
171             When unknown fields are specified in --include-field (--field) or --exclude-field options, ignore them instead of throwing an error.
172              
173             =item * B<include_field_pat> => I<re>
174              
175             Field regex pattern to select, overidden by --exclude-field-pat.
176              
177             =item * B<include_fields> => I<array[str]>
178              
179             Field names to include, takes precedence over --exclude-field-pat.
180              
181             =item * B<inplace> => I<true>
182              
183             Output to the same file as input.
184              
185             Normally, you output to a different file than input. If you try to output to the
186             same file (C<-o INPUT.csv -O>) you will clobber the input file; thus the utility
187             prevents you from doing it. However, with this C<--inplace> option, you can
188             output to the same file. Like perl's C<-i> option, this will first output to a
189             temporary file in the same directory as the input file then rename to the final
190             file at the end. You cannot specify output file (C<-o>) when using this option,
191             but you can specify backup extension with C<-b> option.
192              
193             Some caveats:
194              
195             =over
196              
197             =item * if input file is a symbolic link, it will be replaced with a regular file;
198              
199             =item * renaming (implemented using C<rename()>) can fail if input filename is too long;
200              
201             =item * value specified in C<-b> is currently not checked for acceptable characters;
202              
203             =item * things can also fail if permissions are restrictive;
204              
205             =back
206              
207             =item * B<inplace_backup_ext> => I<str> (default: "")
208              
209             Extension to add for backup of input file.
210              
211             In inplace mode (C<--inplace>), if this option is set to a non-empty string, will
212             rename the input file using this extension as a backup. The old existing backup
213             will be overwritten, if any.
214              
215             =item * B<input_escape_char> => I<str>
216              
217             Specify character to escape value in field in input CSV, will be passed to Text::CSV_XS.
218              
219             Defaults to C<\\> (backslash). Overrides C<--input-tsv> option.
220              
221             =item * B<input_filename> => I<filename> (default: "-")
222              
223             Input CSV file.
224              
225             Use C<-> to read from stdin.
226              
227             Encoding of input file is assumed to be UTF-8.
228              
229             =item * B<input_header> => I<bool> (default: 1)
230              
231             Specify whether input CSV has a header row.
232              
233             By default, the first row of the input CSV will be assumed to contain field
234             names (and the second row contains the first data row). When you declare that
235             input CSV does not have header row (C<--no-input-header>), the first row of the
236             CSV is assumed to contain the first data row. Fields will be named C<field1>,
237             C<field2>, and so on.
238              
239             =item * B<input_quote_char> => I<str>
240              
241             Specify field quote character in input CSV, will be passed to Text::CSV_XS.
242              
243             Defaults to C<"> (double quote). Overrides C<--input-tsv> option.
244              
245             =item * B<input_sep_char> => I<str>
246              
247             Specify field separator character in input CSV, will be passed to Text::CSV_XS.
248              
249             Defaults to C<,> (comma). Overrides C<--input-tsv> option.
250              
251             =item * B<input_tsv> => I<true>
252              
253             Inform that input file is in TSV (tab-separated) format instead of CSV.
254              
255             Overriden by C<--input-sep-char>, C<--input-quote-char>, C<--input-escape-char>
256             options. If one of those options is specified, then C<--input-tsv> will be
257             ignored.
258              
259             =item * B<output_always_quote> => I<bool> (default: 0)
260              
261             Whether to always quote values.
262              
263             When set to false (the default), values are quoted only when necessary:
264              
265             field1,field2,"field three contains comma (,)",field4
266              
267             When set to true, then all values will be quoted:
268              
269             "field1","field2","field three contains comma (,)","field4"
270              
271             =item * B<output_escape_char> => I<str>
272              
273             Specify character to escape value in field in output CSV, will be passed to Text::CSV_XS.
274              
275             This is like C<--input-escape-char> option but for output instead of input.
276              
277             Defaults to C<\\> (backslash). Overrides C<--output-tsv> option.
278              
279             =item * B<output_filename> => I<filename>
280              
281             Output filename.
282              
283             Use C<-> to output to stdout (the default if you don't specify this option).
284              
285             Encoding of output file is assumed to be UTF-8.
286              
287             =item * B<output_header> => I<bool>
288              
289             Whether output CSV should have a header row.
290              
291             By default, a header row will be output I<if> input CSV has header row. Under
292             C<--output-header>, a header row will be output even if input CSV does not have
293             header row (value will be something like "col0,col1,..."). Under
294             C<--no-output-header>, header row will I<not> be printed even if input CSV has
295             header row. So this option can be used to unconditionally add or remove header
296             row.
297              
298             =item * B<output_quote_char> => I<str>
299              
300             Specify field quote character in output CSV, will be passed to Text::CSV_XS.
301              
302             This is like C<--input-quote-char> option but for output instead of input.
303              
304             Defaults to C<"> (double quote). Overrides C<--output-tsv> option.
305              
306             =item * B<output_quote_empty> => I<bool> (default: 0)
307              
308             Whether to quote empty values.
309              
310             When set to false (the default), empty values are not quoted:
311              
312             field1,field2,,field4
313              
314             When set to true, then empty values will be quoted:
315              
316             field1,field2,"",field4
317              
318             =item * B<output_sep_char> => I<str>
319              
320             Specify field separator character in output CSV, will be passed to Text::CSV_XS.
321              
322             This is like C<--input-sep-char> option but for output instead of input.
323              
324             Defaults to C<,> (comma). Overrides C<--output-tsv> option.
325              
326             =item * B<output_tsv> => I<bool>
327              
328             Inform that output file is TSV (tab-separated) format instead of CSV.
329              
330             This is like C<--input-tsv> option but for output instead of input.
331              
332             Overriden by C<--output-sep-char>, C<--output-quote-char>, C<--output-escape-char>
333             options. If one of those options is specified, then C<--output-tsv> will be
334             ignored.
335              
336             =item * B<overwrite> => I<bool>
337              
338             Whether to override existing output file.
339              
340             =item * B<show_selected_fields> => I<true>
341              
342             Show selected fields and then immediately exit.
343              
344              
345             =back
346              
347             Returns an enveloped result (an array).
348              
349             First element ($status_code) is an integer containing HTTP-like status code
350             (200 means OK, 4xx caller error, 5xx function error). Second element
351             ($reason) is a string containing error message, or something like "OK" if status is
352             200. Third element ($payload) is the actual result, but usually not present when enveloped result is an error response ($status_code is not 2xx). Fourth
353             element (%result_meta) is called result metadata and is optional, a hash
354             that contains extra information, much like how HTTP response headers provide additional metadata.
355              
356             Return value: (any)
357              
358             =head1 HOMEPAGE
359              
360             Please visit the project's homepage at L<https://metacpan.org/release/App-CSVUtils>.
361              
362             =head1 SOURCE
363              
364             Source repository is at L<https://github.com/perlancar/perl-App-CSVUtils>.
365              
366             =head1 AUTHOR
367              
368             perlancar <perlancar@cpan.org>
369              
370             =head1 CONTRIBUTING
371              
372              
373             To contribute, you can send patches by email/via RT, or send pull requests on
374             GitHub.
375              
376             Most of the time, you don't need to build the distribution yourself. You can
377             simply modify the code, then test via:
378              
379             % prove -l
380              
381             If you want to build the distribution (e.g. to try to install it locally on your
382             system), you can install L<Dist::Zilla>,
383             L<Dist::Zilla::PluginBundle::Author::PERLANCAR>,
384             L<Pod::Weaver::PluginBundle::Author::PERLANCAR>, and sometimes one or two other
385             Dist::Zilla- and/or Pod::Weaver plugins. Any additional steps required beyond
386             that are considered a bug and can be reported to me.
387              
388             =head1 COPYRIGHT AND LICENSE
389              
390             This software is copyright (c) 2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016 by perlancar <perlancar@cpan.org>.
391              
392             This is free software; you can redistribute it and/or modify it under
393             the same terms as the Perl 5 programming language system itself.
394              
395             =head1 BUGS
396              
397             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=App-CSVUtils>
398              
399             When submitting a bug or request, please include a test-file or a
400             patch to an existing test-file that illustrates the bug or desired
401             feature.
402              
403             =cut