File Coverage

lib/Spreadsheet/Reader/ExcelXML/ZipReader.pm
Criterion Covered Total %
statement 64 64 100.0
branch 8 8 100.0
condition n/a
subroutine 17 17 100.0
pod 1 2 50.0
total 90 91 98.9


line stmt bran cond sub pod time code
1             package Spreadsheet::Reader::ExcelXML::ZipReader;
2             our $AUTHORITY = 'cpan:JANDREW';
3 16     16   199332 use version; our $VERSION = version->declare('v0.16.8');
  16         1460  
  16         102  
4             ###LogSD warn "You uncovered internal logging statements for Spreadsheet::Reader::ExcelXML::ZipReader-$VERSION";
5              
6 16     16   2214 use 5.010;
  16         44  
7 16     16   469 use Moose;
  16         213145  
  16         126  
8 16     16   71262 use MooseX::StrictConstructor;
  16         20345  
  16         118  
9 16     16   36143 use MooseX::HasDefaults::RO;
  16         4865  
  16         113  
10 16         225 use Types::Standard qw(
11             HasMethods Bool Str Enum
12 16     16   54100 );#Int Num
  16         47472  
13 16     16   23867 use Archive::Zip qw( AZ_OK );
  16         640980  
  16         773  
14 16     16   6883 use Capture::Tiny qw( capture_stderr );
  16         47583  
  16         783  
15 16     16   75 use Carp 'confess';
  16         26  
  16         608  
16 16     16   76 use IO::File;
  16         20  
  16         2191  
17 16     16   86 use lib '../../../../lib',;
  16         20  
  16         136  
18             ###LogSD with 'Log::Shiras::LogSpace';
19             ###LogSD use Log::Shiras::Telephone;
20              
21 16     16   2206 use Spreadsheet::Reader::ExcelXML::Types qw( IOFileType );
  16         25  
  16         277  
22              
23             #########1 Public Attributes 3#########4#########5#########6#########7#########8#########9
24              
25             has file =>(
26             isa => IOFileType,
27             reader => 'get_file',
28             writer => 'set_file',
29             predicate => 'has_file',
30             clearer => 'clear_file',
31             coerce => 1,
32             trigger => \&_build_zip_reader,
33             handles => [ 'close' ],
34             );
35              
36             has file_type =>(
37             isa => Enum[ 'zip' ],
38             reader => 'get_file_type',
39             default => 'zip',
40             );
41              
42             has workbook_inst =>(
43             isa => 'Spreadsheet::Reader::ExcelXML::Workbook',
44             handles =>[ qw( set_error )],
45             writer => 'set_workbook_inst',
46             );
47              
48             #########1 Public Methods 3#########4#########5#########6#########7#########8#########9
49              
50             sub extract_file{
51 106     106 1 1040 my ( $self, $file ) = ( @_ );
52             ###LogSD my $phone = Log::Shiras::Telephone->new( name_space =>
53             ###LogSD $self->get_all_space . '::extract_file', );
54             ###LogSD $phone->talk( level => 'trace', message =>[
55             ###LogSD 'Arrived at extract_file for the workbook general settings:', $file ] );
56 106         540 my $zip_member = $self->_member_named( $file );
57             ###LogSD $phone->talk( level => 'debug', message =>[ 'zip member:', $zip_member ] );
58 106 100       6074 if( $zip_member ){
59 105         20232 my $workbook_fh = IO::File->new_tmpfile;
60 105         676 $workbook_fh->binmode();
61 105         1316 $zip_member->extractToFileHandle( $workbook_fh );
62 105         91065 $workbook_fh->seek( 0, 0 );
63             ###LogSD $phone->talk( level => 'debug', message =>[
64             ###LogSD 'succesfully built the zip sub file:', $workbook_fh ] );
65 105         4396 return $workbook_fh;
66             }else{
67             ###LogSD $phone->talk( level => 'debug', message =>[ "no zip file for: $file" ] );
68 1         3 return undef;
69             }
70             }
71              
72             #########1 Private Attributes 3#########4#########5#########6#########7#########8#########9
73              
74             has _loaded =>(
75             isa => Bool,
76             writer => '_good_load',
77             reader => 'loaded_correctly',
78             default => 0,
79             );
80              
81             has _zip_reader =>(
82             isa => 'Archive::Zip',
83             reader => '_get_zip_parser',
84             writer => '_set_zip_parser',
85             predicate => '_has_zip_parser',
86             clearer => '_clear_zip_parser',
87             handles =>{
88             _member_named => 'memberNamed',
89             },
90             );
91              
92             has _read_unique_bits =>(
93             isa => Bool,
94             reader => '_get_unique_bits',
95             writer => '_need_unique_bits',
96             clearer => '_clear_read_unique_bits',
97             default => 1,
98             );
99              
100             #########1 Private Methods 3#########4#########5#########6#########7#########8#########9
101              
102             sub _build_zip_reader{
103 21     21   557 my( $self, $file ) = @_;
104             ###LogSD my $phone = Log::Shiras::Telephone->new( name_space =>
105             ###LogSD $self->get_all_space . '::ZipReader::_build_zip_reader', );
106             ###LogSD $phone->talk( level => 'debug', message => [
107             ###LogSD "turning a file handle into a zip reader", $file, ] );
108              
109             # Read the XLSX zip file and catch any errors (other zip file sanity tests go here)
110 21         172 my $workbook_file = Archive::Zip->new();
111 21         661 my $read_state;
112 21         156 $file->seek( 0, 0 );# Reset in case an XML read attempt was made
113 21     21   669 my $error_message = capture_stderr{ $read_state = $workbook_file->readFromFileHandle($file) };
  21         1618551  
114             ###LogSD $phone->talk( level => 'debug', message => [
115             ###LogSD "Error message is:", $error_message ] );
116 21 100       49589 if( $read_state != AZ_OK ){
117             ###LogSD $phone->talk( level => 'warn', message =>[
118             ###LogSD "Failed to open the file as a zip file" ] );
119 3         32 $self->set_error( "|$file| won't open as a zip file because: $error_message" );
120 3         79 $self->clear_file;
121 3         79 $self->_clear_zip_parser;
122             }else{
123             ###LogSD $phone->talk( level => 'debug', message =>[
124             ###LogSD "Certified this as a zip file" ] );
125 18         915 $self->_set_zip_parser( $workbook_file );
126 18         561 $self->_good_load( 1 );
127             }
128             }
129              
130             sub DEMOLISH{
131 20     20 0 4312 my ( $self ) = @_;
132             ###LogSD my $phone = Log::Shiras::Telephone->new( name_space =>
133             ###LogSD $self->get_all_space . '::ZipReader::DEMOLISH', );
134             ###LogSD $phone->talk( level => 'debug', message => [
135             ###LogSD "clearing the zip reader for log space:", $self->get_log_space, ] );
136              
137             # Clear the reader
138 20 100       675 if( $self->_has_zip_parser ){
139             ###LogSD $phone->talk( level => 'debug', message =>[ "Clearing the zip parser", ] );
140 17         481 $self->_clear_zip_parser;
141             }
142              
143             # Clear the file
144 20 100       590 if( $self->has_file ){
145             ###LogSD $phone->talk( level => 'debug', message =>[ "Closing and disconnecting the file handle for the zip parser", ] );
146 17         459 $self->clear_file;
147             }
148             }
149              
150             #########1 Phinish 3#########4#########5#########6#########7#########8#########9
151              
152 16     16   17631 no Moose;
  16         26  
  16         134  
153              
154             1;
155              
156             #########1 Documentation 3#########4#########5#########6#########7#########8#########9
157             __END__
158              
159             =head1 NAME
160              
161             Spreadsheet::Reader::ExcelXML::ZipReader - Base Zip file reader
162              
163             =head1 SYNOPSIS
164              
165             #!/usr/bin/env perl
166             use MooseX::ShortCut::BuildInstance qw( build_instance );
167             use lib '../../../../lib';
168             use Spreadsheet::Reader::ExcelXML::ZipReader;
169             use Spreadsheet::Reader::ExcelXML::WorkbookFileInterface;
170             my $test_file = '../../../../t/test_files/TestBook.xlsx';
171             my $test_instance = build_instance(
172             package => 'WorkbookFileInterface',
173             superclasses => ['Spreadsheet::Reader::ExcelXML::ZipReader'],
174             add_roles_in_sequence =>[
175             'Spreadsheet::Reader::ExcelXML::WorkbookFileInterface',
176             ],
177             file => $test_file,
178             );
179             my $sub_file = $test_instance->extract_file( 'xl/workbook.xml' );
180             print $sub_file->getline;
181              
182             ##############################################################
183             # SYNOPSIS Screen Output
184             # 01: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
185             ##############################################################
186              
187             =head1 DESCRIPTION
188              
189             This documentation is written to explain ways to use this module when writing your own
190             excel parser. To use the general package for excel parsing out of the box please review
191             the documentation for L<Workbooks|Spreadsheet::Reader::ExcelXML>,
192             L<Worksheets|Spreadsheet::Reader::ExcelXML::Worksheet>, and
193             L<Cells|Spreadsheet::Reader::ExcelXML::Cell>
194              
195             This module provides a way to open a zip file or file handle and then extract sub files.
196             This package uses L<Archive::Zip>. Not all versions of Archive::Zip work for everyone.
197             I have tested this with Archive::Zip 1.30. Please let me know if this does not work with
198             a sucessfully installed (read passed the full test suit) version of Archive::Zip newer
199             than that.
200              
201             =head2 Attributes
202              
203             Data passed to new when creating an instance. For modification of these attributes see
204             the listed 'attribute methods'. For general information on attributes see
205             L<Moose::Manual::Attributes>. For ways to manage the instance when opened see the
206             L<Methods|/Methods>.
207              
208             =head3 file
209              
210             =over
211              
212             B<Definition:> This attribute holds the file handle for the file being read. If the full
213             file name and path is passed to the attribute it is coerced to an IO::File file handle.
214             This file handle will be expected to pass the test
215              
216             B<Default:> no default - this must be provided to read a file
217              
218             B<Required:> yes
219              
220             B<Range:> any Zip file name and path or IO::File file handle for a zip file
221              
222             B<attribute methods> Methods provided to adjust this attribute
223              
224             =over
225              
226             B<set_file>
227              
228             =over
229              
230             B<Definition:> change the file value in the attribute (this will reboot
231             the file instance and lock the file)
232              
233             =back
234              
235             B<get_file>
236              
237             =over
238              
239             B<Definition:> Returns the file handle of the file even if a file name
240             was passed
241              
242             =back
243              
244             B<has_file>
245              
246             =over
247              
248             B<Definition:> this is used to see if the file loaded correctly.
249              
250             =back
251              
252             B<clear_file>
253              
254             =over
255              
256             B<Definition:> this clears (and unlocks) the file handle
257              
258             =back
259              
260             =back
261              
262             B<Delegated Methods>
263              
264             =over
265              
266             L<close|IO::Handle/$io-E<gt>close>
267              
268             =over
269              
270             closes the file handle
271              
272             =back
273              
274             =back
275              
276             =back
277              
278             =head3 file_type
279              
280             =over
281              
282             B<Definition:> This stores the file type for this file. The type defaults to 'zip'
283             for this reader.
284              
285             B<Default:> zip
286              
287             B<Range:> 'zip'
288              
289             B<attribute methods> Methods provided to adjust this attribute
290              
291             =over
292              
293             B<get_file_type>
294              
295             =over
296              
297             B<Definition:> returns the attribute value
298              
299             =back
300              
301             =back
302              
303             =back
304              
305             =head3 workbook_inst
306              
307             =over
308              
309             B<Definition:> This attribute holds a reference to the top level workbook (parser).
310             The purpose is to use some of the methods provided there.
311              
312             B<Default:> no default
313              
314             B<Required:> not strictly for this class but the attribute is provided to give
315             self referential access to general workbook settings and methods for composed
316             classes that inherit this a base class.
317              
318             B<Range:> isa => 'Spreadsheet::Reader::ExcelXML::Workbook'
319              
320             B<attribute methods> Methods provided to adjust this attribute
321              
322             =over
323              
324             B<set_workbook_inst>
325              
326             =over
327              
328             set the attribute with a workbook instance
329              
330             =back
331              
332             =back
333              
334             B<Delegated Methods (required)> Methods delegated to this module by the
335             attribute. All methods are delegated with the method name unchanged.
336             Follow the link to review documentation of the provider for each method.
337             As you can see several are delegated through the Workbook level and
338             don't originate there.
339              
340             =over
341              
342             L<Spreadsheet::Reader::ExcelXML::Error/set_error( $error_string )>
343              
344             =back
345              
346             =back
347              
348             =head2 Methods
349              
350             These are the methods provided by this class.
351              
352             =head3 extract_file( $zip_sub_file )
353              
354             =over
355              
356             B<Definition:> This will pull a subfile from the zipped package using the Archive::Zip
357             method L<memberNamed|Archive::Zip/Zip Archive Accessors> and load it to a new
358             'IO::File->new_tmpfile' file handle.
359              
360             B<Accepts:> $zip_sub_file compliant with the Archive::Zip method 'memberNamed'
361              
362             B<Returns:> an IO::File handle loaded with the extracted target sub file for reading
363              
364             =back
365              
366             =head3 loaded_correctly
367              
368             =over
369              
370             B<Definition:> This will indicate if the zip reader was able to open the base file
371             with Archive::Zip as a zip file.
372              
373             B<Accepts:> nothing
374              
375             B<Returns:> (1|0) 1 = good file
376              
377             =back
378              
379             =head1 SUPPORT
380              
381             =over
382              
383             L<github Spreadsheet::Reader::ExcelXML/issues
384             |https://github.com/jandrew/p5-spreadsheet-reader-excelxml/issues>
385              
386             =back
387              
388             =head1 TODO
389              
390             =over
391              
392             B<1.> Nothing currently
393              
394             =back
395              
396             =head1 AUTHOR
397              
398             =over
399              
400             =item Jed Lund
401              
402             =item jandrew@cpan.org
403              
404             =back
405              
406             =head1 COPYRIGHT
407              
408             This program is free software; you can redistribute
409             it and/or modify it under the same terms as Perl itself.
410              
411             The full text of the license can be found in the
412             LICENSE file included with this module.
413              
414             This software is copyrighted (c) 2016 by Jed Lund
415              
416             =head1 DEPENDENCIES
417              
418             =over
419              
420             L<Spreadsheet::Reader::ExcelXML> - the package
421              
422             =back
423              
424             =head1 SEE ALSO
425              
426             =over
427              
428             L<Spreadsheet::Read> - generic Spreadsheet reader
429              
430             L<Spreadsheet::ParseExcel> - Excel binary version 2003 and earlier (.xls files)
431              
432             L<Spreadsheet::XLSX> - Excel version 2007 and later
433              
434             L<Spreadsheet::ParseXLSX> - Excel version 2007 and later
435              
436             L<Log::Shiras|https://github.com/jandrew/Log-Shiras>
437              
438             =over
439              
440             All lines in this package that use Log::Shiras are commented out
441              
442             =back
443              
444             =back
445              
446             =cut
447              
448             #########1#########2 main pod documentation end 5#########6#########7#########8#########9