File Coverage

blib/lib/Benchmark/Featureset/LocaleCountry.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package Benchmark::Featureset::LocaleCountry;
2              
3 1     1   24729 use strict;
  1         3  
  1         39  
4 1     1   5 use warnings;
  1         2  
  1         28  
5              
6 1     1   597 use Benchmark::Featureset::LocaleCountry::Config;
  1         3  
  1         27  
7              
8 1     1   971 use Date::Simple;
  1         9371  
  1         36  
9              
10 1     1   923 use Locale::Country ();
  1         42166  
  1         33  
11 1     1   1402 use Locale::Country::Multilingual {use_io_layer => 1};
  1         4664  
  1         9  
12 1     1   515 use Locale::Geocode ();
  0            
  0            
13             use Locale::Geocode::Territory ();
14             use Locale::Object;
15             use Locale::Object::DB ();
16             use Locale::SubCountry ();
17             use WWW::Scraper::Wikipedia::ISO3166::Database;
18              
19             use Set::Array;
20              
21             use Text::Xslate 'mark_raw';
22              
23             our $VERSION = '1.03';
24              
25             # ------------------------------------------------
26              
27             sub build_country_data
28             {
29             my($self, $module_data) = @_;
30              
31             my(@country_name_count);
32              
33             push @country_name_count, {left => 'Module', right => '# of countries'};
34              
35             for my $module_name (sort keys %$module_data)
36             {
37             push @country_name_count, {left => $module_name, right => $$module_data{$module_name}{country_count} };
38             }
39              
40             return \@country_name_count;
41              
42             } # End of build_country_data.
43              
44             # ------------------------------------------------
45              
46             sub build_environment
47             {
48             my($self) = @_;
49              
50             my(@environment);
51              
52             push @environment,
53             {left => 'Author', right => mark_raw(qq|Ron Savage|)},
54             {left => 'Date', right => Date::Simple -> today},
55             {left => 'OS', right => 'Debian V 6.0.1'},
56             {left => 'Perl', right => 'V 5.12.2'};
57              
58             return \@environment;
59              
60             }
61             # End of build_environment.
62              
63             # ------------------------------------------------
64              
65             sub build_mismatched_countries
66             {
67             my($self, $module_data, $common_countries) = @_;
68              
69             # Get the country names by which each one differs from the common list.
70              
71             my(%mismatched_data);
72              
73             for my $module_name (sort keys %$module_data)
74             {
75             $mismatched_data{$module_name} =
76             {
77             country_names => Set::Array -> new(sort @{$$module_data{$module_name}{country_names} -> difference($common_countries)}),
78             name_list => {},
79             };
80             }
81              
82             # Transform the unique names, for convenience in latter processing.
83              
84             my(%mismatch_list);
85             my(@name_list);
86              
87             for my $module_name (sort keys %$module_data)
88             {
89             @name_list = $mismatched_data{$module_name}{country_names} -> print;
90             @mismatch_list{@name_list} = (1) x @name_list;
91             @{$mismatched_data{$module_name}{name_list} }{@name_list} = (1) x @name_list;
92             }
93              
94             # Output the module names (across) as a heading for the results table.
95              
96             @name_list = ();
97              
98             for my $module_name (sort keys %$module_data)
99             {
100             next if ($$module_data{$module_name}{country_count} == 0);
101              
102             push @name_list, {td => $module_name};
103             }
104              
105             # Output the mismatched names (down) cross-tabulated with the module names (across).
106              
107             my(@mismatched_data);
108              
109             push @mismatched_data, [@name_list];
110              
111             for my $name (sort keys %mismatch_list)
112             {
113             @name_list = ();
114              
115             for my $module_name (sort keys %$module_data)
116             {
117             next if ($$module_data{$module_name}{country_count} == 0);
118              
119             if ($mismatched_data{$module_name}{name_list}{$name})
120             {
121             push @name_list, {td => $name};
122             }
123             else
124             {
125             push @name_list, {td => '-'};
126             }
127             }
128              
129             push @mismatched_data, [@name_list];
130             }
131              
132             return \@mismatched_data;
133              
134             } # End of build_mismatched_countries.
135              
136             # ------------------------------------------------
137             # This is called once per country.
138              
139             sub build_mismatched_division_detail
140             {
141             my($self, $module_data, $common_divisions, $country_name) = @_;
142              
143             # Get the division names per country by which each one differs from the common list.
144              
145             my(%mismatched_data);
146              
147             for my $module_name (sort keys %$module_data)
148             {
149             next if ($$module_data{$module_name}{division_count}{$country_name} == 0);
150              
151             $mismatched_data{$module_name} =
152             {
153             division_names => Set::Array -> new(sort @{$$module_data{$module_name}{division_names}{$country_name} -> difference($common_divisions)}),
154             name_list => {},
155             };
156             }
157              
158             # Transform the unique names, for convenience in latter processing.
159              
160             my(%mismatch_list);
161             my(@name_list);
162              
163             for my $module_name (sort keys %$module_data)
164             {
165             next if ($$module_data{$module_name}{division_count}{$country_name} == 0);
166              
167             @name_list = $mismatched_data{$module_name}{division_names} -> print;
168             @mismatch_list{@name_list} = (1) x @name_list;
169             @{$mismatched_data{$module_name}{name_list} }{@name_list} = (1) x @name_list;
170             }
171              
172             # Output the module names (across) as a heading for the results table.
173              
174             @name_list = ({td => $country_name});
175              
176             for my $module_name (sort keys %$module_data)
177             {
178             next if ($$module_data{$module_name}{division_count}{$country_name} == 0);
179              
180             push @name_list, {td => $module_name};
181             }
182              
183             my(@mismatched_data);
184              
185             push @mismatched_data, [@name_list];
186              
187             # Output the mismatched names (down) cross-tabulated with the module names (across).
188              
189             for my $name (sort keys %mismatch_list)
190             {
191             @name_list = ({td => $country_name});
192              
193             for my $module_name (sort keys %$module_data)
194             {
195             next if ($$module_data{$module_name}{division_count}{$country_name} == 0);
196              
197             if ($mismatched_data{$module_name}{name_list}{$name})
198             {
199             push @name_list, {td => $name};
200             }
201             else
202             {
203             push @name_list, {td => '-'};
204             }
205             }
206              
207             push @mismatched_data, [@name_list];
208             }
209              
210             return @mismatched_data;
211              
212             } # End of build_mismatched_division_detail.
213              
214             # ------------------------------------------------
215              
216             sub build_mismatched_divisions
217             {
218             my($self, $module_data, $common_countries) = @_;
219              
220             my($common_divisions);
221             my(@mismatched_data);
222              
223             for my $country_name ($common_countries -> print)
224             {
225             if ($$module_data{'Locale::Geocode'}{division_count}{$country_name} && $$module_data{'Locale::SubCountry'}{division_count}{$country_name})
226             {
227             $common_divisions = Set::Array -> new(sort @{$$module_data{'Locale::Geocode'}{division_names}{$country_name} -> intersection($$module_data{'Locale::SubCountry'}{division_names}{$country_name})});
228              
229             push @mismatched_data, $self -> build_mismatched_division_detail($module_data, $common_divisions, $country_name);
230             }
231             }
232              
233             return \@mismatched_data;
234              
235             } # End of build_mismatched_divisions.
236              
237             # ------------------------------------------------
238              
239             sub build_module_data
240             {
241             my($self) = @_;
242             my($iso3166) = WWW::Scraper::Wikipedia::ISO3166::Database -> new -> read_countries_table;
243             my($multilingual) = Locale::Country::Multilingual -> new;
244             my($world) = Locale::SubCountry::World -> new;
245             my(%module_data) =
246             (
247             'Locale::Codes' =>
248             {
249             country_count => 0, # See below.
250             country_names => Set::Array -> new(Locale::Country::all_country_names),
251             division_count => {}, # Per country. See below.
252             division_names => {}, # See below.
253             last_update => '2011-03-01',
254             version => $Locale::Codes::VERSION,
255             },
256             'Locale::Country::Multilingual' =>
257             {
258             country_count => 0,
259             country_names => Set::Array -> new($multilingual -> all_country_names),
260             division_count => {},
261             division_names => {},
262             last_update => '2009-04-15',
263             version => $Locale::Country::Multilingual::VERSION,
264             },
265             'Locale::Geocode' =>
266             {
267             country_count => 0,
268             country_names => Set::Array -> new,
269             division_count => {},
270             division_names => {},
271             last_update => '2009-02-10',
272             version => $Locale::Geocode::VERSION,
273             },
274             'Locale::Object' =>
275             {
276             country_count => 0,
277             country_names => Set::Array -> new,
278             division_count => {},
279             division_names => {},
280             last_update => '2007-10-25',
281             version => $Locale::Object::VERSION,
282             },
283             'Locale::SubCountry' =>
284             {
285             country_count => 0,
286             country_names => Set::Array -> new($world -> all_full_names),
287             division_count => {},
288             division_names => {},
289             last_update => '2011-04-06',
290             version => $Locale::SubCountry::VERSION,
291             },
292             'WWW::Scraper::Wikipedia::ISO3166' =>
293             {
294             country_count => 0,
295             country_names => Set::Array -> new(map{$$iso3166{$_}{name} } keys %$iso3166),
296             division_count => {},
297             division_names => {},
298             last_update => '2012-05-16',
299             version => $WWW::Scraper::Wikipedia::ISO3166::VERSION,
300             },
301             );
302              
303             # Get the country names common to those modules which provide them.
304              
305             my($common_countries) = Set::Array -> new(sort @{$module_data{'Locale::Codes'}{country_names} -> intersection($module_data{'Locale::Country::Multilingual'}{country_names})});
306             $common_countries = Set::Array -> new(sort @{$common_countries -> intersection($module_data{'WWW::Scraper::Wikipedia::ISO3166'}{country_names})});
307             $common_countries = Set::Array -> new(sort @{$common_countries -> intersection($module_data{'Locale::SubCountry'}{country_names})});
308              
309             # Use the common names for Locale::Geocode, since we want its territory names.
310              
311             #Ignore#$module_data{'Locale::Geocode'}{country_names} = $common_countries -> print;
312              
313             # Get the country count per module, and get the divisions per country.
314              
315             for my $country_name ($common_countries -> print)
316             {
317             for my $module_name (sort keys %module_data)
318             {
319             $module_data{$module_name}{division_count}{$country_name} = 0;
320             }
321             }
322              
323             my($country_name);
324             my($geocode);
325              
326             for my $module_name (sort keys %module_data)
327             {
328             $module_data{$module_name}{country_count} = $module_data{$module_name}{country_names} -> length;
329              
330             if ($module_data{$module_name}{country_count})
331             {
332             for $country_name ($module_data{$module_name}{country_names} -> print)
333             {
334             $geocode = Locale::Geocode::Territory -> new($country_name);
335              
336             if ($geocode)
337             {
338             $module_data{$module_name}{division_names}{$country_name} = Set::Array -> new(sort map{$_ -> name} $geocode -> divisions);
339             $module_data{$module_name}{division_count}{$country_name} = $module_data{$module_name}{division_names}{$country_name} -> length;
340             }
341             }
342             }
343             }
344              
345             for my $country_name ($common_countries -> print)
346             {
347             for my $module_name (sort keys %module_data)
348             {
349             if ($module_data{$module_name}{division_count}{$country_name} > 0)
350             {
351             #print STDERR "$country_name. $module_name. $module_data{$module_name}{division_count}{$country_name}. \n";
352             }
353             }
354             }
355              
356             my(@module_list);
357              
358             push @module_list, [{td => 'Module'}, {td => 'Version'}, {td => 'Last update'}];
359              
360             for my $module (sort keys %module_data)
361             {
362             push @module_list, [{td => mark_raw(qq|$module|)}, {td => $module_data{$module}{version} }, {td => $module_data{$module}{last_update} }];
363             }
364              
365             return ($common_countries, \%module_data, \@module_list);
366              
367             } # End of build_module_data.
368              
369             # ------------------------------------------------
370              
371             sub build_purpose
372             {
373             my($self) = @_;
374              
375             my(@purpose);
376              
377             push @purpose,
378             {left => 'Country names', right => '2 and 3 letter country codes'},
379             {left => 'SubCountry names', right => '(Divisions, Provinces, States, Territories)'},
380             {left => 'Currency details', right => 'Language details'};
381              
382             return \@purpose;
383              
384             } # End of build_purpose;
385              
386             # ------------------------------------------------
387              
388             sub build_templater
389             {
390             my($self, $config) = @_;
391              
392             return Text::Xslate -> new
393             (
394             input_layer => '',
395             path => $$config{template_path},
396             );
397              
398             } # End of build_templater.
399              
400             # -----------------------------------------------
401              
402             sub new
403             {
404             my($class, %arg) = @_;
405              
406             return bless {}, $class;
407              
408             } # End of new.
409              
410             # ------------------------------------------------
411              
412             sub run
413             {
414             my($self) = @_;
415             my($config) = Benchmark::Featureset::LocaleCountry::Config -> new -> config;
416             my($templater) = $self -> build_templater($config);
417             my($common_countries, $module_data, $module_list) = $self -> build_module_data;
418             my($country_name_count) = $self -> build_country_data($module_data);
419              
420             print $templater -> render
421             (
422             'locale.report.tx',
423             {
424             common_country_count => $common_countries -> length,
425             country_name_count => $country_name_count,
426             country_name_mismatch => $self -> build_mismatched_countries($module_data, $common_countries),
427             default_css => "$$config{css_url}/default.css",
428             #division_name_mismatch => $self -> build_mismatched_divisions($module_data, $common_countries),
429             environment => $self -> build_environment,
430             fancy_table_css => "$$config{css_url}/fancy.table.css",
431             module_data => $module_list,
432             purpose => $self -> build_purpose,
433             }
434             );
435              
436             } # End of run.
437              
438             # ------------------------------------------------
439              
440             1;
441              
442             =pod
443              
444             =head1 NAME
445              
446             Benchmark::Featureset::LocaleCountry - Compare Locale::Codes, Locale::Country::Multilingual, WWW::Scraper::Wikipedia::ISO3166, etc
447              
448             =head1 Synopsis
449              
450             #!/usr/bin/env perl
451              
452             use strict;
453             use warnings;
454              
455             use Benchmark::Featureset::LocaleCountry;
456              
457             # ------------------------------
458              
459             Benchmark::Featureset::LocaleCountry -> new -> run;
460              
461             See scripts/locale.report.pl.
462              
463             Hint: Redirect the output of that script to your $doc_root/locale.report.html.
464              
465             L.
466              
467             =head1 Description
468              
469             L compares some features of various modules:
470              
471             =over 4
472              
473             =item o L
474              
475             =item o L
476              
477             =item o L
478              
479             =item o L
480              
481             =item o L
482              
483             =item o L
484              
485             =back
486              
487             =head1 Distributions
488              
489             This module is available as a Unix-style distro (*.tgz).
490              
491             See L
492             for help on unpacking and installing distros.
493              
494             =head1 Installation
495              
496             =head2 The Module Itself
497              
498             Install L as you would for any C module:
499              
500             Run:
501              
502             cpanm Benchmark::Featureset::LocaleCountry
503              
504             or run:
505              
506             sudo cpan Benchmark::Featureset::LocaleCountry
507              
508             or unpack the distro, and then either:
509              
510             perl Build.PL
511             ./Build
512             ./Build test
513             sudo ./Build install
514              
515             or:
516              
517             perl Makefile.PL
518             make (or dmake or nmake)
519             make test
520             make install
521              
522             =head2 The Configuration File
523              
524             All that remains is to tell L your values for some options.
525              
526             For that, see config/.htbenchmark.featureset.localecountry.conf.
527              
528             If you are using Build.PL, running Build (without parameters) will run scripts/copy.config.pl,
529             as explained next.
530              
531             If you are using Makefile.PL, running make (without parameters) will also run scripts/copy.config.pl.
532              
533             Either way, before editing the config file, ensure you run scripts/copy.config.pl. It will copy
534             the config file using L, to a directory where the run-time code in
535             L will look for it.
536              
537             shell>cd Benchmark-Featureset-LocaleCountry-1.00
538             shell>perl scripts/copy.config.pl
539              
540             Under Debian, this directory will be $HOME/.perl/Benchmark-Featureset-LocaleCountry/. When you
541             run copy.config.pl, it will report where it has copied the config file to.
542              
543             Check the docs for L to see what your operating system returns for a
544             call to my_dist_config().
545              
546             The point of this is that after the module is installed, the config file will be
547             easily accessible and editable without needing permission to write to the directory
548             structure in which modules are stored.
549              
550             That's why L and L are pre-requisites for this module.
551              
552             All modules which ship with their own config file are advised to use the same mechanism
553             for storing such files.
554              
555             =head1 Constructor and Initialization
556              
557             C is called as C<< my($builder) = Benchmark::Featureset::LocaleCountry -> new(k1 => v1, k2 => v2, ...) >>.
558              
559             It returns a new object of type C.
560              
561             Key-value pairs in accepted in the parameter list (see corresponding methods for details):
562              
563             =over 4
564              
565             =item o (None as yet)
566              
567             =back
568              
569             =head1 Methods
570              
571             =head2 build_country_data()
572              
573             Returns an arrayref of module names and country counts.
574              
575             =head2 build_environment()
576              
577             Returns an arrayref of stuff about my working environment.
578              
579             =head2 build_mismatched_countries()
580              
581             Returns an arrayref of mismatches between modules and the country names they use.
582              
583             =head2 build_mismatched_division_list()
584              
585             See build_mismatched_divisions().
586              
587             =head2 build_mismatched_divisions()
588              
589             Returns an arrayref of mismatches between modules and the division names they use.
590              
591             Uses build_mismatched_division_list() to do the work.
592              
593             =head2 build_module_data()
594              
595             Returns:
596              
597             =over 4
598              
599             =item o An object of type Set::Array, called $common_countries
600              
601             This holds the list of countries which all modules have in common.
602              
603             =item o A hashref called $module_data
604              
605             This is the hashref of the modules being tested.
606              
607             =item o An arrayref called $module_list
608              
609             This is for outputting. It contains the modules' names and links to CPAN.
610              
611             =back
612              
613             =head2 build_purpose()
614              
615             Returns an arrayref of stuff about the purpose of this module.
616              
617             =head2 build_templater()
618              
619             Returns an object of type Text::Xslate.
620              
621             =head2 new()
622              
623             For use by subclasses.
624              
625             =head2 run()
626              
627             Does the real work.
628              
629             See scripts/locale.report.pl.
630              
631             Hint: Redirect the output of that script to $doc_root/locale.report.html.
632              
633             =head1 References
634              
635             The modules compared in this package often have links to various documents, which I won't repeat here...
636              
637             =head1 Machine-Readable Change Log
638              
639             The file CHANGES was converted into Changelog.ini by L.
640              
641             =head1 Version Numbers
642              
643             Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions.
644              
645             =head1 Support
646              
647             Email the author, or log a bug on RT:
648              
649             L.
650              
651             =head1 Author
652              
653             L was written by Ron Savage Iron@savage.net.auE> in 2011.
654              
655             Home page: L.
656              
657             =head1 Copyright
658              
659             Australian copyright (c) 2011, Ron Savage.
660              
661             All Programs of mine are 'OSI Certified Open Source Software';
662             you can redistribute them and/or modify them under the terms of
663             The Artistic License, a copy of which is available at:
664             http://www.opensource.org/licenses/index.html
665              
666             =cut