File Coverage

blib/lib/Locale/Utils/PluralForms.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Locale::Utils::PluralForms;
2              
3 6     6   293576 use Moose;
  0            
  0            
4             use MooseX::StrictConstructor;
5              
6             use namespace::autoclean;
7             use syntax qw(method);
8              
9             use English qw(-no_match_vars $EVAL_ERROR);
10             use HTML::Entities qw(decode_entities);
11             require LWP::UserAgent;
12             require Safe;
13              
14             our $VERSION = '0.001';
15              
16             has language => (
17             is => 'rw',
18             isa => 'Str',
19             trigger => \&_language,
20             );
21              
22             has _all_plural_forms_url => (
23             is => 'rw',
24             isa => 'Str',
25             default => 'http://translate.sourceforge.net/wiki/l10n/pluralforms',
26             );
27              
28             has _all_plural_forms_html => (
29             is => 'rw',
30             isa => 'Str',
31             default => \&_get_all_plural_forms_html,
32             lazy => 1,
33             clearer => 'clear_all_plural_forms_html',
34             );
35              
36             has all_plural_forms => (
37             is => 'rw',
38             isa => 'HashRef',
39             default => \&_get_all_plural_forms,
40             lazy => 1,
41             );
42              
43             has plural_forms => (
44             is => 'rw',
45             isa => 'Str',
46             default => 'nplurals=1; plural=0',
47             lazy => 1,
48             trigger => \&_calculate_plural_forms,
49             );
50              
51             has nplurals => (
52             is => 'rw',
53             isa => 'Int',
54             default => 1,
55             lazy => 1,
56             init_arg => undef,
57             writer => '_nplurals',
58             );
59              
60             has plural_code => (
61             is => 'rw',
62             isa => 'CodeRef',
63             default => sub { return sub { return 0 } },
64             lazy => 1,
65             init_arg => undef,
66             writer => '_plural_code',
67             );
68              
69             method _get_all_plural_forms_html () {
70             my $url = $self->_all_plural_forms_url;
71             my $ua = LWP::UserAgent->new;
72             $ua->env_proxy;
73             my $response = $ua->get($url);
74             $response->is_success
75             or confess "$url $response->status_line";
76              
77             return $response->decoded_content;
78             }
79              
80             method _get_all_plural_forms () {
81             my @match = $self->_all_plural_forms_html =~ m{ # no critic(ComplexRegexes)
82             .*?
83             <td \s+ class="col0"> \s* ( [^<]+? ) \s* <
84             .*?
85             <td \s+ class="col1"> \s* ( [^<]+? ) \s* <
86             .*?
87             <td \s+ class="col2 [^"]* "> \s* ( [^<]+? ) \s* <
88             }xmsg;
89             $self->clear_all_plural_forms_html;
90             my %all_plural_forms;
91             while ( my ($iso, $english_name, $plural_forms) = splice @match, 0, 3 ) { ## no critic (MagicNumbers)
92             $all_plural_forms{ decode_entities($iso) } = {
93             english_name => decode_entities($english_name),
94             plural_forms => decode_entities($plural_forms),
95             };
96             }
97              
98             return \%all_plural_forms;
99             }
100              
101             method _language ($language) {
102             my $all_plural_forms = $self->all_plural_forms;
103             if ( exists $all_plural_forms->{$language} ) {
104             return $self->plural_forms(
105             $all_plural_forms->{$language}->{plural_forms}
106             );
107             }
108             $language =~ s{_ .* \z}{}xms;
109             if ( exists $all_plural_forms->{$language} ) {
110             return $self->plural_forms(
111             $all_plural_forms->{$language}->{plural_forms}
112             );
113             }
114              
115             return confess
116             "Missing plural forms for language $language in all_plural_forms";
117             }
118              
119             method _calculate_plural_forms () {
120             my $plural_forms = $self->plural_forms;
121             $plural_forms =~ s{\b ( nplurals | plural | n ) \b}{\$$1}xmsg;
122             my $safe = Safe->new;
123             my $nplurals_code = <<"EOC";
124             my \$n = 0;
125             my (\$nplurals, \$plural);
126             $plural_forms;
127             \$nplurals;
128             EOC
129             $self->_nplurals(
130             $safe->reval($nplurals_code)
131             or confess
132             "Code of Plural-Forms $plural_forms is not safe, $EVAL_ERROR"
133             );
134             my $plural_code = <<"EOC";
135             sub {
136             my \$n = shift;
137             my (\$nplurals, \$plural);
138             $plural_forms;
139             return \$plural || 0;
140             }
141             EOC
142             $self->_plural_code(
143             $safe->reval($plural_code)
144             or confess "Code $plural_forms is not safe, $EVAL_ERROR"
145             );
146              
147             return $self;
148             }
149              
150             __PACKAGE__->meta->make_immutable;
151              
152             1;
153              
154             __END__
155              
156             =head1 NAME
157              
158             Locale::Utils::PluralForms - Utils to use plural forms
159              
160             $Id: PluralForms.pm 382 2011-11-13 13:20:22Z steffenw $
161              
162             $HeadURL: https://perl-gettext-oo.svn.sourceforge.net/svnroot/perl-gettext-oo/Locale-Utils-PluralForms/trunk/lib/Locale/Utils/PluralForms.pm $
163              
164             =head1 VERSION
165              
166             0.001
167              
168             =head1 SYNOPSIS
169              
170             use Locale::Utils::PluralForms;
171              
172             my $obj = Locale::Utils::PluralForms->new;
173              
174             Data downloaded from web
175              
176             $obj = Locale::Utils::PluralForms->new(
177             language => 'en_GB', # fallbacks from given en_GB to en
178             );
179              
180             Data of given data structure
181              
182             $obj = Locale::Utils::PluralForms->new(
183             all_plural_forms => {
184             'en' => {
185             english_name => 'English',
186             plural_forms => 'nplurals=2; plural=(n != 1)',
187             },
188             # next languages
189             },
190             );
191              
192             Getter
193              
194             my $language = $obj->language;
195             my $all_plural_forms = $obj->all_plural_forms;
196             my $plural_forms = $obj->plural_forms;
197             my $nplurals = $obj->nplurals;
198             my $plural_code = $obj->plural_code;
199             my $plural = $obj->plural_code->($number);
200              
201             =head1 DESCRIPTION
202              
203             =head2 Find plural forms for the language
204              
205             This module helps to find the plural forms for all languages.
206             It downloads the plural forms for all languages from web.
207             Then it stores the extracted data
208             into a data structure named "all_plural_forms".
209              
210             It is possible to fill that data structure
211             before method "language" is called first time
212             or to cache after first method call "language".
213              
214             =head2 "plural" as subroutine
215              
216             In the header of a PO- or MO-File
217             is an entry is called "Plural-Forms".
218             How many plural forms the language has, is described there in "nplurals".
219             The second Information in "Plural-Forms" describes as a formula,
220             how to choose the "plural".
221              
222             This module compiles plural forms
223             to a code references in a secure way.
224              
225             =head1 SUBROUTINES/METHODS
226              
227             =head2 Find plural forms for the language
228              
229             =head3 method language
230              
231             Set the language to switch to the plural forms of that language.
232             "plural_forms" is set then and "nplurals" and "plural_code" will be calculated.
233              
234             $obj->language('de_AT'); # A fallback finds plural forms of language de
235             # because de_AT is not different.
236              
237             Read the language back.
238              
239             $obj->language eq 'de_AT';
240              
241             =head3 method all_plural_forms
242              
243             Set the data structure.
244              
245             $obj->all_plural_forms({
246             'de' => {
247             english_name => 'German',
248             plural_forms => 'nplurals=2; plural=(n != 1)',
249             },
250             # next languages
251             });
252              
253             Read the data structure back.
254              
255             my $hash_ref = $obj->all_plural_forms;
256              
257             =head2 executable plural forms
258              
259             =head3 method plural_forms
260              
261             Set "plural_forms" if no "language" is set.
262             After that "nplurals" and "plural_code" will be calculated in a safe way.
263              
264             $obj->plural_forms('nplurals=1; plural=0');
265              
266             Or read it back.
267              
268             my $plural_forms = $obj->plural_forms;
269              
270             =head3 method nplurals
271              
272             This method get back the calculated count of plurals.
273              
274             If no "language" and no "plural_forms" is set,
275             the defaults for "nplurals" is:
276              
277             my $count = $obj->nplurals # returns: 1
278              
279             There is no public setter for "nplurals"
280             and it is not possible to set them in the constructor.
281             Call method "language" or "plural_forms"
282             or set attribute "language" or "plural_forms" in the constructor.
283             After that "nplurals" will be calculated automaticly and safe.
284              
285             =head2 method plural_code
286              
287             This method get back the calculated code for the "plural"
288             to choose the correct "plural".
289              
290             If no "language" and no "plural_forms" is set,
291             the defaults for plural_code is:
292              
293             my $code_ref = $obj->plural_code # returns: sub { return 0 }
294             my $plural = $obj->plural_code->($number); # returns 0
295              
296             There is no public setter for "plural_code"
297             and it is not possible to set them in the constructor.
298             Call method "language" or "plural_forms"
299             or set attribute "language" or "plural_forms" in the constructor.
300             After that "plural_code" will be calculated automaticly and safe.
301              
302             For the example plural forms C<'nplurals=2; plural=(n != 1)'>:
303              
304             $plural = $obj->plural_code->(0), # $plural is 1
305             $plural = $obj->plural_code->(1), # $plural is 0
306             $plural = $obj->plural_code->(2), # $plural is 1
307             $plural = $obj->plural_code->(3), # $plural is 1
308             ...
309              
310             =head1 EXAMPLE
311              
312             Inside of this distribution is a directory named example.
313             Run the *.pl files.
314              
315             =head1 DIAGNOSTICS
316              
317             none
318              
319             =head1 CONFIGURATION AND ENVIRONMENT
320              
321             none
322              
323             =head1 DEPENDENCIES
324              
325             L<Moose|Moose>
326              
327             L<MooseX::StrictConstructor|MooseX::StrictConstructor>
328              
329             L<namespace::autoclean|namespace::autoclean>
330              
331             L<syntax|syntax>
332              
333             L<English|English>
334              
335             L<HTML::Entities|HTML::Entities>
336              
337             L<LWP::UserAgent|LWP::UserAgent>
338              
339             L<Safe|Safe>
340              
341             =head1 INCOMPATIBILITIES
342              
343             not known
344              
345             =head1 BUGS AND LIMITATIONS
346              
347             not known
348              
349             =head1 SEE ALSO
350              
351             L<http://en.wikipedia.org/wiki/Gettext>
352              
353             L<http://translate.sourceforge.net/wiki/l10n/pluralforms>
354              
355             L<Locele::TextDomain|Locele::TextDomain>
356              
357             =head1 AUTHOR
358              
359             Steffen Winkler
360              
361             =head1 LICENSE AND COPYRIGHT
362              
363             Copyright (c) 2011,
364             Steffen Winkler
365             C<< <steffenw at cpan.org> >>.
366             All rights reserved.
367              
368             This module is free software;
369             you can redistribute it and/or modify it
370             under the same terms as Perl itself.
371              
372             =cut