File Coverage

blib/lib/File/Process/Utils.pm
Criterion Covered Total %
statement 100 104 96.1
branch 40 46 86.9
condition 10 17 58.8
subroutine 17 17 100.0
pod 1 4 25.0
total 168 188 89.3


line stmt bran cond sub pod time code
1             package File::Process::Utils;
2              
3 5     5   34 use strict;
  5         10  
  5         152  
4 5     5   24 use warnings;
  5         8  
  5         116  
5              
6 5     5   23 use Carp;
  5         9  
  5         269  
7 5     5   4091 use Text::CSV_XS;
  5         82472  
  5         236  
8 5     5   40 use Data::Dumper;
  5         12  
  5         259  
9 5     5   2507 use ReadonlyX;
  5         7923  
  5         278  
10 5     5   36 use Scalar::Util qw(reftype);
  5         9  
  5         1023  
11              
12             Readonly our $SUCCESS => 1;
13             Readonly our $FAILURE => 0;
14             Readonly our $TRUE => 1;
15             Readonly our $FALSE => 0;
16              
17             Readonly our $EMPTY => q{};
18             Readonly our $NL => "\n";
19             Readonly our $TAB => "\t";
20             Readonly our $PIPE => q{|};
21             Readonly our $COMMA => q{,};
22              
23 5     5   2259 use parent qw(Exporter);
  5         1575  
  5         29  
24              
25             our @EXPORT_OK = qw(
26             $COMMA
27             $EMPTY
28             $FAILURE
29             $FALSE
30             $NL
31             $PIPE
32             $SUCCESS
33             $TAB
34             $TRUE
35             is_array
36             is_hash
37             process_csv
38             );
39              
40             our %EXPORT_TAGS = (
41             'booleans' => [qw($TRUE $FALSE $SUCCESS $FAILURE is_array is_hash)],
42             'chars' => [qw($NL $EMPTY $PIPE $TAB $COMMA)],
43             'all' => \@EXPORT_OK,
44             );
45              
46             our $VERSION = '0.11';
47              
48             ########################################################################
49 236     236   368 sub _is_array { push @_, 'ARRAY'; goto &_is_type; }
  236         471  
50 136     136   216 sub _is_hash { push @_, 'HASH'; goto &_is_type; }
  136         262  
51 108     108 0 151 sub is_code { push @_, 'CODE'; goto &_is_type; }
  108         196  
52             ########################################################################
53              
54             ########################################################################
55             sub is_hash { ## no critic (RequireArgUnpacking)
56             ########################################################################
57 136     136 0 3853 my $result = _is_hash( $_[0] );
58              
59             return
60 136 100       368 if !$result;
61              
62 20 50       37 return wantarray ? %{ ref $_[0] ? $_[0] : {} } : $result;
  19 100       76  
63             }
64              
65             ########################################################################
66             sub is_array { ## no critic (RequireArgUnpacking)
67             ########################################################################
68 236     236 0 2958 my $result = _is_array( $_[0] );
69              
70             return
71 236 100       672 if !$result;
72              
73 58 50       145 return wantarray ? @{ ref $_[0] ? $_[0] : [] } : $result;
  11 100       36  
74             }
75              
76             ########################################################################
77 480   100 480   1513 sub _is_type { return ref $_[0] && reftype( $_[0] ) eq $_[1]; }
78             ########################################################################
79              
80             ########################################################################
81             sub process_csv {
82             ########################################################################
83 9     9 1 42 my ( $file, %options ) = @_;
84              
85 9         31 require File::Process;
86              
87 9   50     29 my $csv_options = $options{csv_options} // {};
88              
89 9         29 my $csv = Text::CSV_XS->new($csv_options);
90              
91 9   33     1102 $options{chomp} //= $TRUE;
92              
93             my ( $csv_lines, %info ) = File::Process::process_file(
94             $file,
95             csv => $csv,
96             %options,
97             pre => sub {
98 9     9   20 my ( $file, $args ) = @_;
99              
100 9         23 my ( $fh, $all_lines ) = File::Process::pre( $file, $args );
101              
102 9 100       25 if ( $args->{'has_headers'} ) {
103 1         55 my @column_names = $args->{csv}->getline($fh);
104 1         55 $args->{csv}->column_names(@column_names);
105             }
106              
107 9         56 return ( $fh, $all_lines );
108             },
109             next_line => sub {
110 90     90   179 my ( $fh, $all_lines, $args ) = @_;
111              
112             return
113             if defined $args->{max_rows}
114 0         0 && @{$all_lines}
115 90 0 33     207 && @{$all_lines} >= $args->{max_rows};
  0   33     0  
116              
117 90         115 my $ref;
118              
119 90 100       165 if ( $args->{has_headers} ) {
120 10         26 $ref = $args->{csv}->getline_hr($fh);
121              
122 10 50       631 if ( my (%skips) = is_hash( $args->{skip_list} ) ) {
123 0         0 for ( keys %skips ) {
124 0         0 delete $ref->{$_};
125             }
126             }
127             }
128             else {
129 80         1830 $ref = $args->{csv}->getline($fh);
130              
131 80 100       2337 return $ref
132             if !$ref;
133              
134 72 100 100     239 if ( !$args->{keep_list} && is_array( $args->{skip_list} ) ) {
135              
136 1         3 my @keep_list = ( 0 .. $#{$ref} );
  1         14  
137              
138 1         3 for ( @{ $args->{skip_list} } ) {
  1         3  
139 1         3 splice @keep_list, $_, 1;
140             }
141              
142 1         2 $args->{keep_list} = \@keep_list;
143             }
144              
145 72 100       185 if ( $args->{keep_list} ) {
146 9         13 $ref = [ @{$ref}[ @{ $args->{keep_list} } ] ];
  9         24  
  9         15  
147             }
148             }
149              
150 82         114 my %row;
151              
152 82         117 my $column_keys = $args->{column_names};
153              
154 82 100       129 if ( is_array($column_keys) ) {
155              
156 45 100       64 if ( !@{$column_keys} ) {
  45         95  
157             # generated extra column names as needed
158 4         6 $column_keys = [ map {"col$_"} ( 0 .. $#{$ref} ) ];
  16         38  
  4         10  
159 4         9 $args->{column_names} = $column_keys;
160             }
161             }
162              
163 82 100       164 if ($column_keys) {
164 45         67 %row = map { $column_keys->[$_] => $ref->[$_] } ( 0 .. $#{$ref} );
  180         444  
  45         84  
165 45 100       129 if ( my (%skips) = is_hash( $args->{skip_list} ) ) {
166 9         20 for ( keys %skips ) {
167 9         23 delete $row{$_};
168             }
169             }
170             }
171              
172             # hooks?
173 82 100       204 if ( my (@hooks) = is_array( $args->{hooks} ) ) {
    100          
174              
175 9         17 for my $col ( 0 .. $#{$ref} ) {
  9         21  
176 36         117 is_code $hooks[$col];
177              
178 36 100       61 next if !is_code $hooks[$col];
179              
180 18         41 $ref->[$col] = $hooks[$col]->( $ref->[$col] );
181             }
182             }
183             elsif ( my (%hooks) = is_hash( $args->{hooks} ) ) {
184              
185             croak "you just define column_names when 'hooks' is a hash\n"
186 9 50       12 if !@{$column_keys};
  9         18  
187              
188 9         17 for my $column_name ( @{$column_keys} ) {
  9         14  
189 36 100       109 next if !is_code $hooks{$column_name};
190              
191             $row{$column_name}
192 18         43 = $hooks{$column_name}->( $row{$column_name} );
193             }
194             }
195              
196 82 100       351 return $column_keys ? \%row : $ref;
197             }
198 9         80 );
199              
200 9         110 return ( $csv_lines, %info );
201             }
202              
203             1;
204              
205             __END__