File Coverage

blib/lib/Geo/What3Words.pm
Criterion Covered Total %
statement 78 105 74.2
branch 9 18 50.0
condition 9 29 31.0
subroutine 17 22 77.2
pod 8 9 88.8
total 121 183 66.1


line stmt bran cond sub pod time code
1             # ABSTRACT: turn WGS84 coordinates into three word addresses and vice-versa using what3words.com HTTPS API
2              
3             package Geo::What3Words;
4             $Geo::What3Words::VERSION = '2.1.6';
5 1     1   133290 use strict;
  1         3  
  1         31  
6 1     1   5 use warnings;
  1         2  
  1         25  
7 1     1   923 use Cpanel::JSON::XS;
  1         5588  
  1         59  
8 1     1   8 use Data::Dumper;
  1         3  
  1         49  
9             $Data::Dumper::Sortkeys = 1;
10 1     1   548 use Encode qw( decode_utf8 );
  1         9706  
  1         65  
11 1     1   7 use HTTP::Tiny;
  1         2  
  1         22  
12 1     1   710 use Net::Ping;
  1         17873  
  1         57  
13 1     1   535 use Net::Ping::External;
  1         1859  
  1         50  
14 1     1   487 use Ref::Util qw( is_hashref is_coderef );
  1         1639  
  1         77  
15 1     1   561 use URI;
  1         4548  
  1         444  
16              
17             my $JSONXS = Cpanel::JSON::XS->new->allow_nonref(1);
18              
19              
20              
21              
22             sub new {
23 4     4 1 4158 my ($class, %params) = @_;
24              
25 4         11 my $self = {};
26 4   50     27 $self->{api_endpoint} = $params{api_endpoint} || 'https://api.what3words.com/v2/';
27 4   100     26 $self->{key} = $params{key} || die "API key not set";
28 3         10 $self->{language} = $params{language};
29 3         8 $self->{logging} = $params{logging};
30              
31             ## _ua is used for testing. But could also be used to
32             ## set proxies or such
33 3   33     11 $self->{ua} = $params{ua} || HTTP::Tiny->new;
34              
35 3   50     10 my $version = $Geo::What3Words::VERSION || '';
36 3         17 $self->{ua}->agent("Perl Geo::What3Words $version");
37              
38 3         61 return bless($self,$class);
39             }
40              
41              
42             sub ping {
43 0     0 1 0 my $self = shift;
44              
45             ## http://example.com/some/path => example.com
46             ## also works with IP addresses
47 0         0 my $host = URI->new($self->{api_endpoint})->host;
48              
49 0         0 $self->_log("pinging $host...");
50              
51 0         0 my $netping = Net::Ping->new('external');
52 0         0 my $res = $netping->ping($host);
53              
54 0 0       0 $self->_log($res ? 'available' : 'unavailable');
55              
56 0         0 return $res;
57             }
58              
59              
60             sub words2pos {
61 0     0 1 0 my ($self, @params) = @_;
62              
63 0         0 my $res = $self->words_to_position(@params);
64 0 0 0     0 if ( $res && is_hashref($res) && exists($res->{geometry}) ){
      0        
65 0         0 return $res->{geometry}->{lat} . ',' . $res->{geometry}->{lng};
66             }
67 0         0 return;
68             }
69              
70              
71              
72             sub pos2words {
73 1     1 1 6 my ($self, @params) = @_;
74 1         4 my $res = $self->position_to_words(@params);
75 1 0 33     9 if ( $res && is_hashref($res) && exists($res->{words}) ){
      33        
76 0         0 return $res->{words};
77             }
78 1         7 return;
79             }
80              
81              
82             sub valid_words_format {
83 9     9 1 26 my $self = shift;
84 9         15 my $words = shift;
85              
86             ## Translating the PHP regular expression w3w uses in their
87             ## documentation
88             ## http://perldoc.perl.org/perlunicode.html#Unicode-Character-Properties
89             ## http://php.net/manual/en/reference.pcre.pattern.differences.php
90 9 100       26 return 0 unless $words;
91 1 100   1   15 return 1 if ($words =~ m/^(\p{Lower}+)\.(\p{Lower}+)\.(\p{Lower}+)$/ );
  1         8  
  1         17  
  7         78  
92 4         14 return 0;
93             }
94              
95              
96             sub words_to_position {
97 0     0 1 0 my $self = shift;
98 0         0 my $words = shift;
99 0   0     0 my $language = shift || $self->{language};
100              
101 0         0 return $self->_query_remote_api('forward', {addr => $words, lang => $language });
102             }
103              
104              
105             sub position_to_words {
106 1     1 1 4 my $self = shift;
107 1         2 my $position = shift;
108 1   33     8 my $language = shift || $self->{language};
109              
110 1         5 return $self->_query_remote_api('reverse', {coords => $position, lang => $language });
111             }
112              
113              
114             sub get_languages {
115 0     0 1 0 my $self = shift;
116 0         0 my $position = shift;
117 0         0 return $self->_query_remote_api('languages');
118             }
119              
120             sub oneword_available {
121 0     0 0 0 warn 'deprecated method: oneword_available';
122 0         0 return;
123             }
124              
125             sub _query_remote_api {
126 1     1   2 my $self = shift;
127 1         2 my $method_name = shift;
128 1   50     3 my $rh_params = shift || {};
129              
130             my $rh_fields = {
131             a => 1,
132             key => $self->{key},
133 1         6 format => 'json',
134             %$rh_params
135             };
136              
137 1         5 foreach my $key (keys %$rh_fields){
138 5 100       14 delete $rh_fields->{$key} if (!defined($rh_fields->{$key}));
139             }
140              
141 1         8 my $uri = URI->new($self->{api_endpoint} . $method_name);
142 1         9085 $uri->query_form( $rh_fields );
143 1         227 my $url = $uri->as_string;
144              
145 1         10 $self->_log("GET $url");
146 1         76 my $response = $self->{ua}->get($url);
147              
148 1 50       162851 if ( ! $response->{success}) {
149 1         28 warn "got failed response from $url: " . $response->{status};
150 1         97 $self->_log("got failed response from $url: " . $response->{status});
151 1         30 return;
152             }
153              
154 0         0 my $json = $response->{content};
155 0         0 $json = decode_utf8($json);
156 0         0 $self->_log($json);
157              
158 0         0 return $JSONXS->decode($json);
159             }
160              
161             sub _log {
162 2     2   5 my $self = shift;
163 2         5 my $message = shift;
164 2 50       11 return unless $self->{logging};
165              
166 2 50       9 if ( is_coderef($self->{logging}) ){
167 2         5 my $lc = $self->{logging};
168 2         10 &$lc("Geo::What3Words -- " . $message);
169             }
170             else {
171 0         0 print "Geo::What3Words -- " . $message . "\n";
172             }
173 2         903 return;
174             }
175              
176              
177             1;
178              
179             __END__