File Coverage

blib/lib/Geo/States.pm
Criterion Covered Total %
statement 39 43 90.7
branch 11 14 78.5
condition 3 3 100.0
subroutine 10 14 71.4
pod 0 2 0.0
total 63 76 82.8


line stmt bran cond sub pod time code
1             package Geo::States;
2              
3 3     3   3172 use strict;
  3         7  
  3         134  
4 3     3   17 use warnings;
  3         6  
  3         101  
5              
6 3     3   3755 use utf8;
  3         35  
  3         22  
7 3     3   107 use Carp ();
  3         143  
  3         3224  
8              
9             our $VERSION = '0.04';
10              
11             # first, our giant data structure
12             our %state_abbr = (
13             us => {
14             al => {text => 'Alabama', capital => 'Montgomery'},
15             ak => {text => 'Alaska', capital => 'Juneau'},
16             as => {text => 'American Samoa', capital => 'Pago Pago'},
17             az => {text => 'Arizona', capital => 'Phoenix'},
18             ar => {text => 'Arkansas', capital => 'Little Rock'},
19             ca => {text => 'California', capital => 'Sacramento'},
20             co => {text => 'Colorado', capital => 'Denver'},
21             ct => {text => 'Connecticut', capital => 'Hartford'},
22             de => {text => 'Delaware', capital => 'Dover'},
23             dc => {text => 'District of Columbia', capital => undef },
24             fl => {text => 'Florida', capital => 'Tallahassee'},
25             ga => {text => 'Georgia', capital => 'Atlanta'},
26             gu => {text => 'Guam', capital => 'Hagåtña'},
27             hi => {text => 'Hawaii', capital => 'Honolulu'},
28             id => {text => 'Idaho', capital => 'Boise'},
29             il => {text => 'Illinois', capital => 'Springfield'},
30             in => {text => 'Indiana', capital => 'Indianapolis'},
31             ia => {text => 'Iowa', capital => 'Des Moines'},
32             ks => {text => 'Kansas', capital => 'Topeka'},
33             ky => {text => 'Kentucky', capital => 'Frankfort'},
34             la => {text => 'Louisiana', capital => 'Baton Rouge'},
35             me => {text => 'Maine', capital => 'Augusta'},
36             md => {text => 'Maryland', capital => 'Annapolis'},
37             ma => {text => 'Massachusetts', capital => 'Boston'},
38             mi => {text => 'Michigan', capital => 'Lansing'},
39             mn => {text => 'Minnesota', capital => 'St. Paul'},
40             ms => {text => 'Mississippi', capital => 'Jackson'},
41             mo => {text => 'Missouri', capital => 'Jefferson City'},
42             mt => {text => 'Montana', capital => 'Helena'},
43             ne => {text => 'Nebraska', capital => 'Lincoln'},
44             nv => {text => 'Nevada', capital => 'Carson City'},
45             nh => {text => 'New Hampshire', capital => 'Concord'},
46             nj => {text => 'New Jersey', capital => 'Trenton'},
47             nm => {text => 'New Mexico', capital => 'Santa Fe'},
48             ny => {text => 'New York', capital => 'Albany'},
49             nc => {text => 'North Carolina', capital => 'Raleigh'},
50             nd => {text => 'North Dakota', capital => 'Bismarck'},
51             mp => {text => 'Northern Mariana Islands', capital => 'Capitol Hill'},
52             oh => {text => 'Ohio', capital => 'Columbus'},
53             ok => {text => 'Oklahoma', capital => 'Oklahoma City'},
54             or => {text => 'Oregon', capital => 'Salem'},
55             pa => {text => 'Pennsylvania', capital => 'Harrisburg'},
56             pr => {text => 'Puerto Rico', capital => 'San Juan'},
57             ri => {text => 'Rhode Island', capital => 'Providence'},
58             sc => {text => 'South Carolina', capital => 'Columbia'},
59             sd => {text => 'South Dakota', capital => 'Pierre'},
60             tn => {text => 'Tennessee', capital => 'Nashville'},
61             tx => {text => 'Texas', capital => 'Austin'},
62             ut => {text => 'Utah', capital => 'Salt Lake City'},
63             vi => {text => 'Virgin Islands', capital => 'Charlotte Amalie'},
64             vt => {text => 'Vermont', capital => 'Montpelier'},
65             va => {text => 'Virginia', capital => 'Richmond'},
66             wa => {text => 'Washington', capital => 'Olympia'},
67             wv => {text => 'West Virginia', capital => 'Charleston'},
68             wi => {text => 'Wisconsin', capital => 'Madison'},
69             wy => {text => 'Wyoming', capital => 'Cheyenne'},
70             },
71             ca => {
72             ab => {text => 'Alberta', capital => 'Edmonton'},
73             bc => {text => 'British Columbia', capital => 'Victoria'},
74             mb => {text => 'Manitoba', capital => 'Winnipeg'},
75             nb => {text => 'New Brunswick', capital => 'Fredericton'},
76             nl => {text => 'Newfoundland and Labrador', capital => q},
77             ns => {text => 'Nova Scotia', capital => 'Halifax'},
78             nt => {text => 'Northwest Territories', capital => 'Yellowknife'},
79             nu => {text => 'Nunavut', capital => 'Iqaluit'},
80             on => {text => 'Ontario', capital => 'Toronto'},
81             pe => {text => 'Prince Edward Island', capital => 'Charlottetown'},
82             qc => {text => 'Quebec', capital => 'Quebec City'},
83             sk => {text => 'Saskatchewan', capital => 'Regina'},
84             yt => {text => 'Yukon', capital => 'Whitehorse'},
85             },
86             );
87              
88             our %state_name;
89             our %objects;
90              
91             sub new {
92 3     3 0 2334 my ($class, $country) = @_;
93              
94 3 50       22 Carp::croak 'Usage: Geo::States->new($COUNTRY)' unless $country;
95              
96 3         23 $country = lc($country);
97              
98 3 100 100     54 Carp::croak "Supported country codes include US and CA"
99             unless $country eq 'us' or $country eq 'ca';
100              
101             # we already have a hash written, this code will
102             # build the same hash with the names and abbrv. swapped
103 2         4 while (my ($key, $val) = each %{$state_abbr{$country}}) {
  71         238  
104 69         1049 $state_name{$country}{lc($val->{text})} = {text => uc($key), capital => $val->{capital}};
105             }
106              
107 2         16 bless({country => $country}, $class);
108             }
109              
110             # I've done some hackery here. you can decide if it's good or bad
111             # I want to access the find() function like an object
112             #
113             # This is because I think this syntax is nice:
114             # say $geo->find('TN')->text
115             sub find {
116 16     16 0 1060 my $self = shift;
117 16 50       49 my $state = shift or return undef;
118              
119 16         34 my $country = $self->{country};
120              
121 16         28 $state = lc($state);
122              
123             # if we have already blessed code for this state, return it
124             # this avoids redefining the same subroutines
125 16 100       234 return $objects{$state} if $objects{$state};
126              
127 10 100       65 my $data = length($state) == 2 ? #
    100          
128             $state_abbr{$country}{$state}
129             : $state_name{$country}{$state}
130             or return undef;
131              
132 8         21 $state =~ s/\s/::/g;
133 8         19 my $class = ref($self) . "::$state";
134              
135             # and basically here I've done something similar
136             # to what I read in the Mojo::Base attributes code
137             # I make my own class with methods (text and capital), bless and return
138 8         18 my $code = "package $class;\n";
139 8         27 for my $sub (keys %$data) {
140 16         660 $code .= "sub $sub { '$data->{$sub}' };\n";
141             }
142 8 50   0   808 eval "$code;1" or Carp::croak "Geo::States error: $@";
  0     0   0  
  0     1   0  
  1     1   5  
  1     4   6  
  4     0   21  
  0     0   0  
  0     4   0  
  4         17  
143 8         32 my $ref = bless(\$code, $class);
144 8         20 $objects{$state} = $ref;
145 8         124 $ref;
146             }
147              
148             1;
149             __END__