File Coverage

blib/lib/Locale/CLDR/Lite.pm
Criterion Covered Total %
statement 15 102 14.7
branch 0 44 0.0
condition 0 12 0.0
subroutine 5 9 55.5
pod n/a
total 20 167 11.9


line stmt bran cond sub pod time code
1             package Locale::CLDR::Lite;
2            
3 1     1   24814 use strict;
  1         3  
  1         44  
4 1     1   5 use warnings;
  1         3  
  1         29  
5 1     1   5 use Carp;
  1         14  
  1         77  
6 1     1   1008 use File::ShareDir ':ALL';
  1         9684  
  1         246  
7 1     1   11 use vars qw( $AUTOLOAD $VERSION );
  1         3  
  1         1779  
8            
9             require XML::Simple;
10             my $xml = XML::Simple->new();
11            
12            
13             =head1 NAME
14            
15             Locale::CLDR::Lite - Simple access to the Unicode Common Locale Data Repository
16            
17             =head1 VERSION
18            
19             Version 0.01_02
20            
21             =cut
22            
23             $VERSION = '0.01_02';
24            
25            
26             =head1 SYNOPSIS
27            
28             NOTE: This is considered alpha code. Interface may well be subject to complete
29             change. I'm open to suggestions.
30            
31             This module aims to be very light, providing accessor methods to CLDR data and
32             managing the LDML inheritence model.
33            
34             use Locale::CLDR::Lite;
35            
36             my $locale = Locale::CLDR::Lite->new( 'en_GB' );
37             my $decimal = $locale->get->numbers->symbols->decimal(); # returns .
38             my $decimal = $locale->get->dates->calendars->calendar(type => 'gregorian')->
39             dateFormats->dateFormatLength(type => 'full')->dateFormat->pattern();
40             # returns EEEE, d MMMM y
41            
42            
43             =head1 METHODS
44            
45             =head2 new
46            
47             Create a new accessor object from a given language tag.
48            
49             =cut
50            
51             sub new {
52 0     0     my ( $class, $lang ) = @_;
53 0 0         croak( 'You must pass a language tag' ) unless $lang;
54            
55             ## Validate tag
56 0 0         croak( 'Language tags contain invalid characters' ) unless $lang =~ /^([a-z]+)(_[a-z]+)?(_[a-z]+)?$/i;
57            
58             # Clean case
59 0           my $type = 'lang';
60 0           $lang = lc($1);
61 0 0 0       if ( $2 && $3 ) {
    0 0        
    0          
62 0           $lang .= lc $2 . uc $3;
63 0           $type = 'lang_script_region';
64             }
65             elsif ( $2 && length $2 > 3 ) {
66 0           $lang .= lc $2;
67 0           $type = 'lang_script';
68             }
69             elsif ( $2 ) {
70 0           $lang .= uc $2;
71 0           $type = 'lang_region';
72             }
73            
74 0           my $self = {
75             lang => $lang,
76             };
77             # We need to know where we are in order to get to the data files
78             #( my $path = $INC{'Locale/CLDR/Lite.pm'} ) =~ s/\.pm$//;
79 0           my $path = dist_dir('Locale-CLDR-Lite');
80 0           my @data_files;
81 0           while ( $lang ) {
82 0 0         if ( -e "$path/common/main/$lang.xml" ) {
83 0           push( @data_files, $lang );
84             }
85             else {
86 0           warn( "No match for $lang, looking down inheritance" );
87             }
88 0 0         $lang = '' unless $lang =~ s/_\w+$//;
89             }
90 0 0         croak( "Could not match language $_[1]" ) unless @data_files;
91 0           $self->{files} = \@data_files;
92 0           $self->{path} = "$path/common/main";
93            
94 0           return bless $self, $class;
95             }
96            
97            
98             =head2 get
99            
100             Get must be called first whenever you want to start a new request navigating
101             from a base node.
102            
103             =cut
104            
105             sub get {
106 0     0     my $self = shift;
107 0 0         croak( 'You can only call get on the base object' ) if ref $self->{node};
108 0           my %clone = %$self;
109 0           $clone{node} = [];
110 0           return bless \%clone, ref $self;
111             }
112            
113            
114             =head2 generated on the fly
115            
116             This script generates accessors as you use them. At this time it provides no
117             validation other than to return undef if your requested tree node doesn't exist.
118             Go to L for details of the
119             locale XML data structure.
120            
121             =cut
122            
123             sub AUTOLOAD {
124 0     0     my $current = shift;
125 0           my ( $attr, $value ) = @_;
126 0 0         croak( 'You must call the get method first' ) unless ref $current->{node};
127 0           $AUTOLOAD =~ m/([^:]*)$/;
128            
129             # Based on the current node
130 0           my $new = {
131             %$current,
132             name => $1,
133             attr => $attr,
134             value => $value,
135             };
136 0           bless $new, ref $current;
137            
138             # Validate new node
139 0           my $found;
140 0           foreach my $file ( @{ $new->{files} }, 'root' ) {
  0            
141 0           my $locale;
142 0 0         if ( $new->{cache}->{$file} ) {
143 0           $locale = $new->{cache}->{$file};
144             }
145             else {
146 0           open( my $INF, "$new->{path}/$file.xml" );
147 0           $locale = $xml->XMLin( $INF );
148 0           close( $INF );
149 0           $new->{cache}->{$file} = $locale;
150             }
151 0           my $branch = $locale;
152 0           $found = 1;
153 0           my $pos = -1;
154 0           foreach my $node ( @{ $current->{node} }, $new ) {
  0            
155 0           $pos++;
156 0 0         if ( ref $branch->{ $node->{name} } ) {
    0          
157 0           $branch = $branch->{ $node->{name} };
158 0 0         if ( $node->{attr} ) {
    0          
159 0 0         if ( ref $branch eq 'HASH' ) {
160 0 0 0       $found = 0 if $branch->{ $node->{attr} } && $branch->{ $node->{attr} } ne $node->{value};
161             }
162             else {
163 0           $found = 0;
164 0           foreach my $hashref ( @$branch ) {
165 0 0 0       if ( $hashref->{ $node->{attr} } && $hashref->{ $node->{attr} } eq $node->{value} ) {
166 0           $branch = $hashref;
167 0           $found = 1;
168 0           last;
169             }
170             }#foreach
171             }#else
172             }#if
173             elsif ( ref $branch eq 'ARRAY' ) {
174 0           croak( "Array of hashes at node '$node->{name}', but no attribute selector supplied" );
175             }
176             # Check for alias
177 0 0         if ( $branch->{alias} ) {
178             # Figure out where it points to, and attach it to the tree
179 0           my $path = $branch->{alias}->{path};
180 0           my $back = $path =~ m#\.\./#g;
181 0           $path =~ s#^(\.\./){$back}##g;
182 0           my $count = 0;
183 0           while ( my ( $field, $pair ) = $path =~ /^(\w+)(\[\@\w+='[\w\-]+'\])?(\/)?/ ) {
184 0           $path =~ s/^\Q$&\E//;
185 0           $count++;
186 0 0         if ( $pair ) {
187 0           my ( $a, $v ) = $pair =~ /([\w\-]+)='([\w\-]+)/;
188 0           $new = $current->{node}->[$pos - $back]->$field($a,$v);
189             }
190             else {
191 0           $new = $current->{node}->[$pos - $back]->$field();
192             }
193 0           $branch = $new->{branch};
194             }#while
195             }#if
196             }#if
197             elsif ( defined $branch->{ $node->{name} } ) {
198 0           return $branch->{ $node->{name} };
199             }
200             else {
201 0           $found = 0;
202 0           last;
203             }
204             }#foreach
205 0 0         if ( $found ) {
206 0           $new->{branch} = $branch;
207 0           last;
208             }
209             }#foreach
210 0 0         return undef unless $found;
211            
212 0           $new->{node} = [ @{ $current->{node} }, $new ];
  0            
213 0           return $new;
214             }
215            
216            
217             # This is provided so AUTOLOAD isn't called instead.
218 0     0     sub DESTROY {}
219            
220            
221             1;
222            
223            
224             =head1 AUTHOR
225            
226             Lyle Hopkins, C<< >>
227            
228             =head1 CAVEATS
229            
230             Not much has been tested. The current stable release (version 21 on 2012/08/30)
231             of the main CLDR XML is included, this is for convenience but makes the module
232             bloated.
233             As this module is indended to be very lightweight is doesn't use a much CPAN
234             so expect funny things in the code.
235            
236             =head1 BUGS
237            
238             Please report any bugs or feature requests to C, or through
239             the web interface at L. I will be notified, and then you'll
240             automatically be notified of progress on your bug as I make changes.
241            
242             =head1 TODO
243            
244             Write more tests and examples
245             Allow for CLDR xml files path overwrite
246            
247             =head1 SUPPORT
248            
249             You can find documentation for this module with the perldoc command.
250            
251             perldoc Locale::CLDR::Lite
252            
253            
254             You can also look for information at:
255            
256             =over 4
257            
258             =item * RT: CPAN's request tracker (report bugs here)
259            
260             L
261            
262             =item * AnnoCPAN: Annotated CPAN documentation
263            
264             L
265            
266             =item * CPAN Ratings
267            
268             L
269            
270             =item * Search CPAN
271            
272             L
273            
274             =back
275            
276            
277             =head1 ACKNOWLEDGEMENTS
278            
279             Thanks to John Imrie for giving advice and pointers.
280            
281             Thanks to everyone contributing to the CLDR project.
282            
283             Thanks to L for funding development.
284            
285             =head1 SEE ALSO
286            
287             L
288            
289             =head1 LICENSE AND COPYRIGHT
290            
291             Copyright 2012 Lyle Hopkins.
292            
293             This program is free software; you can redistribute it and/or modify it
294             under the terms of either: the GNU General Public License as published
295             by the Free Software Foundation; or the Artistic License.
296            
297             See http://dev.perl.org/licenses/ for more information.
298            
299            
300             =cut
301            
302             1; # End of Locale::CLDR::Lite