--- /dev/null
+package Geo::USCensus::Geocoding;
+
+use strict;
+use warnings;
+
+use LWP::UserAgent;
+use JSON;
+use URI;
+use Geo::USCensus::Geocoding::Match;
+
+=head1 NAME
+
+Geo::USCensus::Geocoding - The U.S. Census Bureau geocoding service
+
+=head1 VERSION
+
+Version 0.01
+
+=cut
+
+our $VERSION = '0.01';
+our $DEBUG = 1;
+
+=head1 SYNOPSIS
+
+ use Geo::USCensus::Geocoding;
+
+ my $request = {
+ # required fields
+ street => '123 Main Street',
+ city => 'San Francisco', # city
+ state => 'CA', # state/province
+ zip => '93102', # zip/postal code
+ # optional fields
+ benchmark => 'Public_AR_ACS2013', # default is "Public_AR_Current"
+ vintage => 'Census2010_ACS2013', # default is "Current_Current"
+ };
+ my $result = Geo::USCensus::Geocoding->query($request);
+
+ if ($result->matches) {
+ my $match = $result->match(0);
+ print $match->matchedAddress,"\n",
+ $match->coordinates->{x},',',$match->coordinates->{y},"\n",
+ $match->censustract,"\n";
+ }
+
+=head1 CLASS METHODS
+
+=head2 query HASHREF
+
+Send a request to the web service. See
+L<http://geocoding.geo.census.gov/geocoder> for API documentation. This
+package will always use the JSON data format and the Geographies return type.
+
+Returns an object of class Geo::USCensus::Geocoding.
+
+=cut
+
+my $ua = LWP::UserAgent->new;
+my $api_uri = 'http://geocoding.geo.census.gov/geocoder/geographies/address';
+
+sub query {
+ my $class = shift;
+ my %opt = (
+ benchmark => 'Public_AR_Current',
+ vintage => 'Current_Current',
+ );
+ if (ref $_[0] eq 'HASH') {
+ %opt = (%opt, %{ $_[0] });
+ } else {
+ %opt = (%opt, @_);
+ }
+
+ $opt{format} = 'json';
+
+ foreach (qw(street city state zip)) {
+ die "$_ required\n" unless length($opt{$_});
+ }
+
+ my $uri = URI->new($api_uri);
+ $uri->query_form(\%opt);
+ warn "$class->query\n$uri\n\n" if $DEBUG;
+ my $http_req = HTTP::Request->new(GET => $uri->as_string);
+ my $resp = $ua->request($http_req);
+ my $self = { addr_response => $resp };
+ bless $self, $class;
+ if ( $resp->is_success ) {
+ local $@;
+ my $tree = eval { from_json($resp->content) };
+ if ($@) {
+ $self->message("Unable to parse response:\n$@");
+ return $self;
+ }
+ if (!exists $tree->{result}) {
+ $self->message("Response does not contain geocoding results.");
+ warn $self->message. "\n".$resp->content."\n\n";
+ return $self;
+ }
+ $tree = $tree->{result};
+
+ my @matches;
+ if (exists( $tree->{addressMatches} )) {
+ foreach my $am (@{ $tree->{addressMatches} }) {
+ push @matches, Geo::USCensus::Geocoding::Match->new($am);
+ }
+ } # else what? does this happen if there's no match? a proper REST
+ # interface should throw a 404
+ $self->{matches} = \@matches;
+ } else {
+ $self->message( $resp->status_line );
+ }
+ $self;
+}
+
+=head1 METHODS
+
+=head2 message
+
+Sets/gets an explicit error status.
+
+=cut
+
+sub message {
+ my $self = shift;
+ if (@_) {
+ $self->{_message} = shift;
+ }
+ $self->{_message} || '';
+}
+
+=head2 matches
+
+Returns the number of matches found.
+
+=cut
+
+sub matches {
+ my $self = shift;
+ $self->{matches} ? scalar @{ $self->{matches} } : 0;
+}
+
+=head2 match NUMBER
+
+Returns a specific match (starting from zero). Matches are returned
+as L<Geo::USCensus::Geocoding::Match> objects, in the order they were
+returned by the service.
+
+=cut
+
+sub match {
+ my $self = shift;
+ my $i = shift;
+ $self->{matches}->[$i];
+}
+
+=head1 AUTHOR
+
+Mark Wells, C<< <mark at freeside.biz> >>
+
+=head1 SUPPORT
+
+Commercial support for this module is available from Freeside Internet
+Services:
+
+ L<http://www.freeside.biz/>
+
+=back
+
+
+=head1 LICENSE AND COPYRIGHT
+
+Copyright (C) 2014 Mark Wells.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of either: the GNU General Public License as published
+by the Free Software Foundation; or the Artistic License.
+
+See http://dev.perl.org/licenses/ for more information.
+
+=cut
+
+1;
--- /dev/null
+Geo-USCensus-Geocoding
+
+Interface to the U.S. Census Bureau geocoding service.
+
+INSTALLATION
+
+To install this module, run the following commands:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+SUPPORT AND DOCUMENTATION
+
+After installing, you can find documentation for this module with the
+perldoc command.
+
+ perldoc Geo::USCensus::Geocoding
+
+You can also look for information at:
+
+ RT, CPAN's request tracker (report bugs here)
+ http://rt.cpan.org/NoAuth/Bugs.html?Dist=Geo-USCensus-Geocoding
+
+ AnnoCPAN, Annotated CPAN documentation
+ http://annocpan.org/dist/Geo-USCensus-Geocoding
+
+ CPAN Ratings
+ http://cpanratings.perl.org/d/Geo-USCensus-Geocoding
+
+ Search CPAN
+ http://search.cpan.org/dist/Geo-USCensus-Geocoding/
+
+
+LICENSE AND COPYRIGHT
+
+Copyright (C) 2014 Mark Wells
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of either: the GNU General Public License as published
+by the Free Software Foundation; or the Artistic License.
+
+See http://dev.perl.org/licenses/ for more information.
+