File Coverage

blib/lib/Geo/Coder/Googlev3.pm
Criterion Covered Total %
statement 103 105 98.1
branch 41 48 85.4
condition 6 9 66.6
subroutine 17 17 100.0
pod 6 8 75.0
total 173 187 92.5


line stmt bran cond sub pod time code
1             # -*- mode:perl; coding:iso-8859-1 -*-
2              
3             #
4             # Author: Slaven Rezic
5             #
6             # Copyright (C) 2010,2011,2013,2014,2017 Slaven Rezic. All rights reserved.
7             # This package is free software; you can redistribute it and/or
8             # modify it under the same terms as Perl itself.
9             #
10              
11             package Geo::Coder::Googlev3;
12              
13 1     1   752 use strict;
  1         2  
  1         28  
14 1     1   5 use vars qw($VERSION);
  1         2  
  1         51  
15             our $VERSION = '0.16';
16              
17 1     1   5 use Carp ('croak');
  1         2  
  1         37  
18 1     1   441 use Encode ();
  1         8379  
  1         27  
19 1     1   530 use JSON::XS ();
  1         2610  
  1         37  
20 1     1   505 use LWP::UserAgent ();
  1         36297  
  1         24  
21 1     1   8 use URI ();
  1         2  
  1         12  
22 1     1   378 use URI::QueryParam ();
  1         692  
  1         570  
23              
24             sub new {
25 11     11 1 8645 my($class, %args) = @_;
26 11         44 my $self = bless {}, $class;
27             $self->{ua} = delete $args{ua} ||
28 11   33     166 LWP::UserAgent->new(
29             agent => __PACKAGE__ . "/$VERSION libwww-perl/$LWP::VERSION",
30             env_proxy => 1,
31             timeout => 15,
32             );
33 11   66     14521 $self->{region} = delete $args{region} || delete $args{gl};
34 11         43 $self->{language} = delete $args{language};
35             {
36 11         24 my $sensor;
  11         26  
37 11 100       40 if ($args{sensor}) {
38 3         9 $sensor = delete $args{sensor};
39 3 100       21 if ($sensor !~ m{^(false|true)$}) {
40 1         171 croak "sensor argument has to be either 'false' or 'true'";
41             }
42             }
43 10         34 $self->{sensor} = $sensor;
44             }
45 10 100       40 if ($args{bounds}) {
46 1         8 $self->bounds(delete $args{bounds});
47             }
48 10         39 $self->{key} = delete $args{key};
49 10         28 $self->{use_https} = delete $args{use_https};
50 10 50       37 croak "Unsupported arguments: " . join(" ", %args) if %args;
51 10         41 $self;
52             }
53              
54             sub ua {
55 17     17 0 50 my $self = shift;
56 17 50       138 if (@_) {
57 0         0 $self->{ua} = shift;
58             }
59 17         62 $self->{ua};
60             }
61              
62             sub geocode {
63 16     16 1 64806 my($self, %args) = @_;
64 16         69 my $raw = delete $args{raw};
65 16         106 my $url = $self->geocode_url(%args);
66 16         90 my $ua = $self->ua;
67 16         111 my $resp = $ua->get($url);
68 16 50       1407300 if ($resp->is_success) {
69 16         348 my $content = $resp->decoded_content(charset => "none");
70 16         4461 my $res = JSON::XS->new->utf8->decode($content);
71 16 100       190 if ($raw) {
72 1         17 return $res;
73             }
74 15 100       103 if ($res->{status} eq 'OK') {
    100          
75 11 100       58 if (wantarray) {
76 1         2 return @{ $res->{results} };
  1         18  
77             } else {
78 10         290 return $res->{results}->[0];
79             }
80             } elsif ($res->{status} eq 'ZERO_RESULTS') {
81 2         51 return;
82             } else {
83 2         314 croak "Fetching $url did not return OK status, but '" . $res->{status} . "'";
84             }
85             } else {
86 0         0 croak "Fetching $url failed: " . $resp->status_line;
87             }
88             }
89              
90             # private!
91             sub geocode_url {
92 19     19 0 82 my($self, %args) = @_;
93 19         68 my $loc = $args{location};
94 19 50       230 my $url = URI->new(($self->{use_https} ? 'https' : 'http') . '://maps.google.com/maps/api/geocode/json');
95 19         10630 my %url_params;
96 19         77 $url_params{address} = $loc;
97 19 100       102 $url_params{sensor} = $self->{sensor} if defined $self->{sensor};
98 19 100       90 $url_params{region} = $self->{region} if defined $self->{region};
99 19 100       82 $url_params{language} = $self->{language} if defined $self->{language};
100 19 100       93 if (defined $self->{bounds}) {
101 2         7 $url_params{bounds} = join '|', map { $_->{lat}.','.$_->{lng} } @{ $self->{bounds} };
  4         80  
  2         12  
102             }
103 19 100       88 $url_params{key} = $self->{key} if defined $self->{key};
104 19         123 while(my($k,$v) = each %url_params) {
105 27         2304 $url->query_param($k => Encode::encode_utf8($v));
106             }
107 19         5262 $url = $url->as_string;
108 19         251 $url;
109             }
110              
111             sub region {
112 1     1 1 4 my $self = shift;
113 1 50       8 $self->{region} = shift if @_;
114 1         11 return $self->{region};
115             }
116              
117              
118             sub language {
119 1     1 1 11 my $self = shift;
120 1 50       7 $self->{language} = shift if @_;
121 1         8 return $self->{language};
122             }
123              
124             sub sensor {
125 3     3 1 953 my $self = shift;
126 3 50       15 $self->{sensor} = shift if @_;
127 3         15 return $self->{sensor};
128             }
129              
130 1     1   7 use constant _BOUNDS_ERROR_MSG => "bounds must be in the form [{lat=>...,lng=>...}, {lat=>...,lng=>...}]";
  1         3  
  1         257  
131              
132             sub bounds {
133 7     7 1 3324 my $self = shift;
134 7 100       27 if (@_) {
135 5         11 my $bounds = shift;
136 5 100       22 if (ref $bounds ne 'ARRAY') {
137 1         211 croak _BOUNDS_ERROR_MSG . ', but the supplied parameter is not even an array reference.';
138             }
139 4 100       17 if (@$bounds != 2) {
140 1         82 croak _BOUNDS_ERROR_MSG . ', but the supplied parameter has not exactly two array elements.';
141             }
142 3 100 100     9 if ((grep { ref $_ eq 'HASH' && exists $_->{lng} && exists $_->{lat} ? 1 : 0 } @$bounds) != 2) {
  6 100       50  
143 2         131 croak _BOUNDS_ERROR_MSG . ', but the supplied elements are not lat/lng hashes.';
144             }
145 1         5 $self->{bounds} = $bounds;
146             }
147 3         21 return $self->{bounds};
148             }
149              
150             1;
151              
152             __END__