File Coverage

blib/lib/Spreadsheet/Reader/Format/FmtDefault.pm
Criterion Covered Total %
statement 42 44 95.4
branch 13 18 72.2
condition 1 3 33.3
subroutine 10 10 100.0
pod 3 3 100.0
total 69 78 88.4


line stmt bran cond sub pod time code
1             package Spreadsheet::Reader::Format::FmtDefault;
2             our $AUTHORITY = 'cpan:JANDREW';
3 3     3   4297058 use version; our $VERSION = version->declare('v0.6.4');
  3         79  
  3         33  
4             #~ use Log::Shiras::Unhide qw( :debug );
5             ###LogSD warn "You uncovered internal logging statements for Spreadsheet::Reader::Format::FmtDefault-$VERSION";
6              
7 3     3   402 use 5.010;
  3         12  
8 3     3   16 use Moose;
  3         6  
  3         28  
9 3     3   22443 use Carp 'confess';
  3         7  
  3         197  
10 3     3   2007 use Encode qw(decode);
  3         31182  
  3         244  
11 3     3   725 use Types::Standard qw( HashRef Str is_ArrayRef is_HashRef is_StrictNum );#
  3         78981  
  3         31  
12             ###LogSD use Log::Shiras::Telephone;
13             ###LogSD with 'Log::Shiras::LogSpace';
14              
15             #########1 Dispatch Tables 3#########4#########5#########6#########7#########8#########9
16              
17              
18              
19             #########1 Public Attributes 3#########4#########5#########6#########7#########8#########9
20              
21             has excel_region =>(
22             isa => Str,
23             default => 'en',
24             reader => 'get_excel_region',
25             writer => 'set_excel_region',
26             );
27              
28             has target_encoding =>(
29             isa => Str,
30             reader => 'get_target_encoding',
31             writer => 'set_target_encoding',
32             predicate => 'has_target_encoding',
33             );
34              
35             has defined_excel_translations =>(
36             isa => HashRef,
37             traits => ['Hash'],
38             default => sub{ {
39             0x00 => 'General',
40             0x01 => '0',
41             0x02 => '0.00',
42             0x03 => '#,##0',
43             0x04 => '#,##0.00',
44             0x05 => '$#,##0_);($#,##0)',
45             0x06 => '$#,##0_);[Red]($#,##0)',
46             0x07 => '$#,##0.00_);($#,##0.00)',
47             0x08 => '$#,##0.00_);[Red]($#,##0.00)',
48             0x09 => '0%',
49             0x0A => '0.00%',
50             0x0B => '0.00E+00',
51             0x0C => '# ?/?',
52             0x0D => '# ??/??',
53             0x0E => 'yyyy-mm-dd', # Was 'm-d-yy', which is bad as system default
54             0x0F => 'd-mmm-yy',
55             0x10 => 'd-mmm',
56             0x11 => 'mmm-yy',
57             0x12 => 'h:mm AM/PM',
58             0x13 => 'h:mm:ss AM/PM',
59             0x14 => 'h:mm',
60             0x15 => 'h:mm:ss',
61             0x16 => 'm-d-yy h:mm',
62             0x1F => '#,##0_);(#,##0)',
63             0x20 => '#,##0_);[Red](#,##0)',
64             0x21 => '#,##0.00_);(#,##0.00)',
65             0x22 => '#,##0.00_);[Red](#,##0.00)',
66             0x23 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)',
67             0x24 => '_($*#,##0_);_($*(#,##0);_($*"-"_);_(@_)',
68             0x25 => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)',
69             0x26 => '_($*#,##0.00_);_($*(#,##0.00);_($*"-"??_);_(@_)',
70             0x27 => 'mm:ss',
71             0x28 => '[h]:mm:ss',
72             0x29 => 'mm:ss.0',
73             0x2A => '##0.0E+0',
74             0x2B => '@',
75             0x31 => '@',
76             } },
77             handles =>{
78             _get_defined_excel_format => 'get',
79             _set_defined_excel_format => 'set',
80             total_defined_excel_formats => 'count',
81             },
82             );
83              
84             #########1 Public Methods 3#########4#########5#########6#########7#########8#########9
85              
86             sub get_defined_excel_format{
87 187     187 1 44506 my ( $self, $position, ) = @_;
88             ###LogSD my $phone = Log::Shiras::Telephone->new( name_space =>
89             ###LogSD $self->get_all_space . '::get_defined_excel_format', );
90             ###LogSD $phone->talk( level => 'info', message => [
91             ###LogSD "Getting the defined excel format for position: $position", ] );
92 187 100       816 my $int_value = ( $position =~ /0x/ ) ? hex( $position ) : $position;
93             ###LogSD $phone->talk( level => 'info', message => [
94             ###LogSD "..after int conversion: $int_value", ] );
95 187         10524 return $self->_get_defined_excel_format( $int_value );
96             }
97              
98             sub set_defined_excel_formats{
99 2     2 1 6 my ( $self, @args, ) = @_;
100             ###LogSD my $phone = Log::Shiras::Telephone->new( name_space =>
101             ###LogSD $self->get_all_space . '::set_defined_excel_format', );
102             ###LogSD $phone->talk( level => 'info', message => [
103             ###LogSD "Setting defined excel formats" ] );
104             ###LogSD $phone->talk( level => 'trace', message => [
105             ###LogSD "..from the list: ", @args, ] );
106 2         5 my $position_ref;
107 2 50 33     10 if( @args > 1 and @args % 2 == 0 ){
108 0         0 $position_ref = { @args };
109             }else{
110 2         5 $position_ref = $args[0];
111             }
112 2 100       8 if( is_ArrayRef( $position_ref ) ){
    50          
113 1         7 my $x = -1;
114 1         5 for my $format_string ( @$position_ref ){
115 24         33 $x++;
116 24 100       55 next if !defined $format_string;
117             ###LogSD $phone->talk( level => 'info', message => [
118             ###LogSD "Setting position -$x- to format string: $format_string", ] );
119 1         62 $self->_set_defined_excel_format( $x => $format_string );
120             }
121             }elsif( is_HashRef( $position_ref ) ){
122 1         17 for my $key ( keys %$position_ref ){
123             ###LogSD $phone->talk( level => 'info', message => [
124             ###LogSD "Setting the defined excel format for position -$key- to : ", $position_ref->{$key}, ] );
125 1 50       7 my $int_value = ( $key =~ /0x/ ) ? hex( $key ) : $key;
126 1 50       6 confess "The key -$key- must translate to a number!" if !is_StrictNum( $int_value );
127             ###LogSD $phone->talk( level => 'info', message => [
128             ###LogSD "Initial -$key- translated to position: " . $int_value, ] );
129 1         66 $self->_set_defined_excel_format( $int_value => $position_ref->{$key} );
130             }
131             }else{
132 0         0 confess "Unrecognized format passed: " . join( '~|~', @$position_ref );
133             }
134 2         11 return 1;
135             }
136              
137             sub change_output_encoding{
138 2     2 1 6 my ( $self, $string, ) = @_;
139 2 50       8 return undef if !defined $string;
140             ###LogSD my $phone = Log::Shiras::Telephone->new( name_space =>
141             ###LogSD $self->get_all_space . '::change_output_encoding', );
142             ###LogSD $phone->talk( level => 'info', message => [
143             ###LogSD "Changing the encoding of: $string",
144             ###LogSD ($self->has_target_encoding ? ('..to encoding type: ' . $self->get_target_encoding) : ''), ] );
145 2 100       99 my $output = $self->has_target_encoding ? decode( $self->get_target_encoding, $string ) : $string;
146             ###LogSD $phone->talk( level => 'info', message => [
147             ###LogSD "Final output: $output", ] );
148 2         81 return $output;
149             }
150              
151             #########1 Private Attributes 3#########4#########5#########6#########7#########8#########9
152              
153              
154              
155             #########1 Private Methods 3#########4#########5#########6#########7#########8#########9
156              
157              
158              
159             #########1 Phinish 3#########4#########5#########6#########7#########8#########9
160              
161 3     3   4809 no Moose;
  3         22  
  3         30  
162             __PACKAGE__->meta->make_immutable;
163              
164             1;
165              
166             #########1 Documentation 3#########4#########5#########6#########7#########8#########9
167             __END__
168              
169             =head1 NAME
170              
171             Spreadsheet::Reader::Format::FmtDefault - Default number and string formats
172              
173             =head1 SYNOPSIS
174              
175             #!/usr/bin/env perl
176             use Spreadsheet::Reader::Format::FmtDefault;
177             my $formatter = Spreadsheet::Reader::Format::FmtDefault->new(
178             target_encoding => 'latin1',
179             epoch_year => 1904,
180             );
181             my $excel_format_string = $formatter->get_defined_excel_format( 0x0E );
182             print $excel_format_string . "\n";
183             $excel_format_string = $formatter->get_defined_excel_format( '0x0E' );
184             print $excel_format_string . "\n";
185             $excel_format_string = $formatter->get_defined_excel_format( 14 );
186             print $excel_format_string . "\n";
187             $formatter->set_defined_excel_formats( '0x17' => 'MySpecialFormat' );#Won't really translate!
188             $excel_format_string = $formatter->get_defined_excel_format( 23 );
189             print $excel_format_string . "\n";
190              
191             ###########################
192             # SYNOPSIS Screen Output
193             # 01: yyyy-mm-dd
194             # 02: yyyy-mm-dd
195             # 03: yyyy-mm-dd
196             # 04: MySpecialFormat
197             ###########################
198              
199             =head1 DESCRIPTION
200              
201             This is the default localization class used by L<Spreadsheet::Reader::Format>. It is
202             separate from the other parts of the formatter class to isolate the basic elements of
203             localization to allow for the least work swapping it out. This class can be configured
204             or adjused without replacing it or you can use it as a template for a new localization.
205             To use the class as it stands just adjust the attributes to change the outcome of the
206             methods. If you re-write this class it is used as a base class and must provide the
207             same methods.
208              
209             This class provides two basic functionalities. First, it stores and can retreive defined
210             excel format strings. Excel uses these (common) formats to assign conversions to various
211             cells in the sheet rather than storing a conversion string. Specifically these are the
212             conversions provided to Excel end users in the pull down menu if they do not want to
213             write their own custom conversion strings. This specific class represents the standard
214             set of parsing strings localized for the United States found in Excel. There is one
215             exception where position 14 (0x0E) is different than the Excel implementation since the
216             Excel setting for that position breaks so many database data types. Where excel users
217             have written their own custom conversion definition strings they are stored in the
218             L<Styles|Spreadsheet::Reader::ExcelXML::Styles> file of the zipped archive. These strings
219             are implemented by a parsing engine to convert raw values to formatted values. The rules
220             for these conversions are layed out in L<the Excel documentation
221             |https://support.office.com/en-us/article/Create-or-delete-a-custom-number-format-78f2a361-936b-4c03-8772-09fab54be7f4>.
222             The default implementation of these rules is done in
223             L<Spreadsheet::Reader::Format::ParseExcelFormatStrings>. The second
224             functionality is string decoding. It is assumed that any file encoding is handled by
225             the Excel file reader. However, once the file has been read into memory you may wish
226             to decode it to some specific output format. The attribute L<target_encoding
227             |/target_encoding> and the method L<change_output_encoding|/change_output_encoding( $string )>
228             use L<Encode> to do this.
229              
230             For an explanation of functionality for a fully built Formatter class see the
231             documentation for L<Spreadsheet::Reader::Format>.
232              
233             =head2 Attributes
234              
235             Data passed to new when creating an instance containing this class. For modification
236             of these attributes see the listed 'attribute methods' and L<Methods|/Methods>. For
237             more information on attributes see L<Moose::Manual::Attributes>.
238              
239             =head3 excel_region
240              
241             =over
242              
243             B<Definition:> This records the target region of this localization role (Not the region of the
244             Excel workbook being parsed). It's mostly a reference value.
245              
246             B<Default:> en = english
247              
248             B<Attribute required:> no
249              
250             B<attribute methods> Methods provided to adjust this attribute
251              
252             =over
253              
254             B<get_excel_region>
255              
256             =over
257              
258             B<Definition:> returns the value of the attribute (en)
259              
260             =back
261              
262             B<set_excel_region( $region )>
263              
264             =over
265              
266             B<Definition:> sets the value of the attribute.
267              
268             =back
269              
270             =back
271              
272             =back
273              
274             =head3 target_encoding
275              
276             =over
277              
278             B<Definition:> This is the target output encoding. If it is not defined the string
279             transformation step L<change_output_encoding|/change_output_encoding( $string )> becomes a
280             passthrough. When the value is loaded it is used as a 'decode' target by L<Encode>
281             to transform the internally (unicode) stored perl string to some target 'output'
282             formatting.
283              
284             B<Attribute required:> no
285              
286             B<Default:> none
287              
288             B<Range:> Any encoding recognized by L<Encode|Encode/Listing available encodings>
289             (No type certification is done)
290              
291             B<attribute methods> Methods provided to adjust this attribute
292              
293             =over
294              
295             B<set_target_encoding( $encoding )>
296              
297             =over
298              
299             B<Definition:> This should be recognized by L<Encode/Listing available encodings>
300             I<no testing of this compatability is done>
301              
302             =back
303              
304             B<get_target_encoding>
305              
306             =over
307              
308             B<Definition:> Returns the currently set attribute value
309              
310             =back
311              
312             B<has_target_encoding>
313              
314             =over
315              
316             B<Definition:> Returns positive if the target_encoding has been set
317              
318             =back
319              
320             =back
321              
322             =back
323              
324             =head3 defined_excel_translations
325              
326             =over
327              
328             B<Definition:> In Excel part of localization is the way numbers are displayed.
329             Excel manages that with a default list of format strings that make the numbers appear
330             in a familiar way. These are the choices provided in the pull down menu for formats
331             if you did not want to write your own custom format string. This is where you store
332             that list for this package. In this case the numbers are stored as hash key => value
333             pairs where the keys are array positions (written in hex) and the values are the Excel
334             readable format strings (definitions). Beware that if you change the list your
335             parser may break if you don't supply replacements for all the values in the default
336             list. If you just want to replace some of the values use the method
337             L<set_defined_excel_formats|/set_defined_excel_formats( %args )>.
338              
339             B<Attribute required:> yes
340              
341             B<Default:>
342              
343             {
344             0x00 => 'General',
345             0x01 => '0',
346             0x02 => '0.00',
347             0x03 => '#,##0',
348             0x04 => '#,##0.00',
349             0x05 => '$#,##0_);($#,##0)',
350             0x06 => '$#,##0_);[Red]($#,##0)',
351             0x07 => '$#,##0.00_);($#,##0.00)',
352             0x08 => '$#,##0.00_);[Red]($#,##0.00)',
353             0x09 => '0%',
354             0x0A => '0.00%',
355             0x0B => '0.00E+00',
356             0x0C => '# ?/?',
357             0x0D => '# ??/??',
358             0x0E => 'yyyy-mm-dd', # Was 'm-d-yy', which is bad as system default
359             0x0F => 'd-mmm-yy',
360             0x10 => 'd-mmm',
361             0x11 => 'mmm-yy',
362             0x12 => 'h:mm AM/PM',
363             0x13 => 'h:mm:ss AM/PM',
364             0x14 => 'h:mm',
365             0x15 => 'h:mm:ss',
366             0x16 => 'm-d-yy h:mm',
367             0x1F => '#,##0_);(#,##0)',
368             0x20 => '#,##0_);[Red](#,##0)',
369             0x21 => '#,##0.00_);(#,##0.00)',
370             0x22 => '#,##0.00_);[Red](#,##0.00)',
371             0x23 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)',
372             0x24 => '_($*#,##0_);_($*(#,##0);_($*"-"_);_(@_)',
373             0x25 => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)',
374             0x26 => '_($*#,##0.00_);_($*(#,##0.00);_($*"-"??_);_(@_)',
375             0x27 => 'mm:ss',
376             0x28 => '[h]:mm:ss',
377             0x29 => 'mm:ss.0',
378             0x2A => '##0.0E+0',
379             0x2B => '@',
380             0x31 => '@',
381             }
382              
383             B<Range:> Any hashref of formats recognized by
384             L<Spreadsheet::Reader::Format::ParseExcelFormatStrings>
385              
386             B<attribute methods> Methods provided to by the attribute to adjust it.
387              
388             =over
389              
390             B<total_defined_excel_formats>
391              
392             =over
393              
394             B<Definition:> get the count of the current key => value pairs
395              
396             =back
397              
398             See L<get_defined_excel_format|/get_defined_excel_format( $position )> and
399             L<set_defined_excel_formats|/set_defined_excel_formats( %args )>
400              
401             =back
402              
403             =back
404              
405             =head2 Methods
406              
407             These are methods to use this class. For additional FmtDefault options see the
408             L<Attributes|/Attributes> section.
409              
410             =head3 get_defined_excel_format( $position )
411              
412             =over
413              
414             B<Definition:> This will return the preset excel format string for the stored position
415             from the attribute L<defined_excel_translations|/defined_excel_translations>.
416             The positions are actually stored in a hash where the keys are integers representing a
417             position in an order list.
418              
419             B<Accepts:> an integer or an octal number or octal string for the format string
420             $position
421              
422             B<Returns:> an excel format string (not a built coercion)
423              
424             =back
425              
426             =head3 set_defined_excel_formats( %args )
427              
428             =over
429              
430             B<Definition:> This will set the excel format strings for the indicated positions
431             in the attribute L<defined_excel_translations|/defined_excel_translations>.
432              
433             B<Accepts:> a Hash list, a hash ref (both with keys representing positions), or an arrayref
434             of strings with the update strings in the target position. All passed argument B<lists> greater
435             than one will be assumed to be hash arguments and must come in pairs. If a single argument is
436             passed then that value is checked to see if it is a hashref or an arrayref. For passed
437             arrayrefs all empty positions are ignored meaning that any preexisting value in that positions
438             is left in force. To erase the default value send '@' (passthrough) as the format string for
439             that position. This function does not do any string validation. The validation is done when
440             the coercion is generated.
441              
442             B<Returns:> 1 for success
443              
444             =back
445              
446             =head3 change_output_encoding( $string )
447              
448             =over
449              
450             B<Definition:> This should be called on the output string prior to performing any
451             coercion.
452              
453             B<Accepts:> a perl unicode coded string
454              
455             B<Returns:> the converted $string decoded to the L<defined format|/target_encoding>
456              
457             =back
458              
459             =head1 SUPPORT
460              
461             =over
462              
463             L<github Spreadsheet::Reader::Format/issues
464             |https://github.com/jandrew/p5-spreadsheet-reader-format/issues>
465              
466             =back
467              
468             =head1 TODO
469              
470             =over
471              
472             Nothing L<yet|/SUPPORT>.
473              
474             =back
475              
476             =head1 AUTHOR
477              
478             =over
479              
480             Jed Lund
481              
482             jandrew@cpan.org
483              
484             =back
485              
486             =head1 COPYRIGHT
487              
488             This program is free software; you can redistribute
489             it and/or modify it under the same terms as Perl itself.
490              
491             The full text of the license can be found in the
492             LICENSE file included with this module.
493              
494             This software is copyrighted (c) 2016 by Jed Lund
495              
496             =head1 DEPENDENCIES
497              
498             =over
499              
500             L<Spreadsheet::Reader::Format>
501              
502             =back
503              
504             =head1 SEE ALSO
505              
506             =over
507              
508             L<Spreadsheet::ParseExcel> - Excel 2003 and earlier
509              
510             L<Spreadsheet::XLSX> - 2007+
511              
512             L<Spreadsheet::ParseXLSX> - 2007+
513              
514             L<Log::Shiras|https://github.com/jandrew/Log-Shiras>
515              
516             =over
517              
518             All lines in this package that use Log::Shiras are commented out
519              
520             =back
521              
522             =back
523              
524             =cut
525              
526             #########1#########2 main pod documentation end 5#########6#########7#########8#########9