File Coverage

blib/lib/Catmandu/Importer/CSV.pm
Criterion Covered Total %
statement 17 17 100.0
branch 4 4 100.0
condition n/a
subroutine 6 6 100.0
pod n/a
total 27 27 100.0


line stmt bran cond sub pod time code
1              
2             use Catmandu::Sane;
3 7     7   87454  
  7         16  
  7         45  
4             our $VERSION = '1.2018';
5              
6             use Text::CSV;
7 7     7   5284 use List::Util qw(reduce);
  7         87055  
  7         321  
8 7     7   55 use Moo;
  7         18  
  7         397  
9 7     7   40 use namespace::clean;
  7         15  
  7         46  
10 7     7   2627  
  7         14  
  7         59  
11             with 'Catmandu::Importer';
12              
13             has csv => (is => 'ro', lazy => 1, builder => '_build_csv');
14             has sep_char => (
15             is => 'ro',
16             default => sub {','},
17             coerce => sub {
18             my $sep_char = $_[0];
19             $sep_char =~ s/(\\[abefnrt])/"qq{$1}"/gee;
20             return $sep_char;
21             }
22             );
23             has quote_char => (is => 'ro', default => sub {'"'});
24             has escape_char => (is => 'ro', default => sub {'"'});
25             has allow_loose_quotes => (is => 'ro', default => sub {0});
26             has allow_loose_escapes => (is => 'ro', default => sub {0});
27             has header => (is => 'ro', default => sub {1});
28             has fields => (
29             is => 'rwp',
30             coerce => sub {
31             my $fields = $_[0];
32             if (ref $fields eq 'ARRAY') {return $fields}
33             if (ref $fields eq 'HASH') {return [sort keys %$fields]}
34             return [split ',', $fields];
35             },
36             );
37              
38             my ($self) = @_;
39             Text::CSV->new(
40 23     23   200 {
41 23 100       348 binary => 1,
    100          
42             sep_char => $self->sep_char,
43             quote_char => $self->quote_char ? $self->quote_char : undef,
44             escape_char => $self->escape_char ? $self->escape_char : undef,
45             allow_loose_quotes => $self->allow_loose_quotes,
46             allow_loose_escapes => $self->allow_loose_escapes,
47             }
48             );
49             }
50              
51             my ($self) = @_;
52             sub {
53             state $line = 0;
54             state $fh = $self->fh;
55             state $csv = do {
56             if ($self->header) {
57             if ($self->fields) {
58             $self->csv->getline($fh);
59             $line++;
60             }
61             else {
62             $self->_set_fields($self->csv->getline($fh));
63             $line++;
64             }
65             }
66             if ($self->fields) {
67             $self->csv->column_names($self->fields);
68             }
69             $self->csv;
70             };
71              
72             # generate field names if needed
73             unless ($self->fields) {
74             my $row = $csv->getline($fh) // return;
75             $line++;
76             my $fields = [0 .. (@$row - 1)];
77             $self->_set_fields($fields);
78             $csv->column_names($fields);
79             return reduce {
80             $a->{$b} = $row->[$b] if length $row->[$b];
81             $a;
82             }
83             +{}, @$fields;
84             }
85              
86             my $rec = $csv->getline_hr($fh);
87             $line++;
88              
89             if (defined $rec || $csv->eof()) {
90             return $rec;
91             }
92             else {
93             my ($cde, $str, $pos) = $csv->error_diag();
94             die
95             "at line $line (byte $pos) found a Text::CSV parse error($cde) $str";
96             }
97             };
98             }
99              
100             1;
101              
102              
103             =pod
104              
105             =head1 NAME
106              
107             Catmandu::Importer::CSV - Package that imports CSV data
108              
109             =head1 SYNOPSIS
110              
111             # From the command line
112              
113             # convert a CSV file to JSON
114             catmandu convert CSV to JSON < journals.csv
115              
116             # set column names if CSV file has no header line
117             echo '12157,"The Journal of Headache and Pain",2193-1801' | \
118             catmandu convert CSV --header 0 --fields 'id,title,issn' to YAML
119            
120             # set field separator and quote character
121             echo '12157;$The Journal of Headache and Pain$;2193-1801' | \
122             catmandu convert CSV --header 0 --fields 'id,title,issn' --sep_char ';' --quote_char '$' to XLSX --file journal.xlsx
123              
124             # In a Perl script
125              
126             use Catmandu;
127              
128             my $importer = Catmandu->importer('CSV', file => "/foo/bar.csv");
129              
130             my $n = $importer->each(sub {
131             my $hashref = $_[0];
132             # ...
133             });
134              
135             =head1 DESCRIPTION
136              
137             The package imports comma-separated values (CSV). The object
138             fields are read from the CSV header line or given via the C<fields> parameter.
139             Strings in CSV are quoted by C<quote_char> and fields are separated by
140             C<sep_char>.
141              
142             =head1 CONFIGURATION
143              
144             =over
145              
146             =item file
147              
148             Read input from a local file given by its path. Alternatively a scalar
149             reference can be passed to read from a string.
150              
151             =item fh
152              
153             Read input from an L<IO::Handle>. If not specified, L<Catmandu::Util::io> is used to
154             create the input stream from the C<file> argument or by using STDIN.
155              
156             =item encoding
157              
158             Binmode of the input stream C<fh>. Set to C<:utf8> by default.
159              
160             =item fix
161              
162             An ARRAY of one or more fixes or file scripts to be applied to imported items.
163              
164             =item fields
165              
166             List of fields to be used as columns, given as array reference, comma-separated
167             string, or hash reference. If C<header> is C<0> and C<fields> is C<undef> the
168             fields will be named by column index ("0", "1", "2", ...).
169              
170             =item header
171              
172             Read fields from a header line with the column names, if set to C<1> (the
173             default).
174              
175             =item sep_char
176              
177             Column separator (C<,> by default)
178              
179             =item quote_char
180              
181             Quotation character (C<"> by default)
182              
183             =item escape_char
184              
185             Character for escaping inside quoted field (C<"> by default)
186              
187             =item allow_loose_quotes
188              
189             =item allow_loose_escapes
190              
191             Allow common bad-practice in CSV escaping
192              
193             =back
194              
195             =head1 METHODS
196              
197             Every L<Catmandu::Importer> is a L<Catmandu::Iterable> all its methods are
198             inherited. The methods are not idempotent: CSV streams can only be read once.
199              
200             =head1 SEE ALSO
201              
202             L<Catmandu::Exporter::CSV>, L<Catmandu::Importer::XLS>
203              
204             =cut