File Coverage

blib/lib/Geo/States.pm
Criterion Covered Total %
statement 42 43 97.6
branch 11 14 78.5
condition 3 3 100.0
subroutine 13 14 92.8
pod 0 2 0.0
total 69 76 90.7


line stmt bran cond sub pod time code
1             package Geo::States;
2              
3 5     5   2464 use strict;
  5         6  
  5         127  
4 5     5   18 use warnings;
  5         5  
  5         164  
5              
6 5     5   2410 use utf8;
  5         39  
  5         26  
7 5     5   119 use Carp ();
  5         6  
  5         2967  
8              
9             our $VERSION = '0.05';
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 => '' },
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 7     7 0 1638 my ($class, $country) = @_;
93              
94 7 50       20 Carp::croak 'Usage: Geo::States->new($COUNTRY)' unless $country;
95              
96 7         13 $country = lc($country);
97              
98 7 100 100     52 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 6         6 while (my ($key, $val) = each %{$state_abbr{$country}}) {
  213         343  
104 207         447 $state_name{$country}{lc($val->{text})} = {text => uc($key), capital => $val->{capital}};
105             }
106              
107 6         17 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 28     28 0 1326 my $self = shift;
117 28 50       56 my $state = shift or return undef;
118              
119 28         33 my $country = $self->{country};
120              
121 28         35 $state = lc($state);
122              
123             # if we have already blessed code for this state, return it
124             # this avoids redefining the same subroutines
125 28         63 (my $subclass = $state) =~ s/\s/::/g;
126 28 100       307 return $objects{$subclass} if $objects{$subclass};
127              
128             my $data = length($state) == 2 ? #
129             $state_abbr{$country}{$state}
130 16 100       55 : $state_name{$country}{$state}
    100          
131             or return undef;
132              
133 14         20 my $class = ref($self) . "::$subclass";
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 14         20 my $code = "package $class;\n";
139 14         33 for my $sub (keys %$data) {
140 28         51 $code .= "sub $sub { '$data->{$sub}' };\n";
141             }
142 14 50   3   1015 eval "$code;1" or Carp::croak "Geo::States error: $@";
  3     3   7  
  3     1   12  
  1     1   4  
  1     1   4  
  1     5   3  
  5     4   16  
  4     0   14  
  0            
143 14         23 my $ref = bless(\$code, $class);
144 14         20 $objects{$subclass} = $ref;
145 14         119 $ref;
146             }
147              
148             1;
149             __END__