File Coverage

blib/lib/File/Process/Utils.pm
Criterion Covered Total %
statement 98 102 96.0
branch 40 46 86.9
condition 10 17 58.8
subroutine 16 16 100.0
pod 1 4 25.0
total 165 185 89.1


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