File Coverage

blib/lib/Geo/Coder/Googlev3.pm
Criterion Covered Total %
statement 100 103 97.0
branch 35 42 83.3
condition 4 9 44.4
subroutine 17 17 100.0
pod 6 8 75.0
total 162 179 90.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   526 use strict;
  1         1  
  1         27  
14 1     1   3 use vars qw($VERSION);
  1         1  
  1         43  
15             our $VERSION = '0.15';
16              
17 1     1   11 use Carp ('croak');
  1         1  
  1         33  
18 1     1   480 use Encode ();
  1         6170  
  1         16  
19 1     1   532 use JSON::XS ();
  1         3499  
  1         19  
20 1     1   514 use LWP::UserAgent ();
  1         27584  
  1         16  
21 1     1   4 use URI ();
  1         1  
  1         10  
22 1     1   353 use URI::QueryParam ();
  1         441  
  1         509  
23              
24             sub new {
25 9     9 1 5145 my($class, %args) = @_;
26 9         19 my $self = bless {}, $class;
27             $self->{ua} = delete $args{ua} ||
28 9   33     108 LWP::UserAgent->new(
29             agent => __PACKAGE__ . "/$VERSION libwww-perl/$LWP::VERSION",
30             env_proxy => 1,
31             timeout => 15,
32             );
33 9   33     6215 $self->{region} = delete $args{region} || delete $args{gl};
34 9         17 $self->{language} = delete $args{language};
35             {
36 9         12 my $sensor;
  9         9  
37 9 100       20 if ($args{sensor}) {
38 3         4 $sensor = delete $args{sensor};
39 3 100       15 if ($sensor !~ m{^(false|true)$}) {
40 1         138 croak "sensor argument has to be either 'false' or 'true'";
41             }
42             } else {
43 6         10 $sensor = 'false';
44             }
45 8         17 $self->{sensor} = $sensor;
46             }
47 8 100       18 if ($args{bounds}) {
48 1         5 $self->bounds(delete $args{bounds});
49             }
50 8 50       29 croak "Unsupported arguments: " . join(" ", %args) if %args;
51 8         21 $self;
52             }
53              
54             sub ua {
55 14     14 0 16 my $self = shift;
56 14 50       31 if (@_) {
57 0         0 $self->{ua} = shift;
58             }
59 14         24 $self->{ua};
60             }
61              
62             sub geocode {
63 14     14 1 30428 my($self, %args) = @_;
64 14         27 my $raw = delete $args{raw};
65 14         48 my $url = $self->geocode_url(%args);
66 14         50 my $ua = $self->ua;
67 14         51 my $resp = $ua->get($url);
68 14 50       4829890 if ($resp->is_success) {
69 14         181 my $content = $resp->decoded_content(charset => "none");
70 14         2184 my $res = JSON::XS->new->utf8->decode($content);
71 14 100       109 if ($raw) {
72 1         13 return $res;
73             }
74 13 100       51 if ($res->{status} eq 'OK') {
    50          
75 11 100       25 if (wantarray) {
76 1         3 return @{ $res->{results} };
  1         46  
77             } else {
78 10         166 return $res->{results}->[0];
79             }
80             } elsif ($res->{status} eq 'ZERO_RESULTS') {
81 2         37 return;
82             } else {
83 0         0 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 34 my($self, %args) = @_;
93 17         24 my $loc = $args{location};
94 17         76 my $url = URI->new('http://maps.google.com/maps/api/geocode/json');
95 17         6331 my %url_params;
96 17         43 $url_params{address} = $loc;
97 17         36 $url_params{sensor} = $self->{sensor};
98 17 100       57 $url_params{region} = $self->{region} if defined $self->{region};
99 17 100       38 $url_params{language} = $self->{language} if defined $self->{language};
100 17 100       44 if (defined $self->{bounds}) {
101 1         2 $url_params{bounds} = join '|', map { $_->{lat}.','.$_->{lng} } @{ $self->{bounds} };
  2         22  
  1         2  
102             }
103 17         67 while(my($k,$v) = each %url_params) {
104 38         2458 $url->query_param($k => Encode::encode_utf8($v));
105             }
106 17         2333 $url = $url->as_string;
107 17         98 $url;
108             }
109              
110             sub region {
111 1     1 1 1 my $self = shift;
112 1 50       5 $self->{region} = shift if @_;
113 1         3 return $self->{region};
114             }
115              
116              
117             sub language {
118 1     1 1 6 my $self = shift;
119 1 50       3 $self->{language} = shift if @_;
120 1         4 return $self->{language};
121             }
122              
123             sub sensor {
124 3     3 1 890 my $self = shift;
125 3 50       10 $self->{sensor} = shift if @_;
126 3         13 return $self->{sensor};
127             }
128              
129 1     1   4 use constant _BOUNDS_ERROR_MSG => "bounds must be in the form [{lat=>...,lng=>...}, {lat=>...,lng=>...}]";
  1         1  
  1         160  
130              
131             sub bounds {
132 7     7 1 2131 my $self = shift;
133 7 100       18 if (@_) {
134 5         7 my $bounds = shift;
135 5 100       13 if (ref $bounds ne 'ARRAY') {
136 1         162 croak _BOUNDS_ERROR_MSG . ', but the supplied parameter is not even an array reference.';
137             }
138 4 100       11 if (@$bounds != 2) {
139 1         62 croak _BOUNDS_ERROR_MSG . ', but the supplied parameter has not exactly two array elements.';
140             }
141 3 100 66     5 if ((grep { ref $_ eq 'HASH' && exists $_->{lng} && exists $_->{lat} ? 1 : 0 } @$bounds) != 2) {
  6 100       33  
142 2         127 croak _BOUNDS_ERROR_MSG . ', but the supplied elements are not lat/lng hashes.';
143             }
144 1         2 $self->{bounds} = $bounds;
145             }
146 3         12 return $self->{bounds};
147             }
148              
149             1;
150              
151             __END__