| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Geo::Region; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 2 |  |  | 2 |  | 178680 | use v5.8.1; | 
|  | 2 |  |  |  |  | 8 |  | 
|  | 2 |  |  |  |  | 87 |  | 
| 4 | 2 |  |  | 2 |  | 8 | use utf8; | 
|  | 2 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 26 |  | 
| 5 | 2 |  |  | 2 |  | 60 | use Carp qw( carp ); | 
|  | 2 |  |  |  |  | 7 |  | 
|  | 2 |  |  |  |  | 139 |  | 
| 6 | 2 |  |  | 2 |  | 9 | use Scalar::Util qw( looks_like_number weaken ); | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 82 |  | 
| 7 | 2 |  |  | 2 |  | 7 | use List::Util qw( all any ); | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 183 |  | 
| 8 | 2 |  |  | 2 |  | 1062 | use Moo; | 
|  | 2 |  |  |  |  | 24885 |  | 
|  | 2 |  |  |  |  | 12 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | our $VERSION = '0.06'; | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | my %children_of = ( | 
| 13 |  |  |  |  |  |  | # regions of subregions | 
| 14 |  |  |  |  |  |  | '001' => [qw( 002 009 019 142 150 )], | 
| 15 |  |  |  |  |  |  | '002' => [qw( 011 014 015 017 018 )], | 
| 16 |  |  |  |  |  |  | '003' => [qw( 013 021 029 )], | 
| 17 |  |  |  |  |  |  | '009' => [qw( 053 054 057 061 QO )], | 
| 18 |  |  |  |  |  |  | '019' => [qw( 003 005 013 021 029 419 )], | 
| 19 |  |  |  |  |  |  | '142' => [qw( 030 034 035 143 145 )], | 
| 20 |  |  |  |  |  |  | '150' => [qw( 039 151 154 155 EU )], | 
| 21 |  |  |  |  |  |  | '419' => [qw( 005 013 029 )], | 
| 22 |  |  |  |  |  |  | # regions of countries and territories | 
| 23 |  |  |  |  |  |  | '005' => [qw( AR BO BR CL CO EC FK GF GY PE PY SR UY VE )], | 
| 24 |  |  |  |  |  |  | '011' => [qw( BF BJ CI CV GH GM GN GW LR ML MR NE NG SH SL SN TG )], | 
| 25 |  |  |  |  |  |  | '013' => [qw( BZ CR GT HN MX NI PA SV )], | 
| 26 |  |  |  |  |  |  | '014' => [qw( BI DJ ER ET KE KM MG MU MW MZ RE RW SC SO TZ UG YT ZM ZW )], | 
| 27 |  |  |  |  |  |  | '015' => [qw( DZ EA EG EH IC LY MA SD SS TN )], | 
| 28 |  |  |  |  |  |  | '017' => [qw( AO CD CF CG CM GA GQ ST TD ZR )], | 
| 29 |  |  |  |  |  |  | '018' => [qw( BW LS NA SZ ZA )], | 
| 30 |  |  |  |  |  |  | '021' => [qw( BM CA GL PM US )], | 
| 31 |  |  |  |  |  |  | '029' => [qw( AG AI AN AW BB BL BQ BS CU CW DM DO GD GP HT JM KN KY LC MF MQ MS PR SX TC TT VC VG VI )], | 
| 32 |  |  |  |  |  |  | '030' => [qw( CN HK JP KP KR MN MO TW )], | 
| 33 |  |  |  |  |  |  | '034' => [qw( AF BD BT IN IR LK MV NP PK )], | 
| 34 |  |  |  |  |  |  | '035' => [qw( BN BU ID KH LA MM MY PH SG TH TL TP VN )], | 
| 35 |  |  |  |  |  |  | '039' => [qw( AD AL BA CS ES GI GR HR IT ME MK MT PT RS SI SM VA XK YU )], | 
| 36 |  |  |  |  |  |  | '053' => [qw( AU NF NZ )], | 
| 37 |  |  |  |  |  |  | '054' => [qw( FJ NC PG SB VU )], | 
| 38 |  |  |  |  |  |  | '057' => [qw( FM GU KI MH MP NR PW )], | 
| 39 |  |  |  |  |  |  | '061' => [qw( AS CK NU PF PN TK TO TV WF WS )], | 
| 40 |  |  |  |  |  |  | '143' => [qw( KG KZ TJ TM UZ )], | 
| 41 |  |  |  |  |  |  | '145' => [qw( AE AM AZ BH CY GE IL IQ JO KW LB NT OM PS QA SA SY TR YD YE )], | 
| 42 |  |  |  |  |  |  | '151' => [qw( BG BY CZ HU MD PL RO RU SK SU UA )], | 
| 43 |  |  |  |  |  |  | '154' => [qw( AX DK EE FI FO GB GG IE IM IS JE LT LV NO SE SJ )], | 
| 44 |  |  |  |  |  |  | '155' => [qw( AT BE CH DD DE FR FX LI LU MC NL )], | 
| 45 |  |  |  |  |  |  | 'EU'  => [qw( AT BE BG CY CZ DE DK EE ES FI FR GB GR HR HU IE IT LT LU LV MT NL PL PT RO SE SI SK )], | 
| 46 |  |  |  |  |  |  | 'QO'  => [qw( AC AQ BV CC CP CX DG GS HM IO TA TF UM )], | 
| 47 |  |  |  |  |  |  | ); | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | # codes excluded from country list due to being deprecated or grouping container | 
| 50 |  |  |  |  |  |  | my %noncountries = map { $_ => 1 } qw( | 
| 51 |  |  |  |  |  |  | AN BU CS DD FX NT SU TP YD YU ZR | 
| 52 |  |  |  |  |  |  | EU QO | 
| 53 |  |  |  |  |  |  | ); | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | # deprecated aliases | 
| 56 |  |  |  |  |  |  | my %alias_of = ( | 
| 57 |  |  |  |  |  |  | QU => 'EU', | 
| 58 |  |  |  |  |  |  | UK => 'GB', | 
| 59 |  |  |  |  |  |  | ); | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | sub coerce_region { | 
| 62 |  |  |  |  |  |  | my ($region) = @_; | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | return sprintf('%03d', $region) | 
| 65 |  |  |  |  |  |  | if looks_like_number $region; | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | return $alias_of{uc $region} | 
| 68 |  |  |  |  |  |  | || uc $region; | 
| 69 |  |  |  |  |  |  | } | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | sub coerce_regions { | 
| 72 |  |  |  |  |  |  | my ($regions) = @_; | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | return [ | 
| 75 |  |  |  |  |  |  | map { coerce_region($_) } | 
| 76 |  |  |  |  |  |  | ref $regions eq 'ARRAY' ? @$regions : $regions | 
| 77 |  |  |  |  |  |  | ]; | 
| 78 |  |  |  |  |  |  | } | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 2 |  |  | 2 |  | 5025 | use namespace::clean; | 
|  | 2 |  |  |  |  | 20842 |  | 
|  | 2 |  |  |  |  | 10 |  | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | has _includes => ( | 
| 83 |  |  |  |  |  |  | is       => 'ro', | 
| 84 |  |  |  |  |  |  | coerce   => sub { coerce_regions(shift) }, | 
| 85 |  |  |  |  |  |  | default  => sub { [] }, | 
| 86 |  |  |  |  |  |  | init_arg => 'include', | 
| 87 |  |  |  |  |  |  | ); | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | has _excludes => ( | 
| 90 |  |  |  |  |  |  | is       => 'ro', | 
| 91 |  |  |  |  |  |  | coerce   => sub { coerce_regions(shift) }, | 
| 92 |  |  |  |  |  |  | default  => sub { [] }, | 
| 93 |  |  |  |  |  |  | init_arg => 'exclude', | 
| 94 |  |  |  |  |  |  | ); | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | has _children => ( | 
| 97 |  |  |  |  |  |  | is      => 'lazy', | 
| 98 |  |  |  |  |  |  | builder => sub { | 
| 99 | 11 |  |  | 11 |  | 401 | my $self = shift; | 
| 100 | 11 |  |  |  |  | 14 | my $build_children; | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 50 |  |  |  |  | 92 | $build_children = sub { map { | 
| 103 | 72 |  |  | 72 |  | 75 | $_, exists $children_of{$_} | 
| 104 | 596 | 100 |  |  |  | 773 | ? $build_children->(@{$children_of{$_}}) | 
| 105 |  |  |  |  |  |  | : () | 
| 106 | 11 |  |  |  |  | 60 | } @_ }; | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 29 |  |  |  |  | 42 | my %excludes = map { $_ => 1 } | 
|  | 11 |  |  |  |  | 46 |  | 
| 109 | 11 |  |  |  |  | 22 | $build_children->(@{$self->_excludes}); | 
| 110 |  |  |  |  |  |  |  | 
| 111 | 511 |  |  |  |  | 648 | my %children = map  { $_ => 1 } | 
|  | 567 |  |  |  |  | 515 |  | 
| 112 | 11 |  |  |  |  | 33 | grep { !exists $excludes{$_} } | 
| 113 | 11 |  |  |  |  | 22 | $build_children->(@{$self->_includes}); | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 11 |  |  |  |  | 100 | weaken $build_children; | 
| 116 | 11 |  |  |  |  | 66 | return \%children; | 
| 117 |  |  |  |  |  |  | }, | 
| 118 |  |  |  |  |  |  | ); | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | has _parents => ( | 
| 121 |  |  |  |  |  |  | is      => 'lazy', | 
| 122 |  |  |  |  |  |  | builder => sub { | 
| 123 | 7 |  |  | 7 |  | 377 | my @regions = @{shift->_includes}; | 
|  | 7 |  |  |  |  | 32 |  | 
| 124 | 7 |  |  |  |  | 13 | my ($build_parents, %count); | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 28 |  |  |  |  | 27 | $build_parents = sub { map { | 
| 127 | 35 |  |  | 35 |  | 100 | my $region = $_; | 
| 128 |  |  |  |  |  |  | $region, $build_parents->(grep { | 
| 129 | 28 |  |  |  |  | 125 | any { $_ eq $region } @{$children_of{$_}} | 
|  | 896 |  |  |  |  | 1308 |  | 
|  | 9240 |  |  |  |  | 6453 |  | 
|  | 896 |  |  |  |  | 1381 |  | 
| 130 |  |  |  |  |  |  | } keys %children_of); | 
| 131 | 7 |  |  |  |  | 43 | } @_ }; | 
| 132 |  |  |  |  |  |  |  | 
| 133 | 16 |  |  |  |  | 28 | my %parents = map  { $_ => 1 } | 
|  | 28 |  |  |  |  | 50 |  | 
| 134 | 7 |  |  |  |  | 19 | grep { ++$count{$_} == @regions } | 
| 135 |  |  |  |  |  |  | $build_parents->(@regions); | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 7 |  |  |  |  | 49 | weaken $build_parents; | 
| 138 | 7 |  |  |  |  | 43 | return \%parents; | 
| 139 |  |  |  |  |  |  | }, | 
| 140 |  |  |  |  |  |  | ); | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | has _countries => ( | 
| 143 |  |  |  |  |  |  | is      => 'lazy', | 
| 144 |  |  |  |  |  |  | builder => sub { [ | 
| 145 |  |  |  |  |  |  | sort | 
| 146 | 355 | 100 |  |  |  | 1212 | grep { /^[A-Z]{2}$/ && !exists $noncountries{$_} } | 
|  | 10 |  |  |  |  | 159 |  | 
| 147 | 10 |  |  | 10 |  | 452 | keys %{shift->_children} | 
| 148 |  |  |  |  |  |  | ] }, | 
| 149 |  |  |  |  |  |  | ); | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | sub BUILDARGS { | 
| 152 | 12 |  |  | 12 | 0 | 27305 | my ($class, @args) = @_; | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | # the `include` key is optional for the first argument | 
| 155 | 12 | 100 | 100 |  |  | 121 | my %args = @args == 1 && ref $args[0] eq 'HASH' ? %{$args[0]}        : | 
|  | 1 | 100 |  |  |  | 4 |  | 
| 156 |  |  |  |  |  |  | @args % 2                            ? (include => @args) : | 
| 157 |  |  |  |  |  |  | @args              ; | 
| 158 |  |  |  |  |  |  |  | 
| 159 | 12 | 100 |  |  |  | 38 | if (exists $args{region}) { | 
| 160 | 1 |  |  |  |  | 26 | carp 'Argument "region" is deprecated; use "include" instead'; | 
| 161 | 1 |  |  |  |  | 469 | $args{include} = delete $args{region}; | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 | 12 |  |  |  |  | 277 | return \%args; | 
| 165 |  |  |  |  |  |  | } | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | sub contains { | 
| 168 | 37 |  |  | 37 | 1 | 8406 | my ($self, $region) = @_; | 
| 169 | 37 |  |  |  |  | 897 | return exists $self->_children->{ coerce_region($region) }; | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | sub is_within { | 
| 173 | 17 |  |  | 17 | 1 | 81 | my ($self, $region) = @_; | 
| 174 | 17 |  |  |  |  | 359 | return exists $self->_parents->{ coerce_region($region) }; | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | sub countries { | 
| 178 | 10 |  |  | 10 | 1 | 491 | my ($self) = @_; | 
| 179 | 10 |  |  |  |  | 29 | return @{$self->_countries}; | 
|  | 10 |  |  |  |  | 216 |  | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | 1; | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | __END__ |