File Coverage

blib/lib/PerlIO/via/csv.pm
Criterion Covered Total %
statement 63 64 98.4
branch 17 20 85.0
condition 3 3 100.0
subroutine 15 15 100.0
pod 1 6 16.6
total 99 108 91.6


line stmt bran cond sub pod time code
1             package PerlIO::via::csv;
2              
3 3     3   127781 use 5.008001;
  3         13  
  3         128  
4 3     3   17 use strict;
  3         6  
  3         111  
5 3     3   16 use warnings;
  3         12  
  3         153  
6              
7             our $VERSION = '0.01';
8              
9 3     3   5014 use Spreadsheet::Read; # I can't get this to `require' in OPEN
  3         533547  
  3         303  
10 3     3   3768 use Text::CSV; # ::Encoded ?
  3         8866  
  3         22  
11              
12              
13             BEGIN {
14             # class methods
15 3     3   832 my $sheet = 1;
16             sub sheet {
17 30 100   30 1 5925 $sheet = $_[1] if defined $_[1];
18 30         2441 return $sheet;
19             }
20 3         1944 my $debug = 0;
21             sub debug {
22 3 50   3 0 9 $debug = $_[1] if defined $_[1];
23 3         9 return $debug;
24             }
25              
26             sub import {
27 3     3   30 my $pkg = shift;
28 3         6 my %args = @_;
29              
30             # class methods passed to C<use>
31 3         9 for (qw(sheet)) {
32 3 100       2527 $pkg->$_($args{$_}) if exists $args{$_};
33             }
34              
35             # args to Spreadsheet::Read or ParseExcel?
36             }
37              
38             # function
39             sub damn (@) {
40 3     3 0 43 require Carp;
41 3 50       14 if (__PACKAGE__->debug) {
42 0         0 Carp::confess(join("\n", @_));
43             }
44             else {
45 3         616 Carp::croak(join("\n", @_));
46             }
47             }
48             }
49              
50              
51             ### PerlIO::via interface
52              
53             sub PUSHED {
54 8     8 0 5310 my ($pkg, $mode, $fh) = @_;
55              
56 8         101 bless {
57             row => 1,
58             col => 1,
59             # meta => {},
60             rows => [],
61             }, $pkg;
62             }
63              
64             sub OPEN {
65 8     8   19 my ($self, $path, $mode, $fh) = @_;
66              
67 8         39 my $ref = Spreadsheet::Read::ReadData($path);
68 8         182225 __PACKAGE__->sheet(_lookup_sheet_number($ref, $path));
69 5         25 $self->{rows} = [ Spreadsheet::Read::rows($ref->[__PACKAGE__->sheet]) ];
70              
71 5         381 return 1;
72             }
73             # need FDOPEN and SYSOPEN?
74              
75             sub FILL {
76 10     10 0 1258 my ($self, $fh) = @_;
77              
78 10         16 my $buf = undef;
79 10         29 while (my $row = $self->read_row()) {
80 11         22 $buf .= $row . "\n";
81 11 100       35 last if defined $/;
82             }
83 10         107 return $buf;
84             }
85              
86             {
87             my $csv = Text::CSV->new({binary => 1});
88              
89             sub read_row {
90 14     14 0 18 my ($self) = @_;
91 14         19 my $buf = undef;
92              
93 14         32 my $row_index = $self->{row} - 1;
94 14         21 my $rows = $self->{rows};
95              
96 14 100       42 if ($row_index < @$rows) {
97 11         17 my @cols = @{ $rows->[$row_index] };
  11         40  
98 11 50       62 if ($csv->combine(@cols)) {
99 11         325 $buf = $csv->string;
100             }
101              
102             # on to the next row
103 11         78 $self->{row}++;
104 11         27 $self->{col} = 1;
105             }
106              
107 14         45 return $buf;
108             }
109             }
110              
111             sub _lookup_sheet_number {
112 8     8   24 my ($ref, $path) = @_;
113              
114 8         78 my $sheet = __PACKAGE__->sheet;
115              
116 8 100       128 if ($sheet =~ /^\d+$/) {
117 6         17 my $max = $ref->[0]{sheets};
118 6 100 100     61 if ($sheet < 1 or $sheet > $max) {
119 2         17 damn "There's no worksheet '$sheet' in '$path' (numbers 1 .. $max)";
120             }
121             }
122             else {
123             # try to lookup sheet by name
124             # (does it have to be UCS2 for Excel?)
125 2 100       11 if (exists $ref->[0]{sheet}{$sheet}) {
126 1         7 __PACKAGE__->sheet($ref->[0]{sheet}{$sheet});
127             }
128             else {
129 1         7 damn "There's no worksheet '$sheet' in '$path'";
130             }
131             }
132              
133 5         26 return __PACKAGE__->sheet;
134             }
135              
136             1;
137             __END__
138              
139             =head1 NAME
140              
141             PerlIO::via::csv - PerlIO layer to convert between Excel and CSV
142              
143             =head1 SYNOPSIS
144              
145             use PerlIO::via::csv sheet => 2;
146             open my $fh, '<:via(csv)', 'file.xls'
147             or die "Can't open file.xls: $!";
148              
149             =head1 DESCRIPTION
150              
151             This module implements a PerlIO layer that converts a spreadsheet
152             (anything readable by Spreadsheet::Read, like an Excel file)
153             into comma-separated values (CSV) format. It is currently readonly.
154              
155             The spreadsheet is emulated as a stream of bytes where each cell is a byte.
156             So C<$line = readline $fh> might put C<1,2.3,foo> into $line.
157             Only one of the sheets in a multi-sheet spreadsheet is read,
158             and sheet numbers start at 1. You can also use sheet names
159             (see L</"Class methods">).
160              
161             Currently that's about it, so you're probably better off using one of the
162             xsl2csv utilities available elsewhere (see L</"SEE ALSO">).
163             I hope to support write and append modes (Spreadsheet::ParseExcel::SaveParser?)
164             and filehandle methods like seek and tell. Suggestions welcome.
165              
166             =head1 INTERFACE
167              
168             You can affect which worksheet to read with the C<sheet> class method,
169             which can also be set when you C<use> the module.
170              
171             =head2 Class methods
172              
173             =over 4
174              
175             =item sheet
176              
177             Specify which worksheet to read from. The sheet that is set when you open
178             the file will be the one read from. Use it like this:
179              
180             use PerlIO::via::csv sheet => 3;
181              
182             or
183              
184             use PerlIO::via::csv;
185             PerlIO::via::csv->sheet(3);
186              
187             Tip: try using the name of the worksheet instead of its number
188             (which starts at 1).
189              
190             If you want to read multiple sheets, set a new sheet before reopening
191             the file.
192              
193             Note: I was thinking of reading all worksheets by default; not sure
194             if that makes sense, though.
195              
196             =back
197              
198             =head1 TODO
199              
200             =over 4
201              
202             =item Dates are broken. Not sure if that's my problem or Tux's.
203              
204             =item There are probably problems with encoding.
205              
206             =item Not sure I like how sheets are handled.
207              
208             =item Other I/O operations like seek, tell, unread.
209              
210             =item Writing files.
211              
212             =back
213              
214             =head1 SEE ALSO
215              
216             L<Spreadsheet::Read|Spreadsheet::Read> (and xls2csv in the samples directory)
217              
218             L<Spreadsheet::ParseExcel|Spreadsheet::ParseExcel> (and xls2csv.pl in the
219             samples directory)
220              
221             L<http://search.cpan.org/~ken/xls2csv/script/xls2csv>
222              
223             L<Text::CSV|Text::CSV>
224              
225             =head1 AUTHORS
226              
227             Scott Lanning E<lt>slanning@cpan.orgE<gt>.
228              
229             =head1 LICENSE
230              
231             Copyright 2009, Scott Lanning.
232             This library is free software; you can redistribute it and/or modify it
233             under the same terms as Perl itself.
234              
235             =for comment
236             42
237              
238             =cut