File Coverage

blib/lib/Text/ECSV.pm
Criterion Covered Total %
statement 30 32 93.7
branch 4 6 66.6
condition 2 3 66.6
subroutine 6 6 100.0
pod 3 3 100.0
total 45 50 90.0


line stmt bran cond sub pod time code
1             package Text::ECSV;
2              
3             =head1 NAME
4              
5             Text::ECSV - Extended CSV manipulation routines
6              
7             =head1 SYNOPSIS
8              
9             use Text::ECSV;
10             $ecsv = Text::ECSV->new (); # create a new object
11             $line = 'id=3,name=Text::ECSV,shot_desc=Extended CSV manipulation routines';
12             $status = $ecsv->parse ($line); # parse a CSV string into fields
13             # and name value pairs
14             %columns = $ecsv->fields_hash (); # get the parsed field hash
15             $column = $ecsv->field_named('id'); # get field value for given name
16            
17             $ecsv->combine('b' => 2, 'a' => 1, 'c' => 3, );
18             # ok($ecsv->string eq 'b=2,a=1,c=3');
19              
20             =head1 DESCRIPTION
21              
22             C< use base 'Text::CSV_XS'; > => see L.
23              
24             Roland Giersig had a presentation at YAPC 2007 called 'Techniques for Remote
25             System-Monitoring'. He was explaining his search after a good logging
26             format or how to store continuous flow of data in a most usable form.
27             XML? YAML? CSV? XML is nice but for a machines not for humans,
28             YAML is nice for both but it's hard to grep. CSV is readable and grep-able
29             but not too flexible. So what is the conclusion? ECSV is like a CSV but
30             in each comma separated field the name of the column is set. This gives a
31             flexibility to skip, reorder, add the fields. All the information is stored
32             per line so it's easy to grep. Also it's easy to compare two records by
33             md5-ing the lines or doing string eq.
34              
35             =cut
36              
37 2     2   51935 use warnings;
  2         6  
  2         67  
38 2     2   13 use strict;
  2         4  
  2         129  
39              
40             our $VERSION = '0.01';
41              
42 2     2   12 use base 'Text::CSV_XS', 'Class::Accessor::Fast';
  2         5  
  2         2960  
43              
44             =head1 PROPERTIES
45              
46             =head2 fields_hash
47              
48             Holds hash reference to the resulting hash constructed by C.
49              
50             =head2 dup_keys_strategy
51              
52             If set and a dupplicate key names occure in a parsed line, this strategy
53             is called with C<< ->($name, $old_value, $value) >>.
54              
55             Can be used for duplicate keys to join values to one string, or push them
56             to an array or to treat them how ever is desired. By default values overwrite
57             each other.
58              
59             =cut
60              
61             __PACKAGE__->mk_accessors(qw{
62             fields_hash
63             dup_keys_strategy
64             });
65              
66             =head1 METHODS
67              
68             =head2 field_named($name)
69              
70             Return field with $name.
71              
72             =cut
73              
74             sub field_named {
75 7     7 1 776 my $self = shift;
76 7         11 my $name = shift;
77            
78 7         19 return $self->fields_hash->{$name};
79             }
80              
81              
82             =head2 parse()
83              
84             In aditional to the C functionality it decodes
85             name value pairs to fill in C.
86              
87             =cut
88              
89             sub parse {
90 4     4 1 3715 my $self = shift;
91            
92             # reset fields hash
93 4         16 $self->fields_hash({});
94            
95             # run Text::CSV_XS parse
96 4         44 my $status = $self->SUPER::parse(@_);
97            
98             # if the CSV parsing failed then just return
99 4 50       144 return $status
100             if not $status;
101            
102             # decode the fileds
103 4         18 foreach my $field ($self->fields) {
104             # if we have key value pair
105 14 50       100 if ($field =~ m/^([^=]+)=(.*)$/) {
106 14         25 my $name = $1;
107 14         28 my $value = $2;
108            
109             # if it the second occurence of the same key and we have a strategy use it
110             # to construct the new value
111 14 100 66     56 if (exists $self->{'fields_hash'}->{$name} and exists $self->{'dup_keys_strategy'}) {
112 3         14 $value = $self->{'dup_keys_strategy'}->($name, $self->{'fields_hash'}->{$name}, $value);
113             }
114            
115             # store value
116 14         68 $self->{'fields_hash'}->{$name} = $value;
117             }
118             # else fail
119             else {
120 0         0 $status = 0;
121             # TODO fill error messages
122            
123 0         0 last;
124             }
125             }
126            
127 4         23 return $status;
128             }
129              
130              
131             =head2 combine($key => $value, ...)
132              
133             The function joins all $key.'='.$value and then calls C
134             constructing a CSV from the arguments, returning success or failure.
135              
136             =cut
137              
138             sub combine {
139 1     1 1 926 my $self = shift;
140 1         4 my @key_values = @_;
141 1         2 my @fields;
142            
143 1         4 while (@key_values) {
144 3         13 push @fields, (shift(@key_values).'='.shift(@key_values));
145             }
146            
147 1         10 return $self->SUPER::combine(@fields);
148             }
149              
150             1;
151              
152              
153             __END__