File Coverage

blib/lib/Geo/Coder/US/Census.pm
Criterion Covered Total %
statement 39 74 52.7
branch 2 20 10.0
condition 2 5 40.0
subroutine 12 14 85.7
pod 4 4 100.0
total 59 117 50.4


line stmt bran cond sub pod time code
1             package Geo::Coder::US::Census;
2              
3 4     4   341698 use strict;
  4         30  
  4         112  
4 4     4   18 use warnings;
  4         6  
  4         87  
5              
6 4     4   19 use Carp;
  4         18  
  4         172  
7 4     4   1245 use Encode;
  4         28562  
  4         271  
8 4     4   1477 use JSON;
  4         29039  
  4         22  
9 4     4   1425 use HTTP::Request;
  4         59723  
  4         132  
10 4     4   1638 use LWP::UserAgent;
  4         72155  
  4         149  
11 4     4   1239 use LWP::Protocol::https;
  4         285549  
  4         192  
12 4     4   30 use URI;
  4         7  
  4         75  
13 4     4   1495 use Geo::StreetAddress::US;
  4         142404  
  4         2240  
14              
15             =head1 NAME
16              
17             Geo::Coder::US::Census - Provides a geocoding functionality for the US using http:://geocoding.geo.census.gov
18              
19             =head1 VERSION
20              
21             Version 0.02
22              
23             =cut
24              
25             our $VERSION = '0.02';
26              
27             =head1 SYNOPSIS
28              
29             use Geo::Coder::US::Census;
30              
31             my $geocoder = Geo::Coder::US::Census->new();
32             my $location = $geocoder->geocode(location => '4600 Silver Hill Rd., Suitland, MD, USA');
33              
34             =head1 DESCRIPTION
35              
36             Geo::Coder::US::Census provides an interface to geocoding.geo.census.gov. Geo::Coder::US no longer seems to work.
37              
38             =head1 METHODS
39              
40             =head2 new
41              
42             $geocoder = Geo::Coder::US::Census->new();
43             my $ua = LWP::UserAgent->new();
44             $ua->env_proxy(1);
45             $geocoder = Geo::Coder::US::Census->new(ua => $ua);
46              
47             =cut
48              
49             sub new {
50 2     2 1 2194 my($class, %param) = @_;
51              
52 2   33     29 my $ua = delete $param{ua} || LWP::UserAgent->new(agent => __PACKAGE__ . "/$VERSION");
53 2   50     4194 my $host = delete $param{host} || 'geocoding.geo.census.gov/geocoder/locations/address';
54              
55 2         15 return bless { ua => $ua, host => $host }, $class;
56             }
57              
58             =head2 geocode
59              
60             $location = $geocoder->geocode(location => $location);
61             # @location = $geocoder->geocode(location => $location);
62              
63             print 'Latitude: ', $location->{'latt'}, "\n";
64             print 'Longitude: ', $location->{'longt'}, "\n";
65              
66             =cut
67              
68             sub geocode {
69 1     1 1 612 my $self = shift;
70              
71 1         17 my %param;
72 1 50       5 if (@_ % 2 == 0) {
73 1         3 %param = @_;
74             } else {
75 0         0 $param{location} = shift;
76             }
77              
78             my $location = $param{location}
79 1 50       20 or Carp::croak("Usage: geocode(location => \$location)");
80              
81 0 0         if (Encode::is_utf8($location)) {
82 0           $location = Encode::encode_utf8($location);
83             }
84              
85 0 0         if($location =~ /,?(.+)\s*(United States|US|USA)$/i) {
86 0           $location = $1;
87             }
88              
89 0           my $uri = URI->new("https://$self->{host}");
90 0           $location =~ s/\s/+/g;
91 0           my $hr = Geo::StreetAddress::US->parse_address($location);
92              
93 0           my %query_parameters = ('format' => 'json', 'benchmark' => 'Public_AR_Current');
94 0 0         if($hr->{'street'}) {
95 0 0         if($hr->{'number'}) {
96 0           $query_parameters{'street'} = $hr->{'number'} . ' ' . $hr->{'street'} . ' ' . $hr->{'type'};
97             } else {
98 0           $query_parameters{'street'} = $hr->{'street'} . ' ' . $hr->{'type'};
99             }
100 0 0         if($hr->{'suffix'}) {
101 0           $query_parameters{'street'} .= ' ' . $hr->{'suffix'};
102             }
103             }
104 0           $query_parameters{'city'} = $hr->{'city'};
105 0           $query_parameters{'state'} = $hr->{'state'};
106            
107 0           $uri->query_form(%query_parameters);
108 0           my $url = $uri->as_string();
109              
110 0           my $res = $self->{ua}->get($url);
111              
112 0 0         if($res->is_error()) {
113 0           Carp::croak("geocoding.geo.census.gov API returned error: " . $res->status_line());
114 0           return;
115             }
116              
117 0           my $json = JSON->new->utf8();
118 0           return $json->decode($res->content());
119              
120             # my @results = @{ $data || [] };
121             # wantarray ? @results : $results[0];
122             }
123              
124             =head2 ua
125              
126             Accessor method to get and set UserAgent object used internally. You
127             can call I for example, to get the proxy information from
128             environment variables:
129              
130             $geocoder->ua()->env_proxy(1);
131              
132             You can also set your own User-Agent object:
133              
134             $geocoder->ua(LWP::UserAgent::Throttled->new());
135              
136             =cut
137              
138             sub ua {
139 0     0 1   my $self = shift;
140 0 0         if (@_) {
141 0           $self->{ua} = shift;
142             }
143 0           $self->{ua};
144             }
145              
146             =head2 reverse_geocode
147              
148             # $location = $geocoder->reverse_geocode(latlng => '37.778907,-122.39732');
149              
150             # Similar to geocode except it expects a latitude/longitude parameter.
151              
152             Not supported.
153              
154             =cut
155              
156             sub reverse_geocode {
157 0     0 1   my $self = shift;
158              
159 0           my %param;
160 0 0         if (@_ % 2 == 0) {
161 0           %param = @_;
162             } else {
163 0           $param{latlng} = shift;
164             }
165              
166             # my $latlng = $param{latlng}
167             # or Carp::croak("Usage: reverse_geocode(latlng => \$latlng)");
168              
169             # return $self->geocode(location => $latlng, reverse => 1);
170 0           Carp::croak('Reverse geocode is not supported');
171             };
172              
173             =head1 AUTHOR
174              
175             Nigel Horne
176              
177             Based on L.
178              
179             This library is free software; you can redistribute it and/or modify
180             it under the same terms as Perl itself.
181              
182             Lots of thanks to the folks at geocoding.geo.census.gov.
183              
184             =head1 BUGS
185              
186             Should be called Geo::Coder::NA for North America.
187              
188             =head1 SEE ALSO
189              
190             L, L
191              
192             https://www.census.gov/data/developers/data-sets/Geocoding-services.html
193              
194             =head1 LICENSE AND COPYRIGHT
195              
196             Copyright 2017 Nigel Horne.
197              
198             This program is released under the following licence: GPL2
199              
200             =cut
201              
202             1;