File Coverage

blib/lib/WWW/Google/DistanceMatrix.pm
Criterion Covered Total %
statement 44 92 47.8
branch 12 24 50.0
condition 10 18 55.5
subroutine 11 13 84.6
pod 1 1 100.0
total 78 148 52.7


line stmt bran cond sub pod time code
1             package WWW::Google::DistanceMatrix;
2              
3             $WWW::Google::DistanceMatrix::VERSION = '0.21';
4             $WWW::Google::DistanceMatrix::AUTHORITY = 'cpan:MANWAR';
5              
6             =head1 NAME
7              
8             WWW::Google::DistanceMatrix - Interface to Google Distance Matrix API.
9              
10             =head1 VERSION
11              
12             Version 0.21
13              
14             =cut
15              
16 5     5   68802 use 5.006;
  5         40  
17 5     5   3163 use JSON;
  5         62088  
  5         24  
18 5     5   3801 use Data::Dumper;
  5         38700  
  5         389  
19              
20 5     5   2690 use WWW::Google::UserAgent;
  5         582010  
  5         188  
21 5     5   2642 use WWW::Google::DistanceMatrix::Result;
  5         16  
  5         196  
22 5     5   2939 use WWW::Google::UserAgent::DataTypes -all;
  5         806903  
  5         79  
23 5     5   94719 use WWW::Google::DistanceMatrix::Params qw(validate $FIELDS);
  5         66  
  5         739  
24              
25 5     5   67 use Moo;
  5         11  
  5         43  
26 5     5   2773 use namespace::autoclean;
  5         13  
  5         48  
27             extends 'WWW::Google::UserAgent';
28              
29             our $BASE_URL = 'https://maps.googleapis.com/maps/api/distancematrix';
30             our $REASON = {
31             'INVALID_REQUEST' => 'Indicates that the provided request was invalid.',
32             'MAX_ELEMENTS_EXCEEDED' => 'Indicates that the product of origins and destinations exceeds the per-query limit.',
33             'OVER_QUERY_LIMIT' => 'Indicates the service has received too many requests from your application within the allowed time period.',
34             'REQUEST_DENIED' => 'Indicates that the service denied use of the Distance Matrix service by your application.',
35             'UNKNOWN_ERROR' => 'Indicates a Distance Matrix request could not be processed due to a server error. The request may succeed if you try again.'
36             };
37              
38             has avoid => (is => 'ro', isa => Avoid);
39             has sensor => (is => 'ro', isa => TrueFalse, default => sub { 'false' });
40             has units => (is => 'ro', isa => Unit, default => sub { 'metric' });
41             has mode => (is => 'ro', isa => Mode, default => sub { 'driving' });
42             has language => (is => 'ro', isa => Language, default => sub { 'en' });
43             has output => (is => 'ro', isa => FileType, default => sub { 'json' });
44              
45             =head1 DESCRIPTION
46              
47             The Google Distance Matrix API is a service that provides travel distance & time
48             for a matrix of origins and destinations.The information returned is based on the
49             recommended route between start & end points as calculated by the Google Maps API
50             & consists of rows containing duration and distance values for each pair. The
51             Distance Matrix API has the following limits in place:
52              
53             =over 3
54              
55             =item * 100 elements per query.
56              
57             =item * 100 elements per 10 seconds.
58              
59             =item * 2500 elements per 24 hour period.
60              
61             =back
62              
63             The official Google API document can be found L.
64              
65             =head1 NOTE
66              
67             Use of the Distance Matrix API must relate to the display of information on a
68             Google Map; for example to determine origin-destination pairs that fall within
69             specific driving time from one another before requesting and displaying those
70             destinations on a map.Use of the service in an application that doesn't display a
71             Google map is prohibited.
72              
73             =head1 CONSTRUCTOR
74              
75             The following list of optional parameters can be passed in to the constructor.
76              
77             +----------+----------+-----------------------------------------------------+
78             | key | Required | |
79             +----------+----------+-----------------------------------------------------+
80             | mode | No | Specifies what mode of transport to use when |
81             | | | calculating directions. Valid values are 'driving', |
82             | | | 'walking' and 'bicycling'. Default value is |
83             | | | 'driving'. |
84             | language | No | The language in which to return results. Default is |
85             | | | 'en'. |
86             | avoid | No | Introduces restrictions to the route. Valid values: |
87             | | | 'tolls' and 'highways'. Only one restriction can be |
88             | | | specified. |
89             | units | No | Specifies the unit system to use when expressing |
90             | | | distance as text. Valid values: 'metric' (default) |
91             | | | and 'imperial'. |
92             | sensor | No | Indicates whether your application is using a sensor|
93             | | | (such as a GPS locator) to determine the user's |
94             | | | location. This value must be either 'true' or |
95             | | | 'false'. Default is 'false'. |
96             +----------+----------+-----------------------------------------------------+
97              
98             =head1 SUPPORTED LANGUAGES
99              
100             +-------+-------------------------+-------+-------+
101             | Code | Name | v2 | v3 |
102             +-------+-------------------------+-------+-------+
103             | ar | ARABIC | Yes | Yes |
104             | eu | BASQUE | No | Yes |
105             | bg | BULGARIAN | Yes | Yes |
106             | bn | BENGALI | Yes | Yes |
107             | ca | CATALAN | Yes | Yes |
108             | cs | CZECH | Yes | Yes |
109             | da | DANISH | Yes | Yes |
110             | de | GERMAN | Yes | Yes |
111             | de | GERMAN | Yes | Yes |
112             | el | GREEK | Yes | Yes |
113             | en | ENGLISH | Yes | Yes |
114             | en-AU | ENGLISH (AUSTRALIAN) | No | Yes |
115             | en-GB | ENGLISH (GREAT BRITAIN) | No | Yes |
116             | es | SPANISH | Yes | Yes |
117             | eu | BASQUE | Yes | Yes |
118             | fa | FARSI | No | Yes |
119             | fi | FINNISH | Yes | Yes |
120             | fil | FILIPINO | Yes | Yes |
121             | fr | FRENCH | Yes | Yes |
122             | gl | GALICIAN | Yes | Yes |
123             | gu | GUJARATI | Yes | Yes |
124             | hi | HINDI | Yes | Yes |
125             | hr | CROATIAN | Yes | Yes |
126             | hu | HUNGARIAN | Yes | Yes |
127             | id | INDONESIAN | Yes | Yes |
128             | it | ITALIAN | Yes | Yes |
129             | iw | HEBREW | Yes | Yes |
130             | ja | JAPANESE | Yes | Yes |
131             | kn | KANNADA | Yes | Yes |
132             | ko | KOREAN | Yes | Yes |
133             | lt | LITHUANIAN | Yes | Yes |
134             | lv | LATVIAN | Yes | Yes |
135             | ml | MALAYALAM | Yes | Yes |
136             | mr | MARATHI | Yes | Yes |
137             | nl | DUTCH | Yes | Yes |
138             | nn | NORWEGIAN NYNORSK | Yes | No |
139             | no | NORWEGIAN | Yes | Yes |
140             | or | ORIYA | Yes | No |
141             | pl | POLISH | Yes | Yes |
142             | pt | PORTUGUESE | Yes | Yes |
143             | pt-BR | PORTUGUESE (BRAZIL) | Yes | Yes |
144             | pt-PT | PORTUGUESE (PORTUGAL) | Yes | Yes |
145             | rm | ROMANSCH | Yes | No |
146             | ro | ROMANIAN | Yes | Yes |
147             | ru | RUSSIAN | Yes | Yes |
148             | sk | SLOVAK | Yes | Yes |
149             | sl | SLOVENIAN | Yes | Yes |
150             | sr | SERBIAN | Yes | Yes |
151             | sv | SWEDISH | Yes | Yes |
152             | tl | TAGALOG | No | Yes |
153             | ta | TAMIL | Yes | Yes |
154             | te | TELUGU | Yes | Yes |
155             | th | THAI | Yes | Yes |
156             | tr | TURKISH | Yes | Yes |
157             | uk | UKRAINIAN | Yes | Yes |
158             | vi | VIETNAMESE | Yes | Yes |
159             | zh-CN | CHINESE (SIMPLIFIED) | Yes | Yes |
160             | zh-TW | CHINESE (TRADITIONAL) | Yes | Yes |
161             +-------+-------------------------+-------+-------+
162              
163             =head1 METHODS
164              
165             =head2 getDistance(\%param)
166              
167             It expects parameter as ref to a hash containing keys from the table below and it
168             then returns the distance matrix as ref to a list of objects of type L
169             from the set of origins to the set of destinations. On error it throws exception
170             of type L.
171              
172             +----------+----------------------------------------------------------------+
173             | key | Description |
174             +----------+----------------------------------------------------------------+
175             | o_addr | One or more origin address(es). |
176             | o_latlng | One or more origin latitude/longitude coordinate(s). |
177             | d_addr | One or more destination address(es). |
178             | d_latlng | One or more destination latitude/longitude coordinate(s). |
179             +----------+----------------------------------------------------------------+
180              
181             If you pass coordinates ensure that no space exists between the latitude an
182             longitude values.
183              
184             use strict; use warnings;
185             use WWW::Google::DistanceMatrix;
186              
187             my $api_key = 'Your API Key';
188             my $google = WWW::Google::DistanceMatrix->new( 'api_key' => $api_key );
189             my $results = $google->getDistance({ o_addr => ['Vancouver+BC'], d_addr => ['Victoria+BC'] });
190             foreach my $result (@$results) {
191             print $result->as_string, "\n";
192             }
193              
194             =cut
195              
196             sub getDistance {
197 9     9 1 7001 my ($self, $params) = @_;
198              
199 9         26 my $url = $self->_url($params);
200 0         0 my $response = $self->get($url);
201 0         0 my $content = from_json($response->{content});
202              
203 0         0 _check_content($content);
204 0         0 return _result($content);
205             }
206              
207             #
208             #
209             # PRIVATE METHODS
210              
211             sub _check_content {
212 0     0   0 my ($content) = @_;
213              
214 0 0 0     0 if (defined $content && defined $content->{error_message}) {
215 0         0 my @caller = caller(1);
216 0 0       0 @caller = caller(2) if $caller[3] eq '(eval)';
217 0         0 my $status = $content->{status};
218              
219             WWW::Google::UserAgent::Exception->throw({
220             method => $caller[3],
221             message => $content->{error_message},
222             code => $status,
223 0         0 reason => $REASON->{$status},
224             filename => $caller[1],
225             line_number => $caller[2] });
226             }
227             }
228              
229             sub _url {
230 9     9   20 my ($self, $params) = @_;
231              
232 9         65 my @caller = caller(1);
233 9 50       32 @caller = caller(2) if $caller[3] eq '(eval)';
234              
235 9         20 my ($origins, $destinations) = ([], []);
236 9 100 66     49 if (defined $params && ref($params) eq 'HASH') {
237 8 100 100     32 if (defined $params->{'o_addr'} && (ref($params->{'o_addr'}) eq 'ARRAY')) {
238 1         7 $FIELDS->{'o_addr'}->{check}->($params->{'o_addr'});
239 1         2 push @$origins, @{$params->{'o_addr'}};
  1         4  
240             }
241 8 100 100     29 if (defined $params->{'o_latlng'} && (ref($params->{'o_latlng'}) eq 'ARRAY')) {
242 1         7 $FIELDS->{'o_latlng'}->{check}->($params->{'o_latlng'});
243 0         0 push @$origins, @{$params->{'o_latlng'}};
  0         0  
244             }
245              
246             WWW::Google::UserAgent::Exception->throw({
247 7 100       49 method => $caller[3],
248             message => "Missing mandatory param: origins",
249             code => 'MISSING_REQUIRED_PARAM',
250             reason => 'MISSING_REQUIRED_PARAM',
251             filename => $caller[1],
252             line_number => $caller[2] }) unless scalar(@$origins);
253              
254 1 50 33     5 if (defined $params->{'d_addr'} && (ref($params->{'d_addr'}) eq 'ARRAY')) {
255 0         0 $FIELDS->{'d_addr'}->{check}->($params->{'d_addr'});
256 0         0 push @$destinations, @{$params->{'d_addr'}};
  0         0  
257             }
258 1 50 33     5 if (defined $params->{'d_latlng'} && (ref($params->{'d_latlng'}) eq 'ARRAY')) {
259 0         0 $FIELDS->{'d_latlng'}->{check}->($params->{'d_latlng'});
260 0         0 push @$destinations, @{$params->{'d_latlng'}};
  0         0  
261             }
262              
263             WWW::Google::UserAgent::Exception->throw({
264 1 50       9 method => $caller[3],
265             message => "Missing mandatory param: destinations",
266             code => 'MISSING_REQUIRED_PARAM',
267             reason => 'MISSING_REQUIRED_PARAM',
268             filename => $caller[1],
269             line_number => $caller[2] }) unless scalar(@$destinations);
270             }
271             else {
272 1         14 WWW::Google::UserAgent::Exception->throw({
273             method => $caller[3],
274             message => "Missing mandatory param: origins/destinations",
275             code => 'MISSING_REQUIRED_PARAM',
276             reason => 'MISSING_REQUIRED_PARAM',
277             filename => $caller[1],
278             line_number => $caller[2] });
279             }
280              
281 0           validate({ origins => 1, destinations => 1 },
282             { origins => $origins, destinations => $destinations });
283              
284 0           my $keys = [];
285 0           foreach (qw(sensor avoid units mode language)) {
286 0 0         if (defined $self->{$_}) {
287 0           my $_key = "$_=%" . $FIELDS->{$_}->{type};
288 0           push @$keys, sprintf($_key, $self->{$_});
289             }
290             }
291              
292 0           my $url = sprintf("%s/%s?key=%s&%s",
293             $BASE_URL, $self->output, $self->api_key, join("&", @$keys));
294 0           $url .= sprintf("&origins=%s", join("|", @{$origins}));
  0            
295 0           $url .= sprintf("&destinations=%s", join("|", @{$destinations}));
  0            
296              
297 0           return $url;
298             }
299              
300             sub _result {
301 0     0     my ($data) = @_;
302              
303 0           my $results = [];
304 0           my $o_index = 0;
305 0           foreach my $origin (@{$data->{origin_addresses}}) {
  0            
306 0           my $d_index = 0;
307 0           foreach my $destination (@{$data->{destination_addresses}}) {
  0            
308 0           my ($duration, $distance);
309 0 0         if ($data->{rows}->[$o_index]->{elements}->[$d_index]->{status} eq 'OK') {
310 0           $duration = $data->{rows}->[$o_index]->{elements}->[$d_index]->{duration}->{text};
311 0           $distance = $data->{rows}->[$o_index]->{elements}->[$d_index]->{distance}->{text};
312             }
313             else {
314 0           $duration = 'N/A';
315 0           $distance = 'N/A';
316             }
317              
318 0           push @$results,
319             WWW::Google::DistanceMatrix::Result->new(
320             origin => $origin,
321             destination => $destination,
322             duration => $duration,
323             distance => $distance);
324              
325 0           $d_index++;
326             }
327 0           $o_index++;
328             }
329              
330 0           return $results;
331             }
332              
333             =head1 AUTHOR
334              
335             Mohammad S Anwar, C<< >>
336              
337             =head1 REPOSITORY
338              
339             L
340              
341             =head1 BUGS
342              
343             Please report any bugs or feature requests to C
344             rt.cpan.org>, or through the web interface at L.
345             I will be notified, and then you'll automatically be notified of progress on your
346             bug as I make changes.
347              
348             =head1 SUPPORT
349              
350             You can find documentation for this module with the perldoc command.
351              
352             perldoc WWW::Google::DistanceMatrix
353              
354             You can also look for information at:
355              
356             =over 4
357              
358             =item * RT: CPAN's request tracker (report bugs here)
359              
360             L
361              
362             =item * AnnoCPAN: Annotated CPAN documentation
363              
364             L
365              
366             =item * CPAN Ratings
367              
368             L
369              
370             =item * Search CPAN
371              
372             L
373              
374             =back
375              
376             =head1 LICENSE AND COPYRIGHT
377              
378             Copyright (C) 2011 - 2015 Mohammad S Anwar.
379              
380             This program is free software; you can redistribute it and/or modify it under
381             the terms of the the Artistic License (2.0). You may obtain a copy of the full
382             license at:
383              
384             L
385              
386             Any use, modification, and distribution of the Standard or Modified Versions is
387             governed by this Artistic License.By using, modifying or distributing the Package,
388             you accept this license. Do not use, modify, or distribute the Package, if you do
389             not accept this license.
390              
391             If your Modified Version has been derived from a Modified Version made by someone
392             other than you,you are nevertheless required to ensure that your Modified Version
393             complies with the requirements of this license.
394              
395             This license does not grant you the right to use any trademark, service mark,
396             tradename, or logo of the Copyright Holder.
397              
398             This license includes the non-exclusive, worldwide, free-of-charge patent license
399             to make, have made, use, offer to sell, sell, import and otherwise transfer the
400             Package with respect to any patent claims licensable by the Copyright Holder that
401             are necessarily infringed by the Package. If you institute patent litigation
402             (including a cross-claim or counterclaim) against any party alleging that the
403             Package constitutes direct or contributory patent infringement,then this Artistic
404             License to you shall terminate on the date that such litigation is filed.
405              
406             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND
407             CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
408             WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
409             NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS
410             REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT,
411             INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE
412             OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
413              
414             =cut
415              
416             1; # End of WWW::Google::DistanceMatrix