File Coverage

blib/lib/Geo/Coder/Googlev3.pm
Criterion Covered Total %
statement 96 105 91.4
branch 35 48 72.9
condition 6 9 66.6
subroutine 16 17 94.1
pod 6 8 75.0
total 159 187 85.0


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,2018 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   644 use strict;
  1         2  
  1         23  
14 1     1   4 use vars qw($VERSION);
  1         1  
  1         50  
15             our $VERSION = '0.17';
16              
17 1     1   5 use Carp ('croak');
  1         1  
  1         40  
18 1     1   442 use Encode ();
  1         7537  
  1         17  
19 1     1   477 use JSON::XS ();
  1         2260  
  1         16  
20 1     1   514 use LWP::UserAgent ();
  1         34932  
  1         19  
21 1     1   6 use URI ();
  1         2  
  1         12  
22 1     1   378 use URI::QueryParam ();
  1         571  
  1         594  
23              
24             sub new {
25 6     6 1 3527 my($class, %args) = @_;
26 6         14 my $self = bless {}, $class;
27             $self->{ua} = delete $args{ua} ||
28 6   33     72 LWP::UserAgent->new(
29             agent => __PACKAGE__ . "/$VERSION libwww-perl/$LWP::VERSION",
30             env_proxy => 1,
31             timeout => 15,
32             );
33 6   66     6923 $self->{region} = delete $args{region} || delete $args{gl};
34 6         16 $self->{language} = delete $args{language};
35             {
36 6         13 my $sensor;
  6         9  
37 6 50       17 if ($args{sensor}) {
38 0         0 $sensor = delete $args{sensor};
39 0 0       0 if ($sensor !~ m{^(false|true)$}) {
40 0         0 croak "sensor argument has to be either 'false' or 'true'";
41             }
42             }
43 6         12 $self->{sensor} = $sensor;
44             }
45 6 100       14 if ($args{bounds}) {
46 1         7 $self->bounds(delete $args{bounds});
47             }
48 6         14 $self->{key} = delete $args{key};
49 6         12 $self->{use_https} = delete $args{use_https};
50 6 50       13 croak "Unsupported arguments: " . join(" ", %args) if %args;
51 6         15 $self;
52             }
53              
54             sub ua {
55 17     17 0 25 my $self = shift;
56 17 50       43 if (@_) {
57 0         0 $self->{ua} = shift;
58             }
59 17         33 $self->{ua};
60             }
61              
62             sub geocode {
63 17     17 1 3032486 my($self, %args) = @_;
64 17         35 my $raw = delete $args{raw};
65 17         81 my $url = $self->geocode_url(%args);
66 17         61 my $ua = $self->ua;
67 17         69 my $resp = $ua->get($url);
68 17 50       5513191 if ($resp->is_success) {
69 17         225 my $content = $resp->decoded_content(charset => "none");
70 17         2672 my $res = JSON::XS->new->utf8->decode($content);
71 17 50       129 if ($raw) {
72 0         0 return $res;
73             }
74 17 100       70 if ($res->{status} eq 'OK') {
    100          
75 11 100       28 if (wantarray) {
76 1         2 return @{ $res->{results} };
  1         15  
77             } else {
78 10         151 return $res->{results}->[0];
79             }
80             } elsif ($res->{status} eq 'ZERO_RESULTS') {
81 1         13 return;
82             } else {
83 5         654 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 17     17 0 55 my($self, %args) = @_;
93 17         40 my $loc = $args{location};
94 17 50       132 my $url = URI->new(($self->{use_https} ? 'https' : 'http') . '://maps.google.com/maps/api/geocode/json');
95 17         6795 my %url_params;
96 17         56 $url_params{address} = $loc;
97 17 50       57 $url_params{sensor} = $self->{sensor} if defined $self->{sensor};
98 17 100       67 $url_params{region} = $self->{region} if defined $self->{region};
99 17 100       53 $url_params{language} = $self->{language} if defined $self->{language};
100 17 100       49 if (defined $self->{bounds}) {
101 1         3 $url_params{bounds} = join '|', map { $_->{lat}.','.$_->{lng} } @{ $self->{bounds} };
  2         27  
  1         3  
102             }
103 17 100       53 $url_params{key} = $self->{key} if defined $self->{key};
104 17         64 while(my($k,$v) = each %url_params) {
105 23         1015 $url->query_param($k => Encode::encode_utf8($v));
106             }
107 17         2927 $url = $url->as_string;
108 17         110 $url;
109             }
110              
111             sub region {
112 1     1 1 3 my $self = shift;
113 1 50       4 $self->{region} = shift if @_;
114 1         5 return $self->{region};
115             }
116              
117              
118             sub language {
119 1     1 1 6 my $self = shift;
120 1 50       4 $self->{language} = shift if @_;
121 1         5 return $self->{language};
122             }
123              
124             sub sensor {
125 0     0 1 0 my $self = shift;
126 0 0       0 $self->{sensor} = shift if @_;
127 0         0 return $self->{sensor};
128             }
129              
130 1     1   6 use constant _BOUNDS_ERROR_MSG => "bounds must be in the form [{lat=>...,lng=>...}, {lat=>...,lng=>...}]";
  1         2  
  1         180  
131              
132             sub bounds {
133 7     7 1 2740 my $self = shift;
134 7 100       20 if (@_) {
135 5         8 my $bounds = shift;
136 5 100       15 if (ref $bounds ne 'ARRAY') {
137 1         126 croak _BOUNDS_ERROR_MSG . ', but the supplied parameter is not even an array reference.';
138             }
139 4 100       11 if (@$bounds != 2) {
140 1         56 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       40  
143 2         107 croak _BOUNDS_ERROR_MSG . ', but the supplied elements are not lat/lng hashes.';
144             }
145 1         6 $self->{bounds} = $bounds;
146             }
147 3         21 return $self->{bounds};
148             }
149              
150             1;
151              
152             __END__