File Coverage

blib/lib/Geo/What3Words.pm
Criterion Covered Total %
statement 78 104 75.0
branch 9 18 50.0
condition 9 26 34.6
subroutine 17 22 77.2
pod 8 9 88.8
total 121 179 67.6


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 = '3.0.0';
5 1     1   131533 use strict;
  1         3  
  1         29  
6 1     1   5 use warnings;
  1         2  
  1         24  
7 1     1   950 use Cpanel::JSON::XS;
  1         5585  
  1         59  
8 1     1   8 use Data::Dumper;
  1         2  
  1         49  
9             $Data::Dumper::Sortkeys = 1;
10 1     1   557 use Encode qw( decode_utf8 );
  1         9490  
  1         67  
11 1     1   7 use HTTP::Tiny;
  1         2  
  1         21  
12 1     1   725 use Net::Ping;
  1         17777  
  1         55  
13 1     1   485 use Net::Ping::External;
  1         1830  
  1         49  
14 1     1   539 use Ref::Util qw( is_hashref is_coderef );
  1         1595  
  1         74  
15 1     1   608 use URI;
  1         4500  
  1         437  
16              
17             my $JSONXS = Cpanel::JSON::XS->new->allow_nonref(1);
18              
19              
20              
21              
22             sub new {
23 4     4 1 4056 my ($class, %params) = @_;
24              
25 4         11 my $self = {};
26 4   50     28 $self->{api_endpoint} = $params{api_endpoint} || 'https://api.what3words.com/v3/';
27 4   100     26 $self->{key} = $params{key} || die "API key not set";
28 3         7 $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         18 $self->{ua}->agent("Perl Geo::What3Words $version");
37              
38 3         60 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->{coordinates}) ){
      0        
65 0         0 return $res->{coordinates}->{lat} . ',' . $res->{coordinates}->{lng};
66             }
67 0         0 return;
68             }
69              
70              
71              
72             sub pos2words {
73 1     1 1 7 my ($self, @params) = @_;
74 1         4 my $res = $self->position_to_words(@params);
75 1 0 33     8 if ( $res && is_hashref($res) && exists($res->{words}) ){
      33        
76 0         0 return $res->{words};
77             }
78 1         8 return;
79             }
80              
81              
82             sub valid_words_format {
83 9     9 1 24 my $self = shift;
84 9         17 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   7 return 1 if ($words =~ m/^(\p{Lower}+)\.(\p{Lower}+)\.(\p{Lower}+)$/ );
  1         21  
  1         18  
  7         78  
92 4         16 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              
100 0         0 return $self->_query_remote_api('convert-to-coordinates', {
101             words => $words
102             });
103            
104             }
105              
106              
107             sub position_to_words {
108 1     1 1 2 my $self = shift;
109 1         3 my $position = shift;
110 1   33     7 my $language = shift || $self->{language};
111              
112             # https://developer.what3words.com/public-api/docs#convert-to-3wa
113 1         5 return $self->_query_remote_api('convert-to-3wa', {
114             coordinates => $position,
115             language => $language
116             });
117             }
118              
119              
120             sub get_languages {
121 0     0 1 0 my $self = shift;
122 0         0 my $position = shift;
123 0         0 return $self->_query_remote_api('available-languages');
124             }
125              
126             sub oneword_available {
127 0     0 0 0 warn 'deprecated method: oneword_available';
128 0         0 return;
129             }
130              
131             sub _query_remote_api {
132 1     1   3 my $self = shift;
133 1         2 my $method_name = shift;
134 1   50     3 my $rh_params = shift || {};
135              
136             my $rh_fields = {
137             #a => 1,
138             key => $self->{key},
139 1         5 format => 'json',
140             %$rh_params
141             };
142              
143 1         4 foreach my $key (keys %$rh_fields){
144 4 100       27 delete $rh_fields->{$key} if (!defined($rh_fields->{$key}));
145             }
146              
147 1         10 my $uri = URI->new($self->{api_endpoint} . $method_name);
148 1         8758 $uri->query_form( $rh_fields );
149 1         217 my $url = $uri->as_string;
150              
151 1         13 $self->_log("GET $url");
152 1         37 my $response = $self->{ua}->get($url);
153              
154 1 50       153404 if ( ! $response->{success}) {
155 1         23 warn "got failed response from $url: " . $response->{status};
156 1         92 $self->_log("got failed response from $url: " . $response->{status});
157 1         32 return;
158             }
159              
160 0         0 my $json = $response->{content};
161 0         0 $json = decode_utf8($json);
162 0         0 $self->_log($json);
163              
164 0         0 return $JSONXS->decode($json);
165             }
166              
167             sub _log {
168 2     2   5 my $self = shift;
169 2         5 my $message = shift;
170 2 50       10 return unless $self->{logging};
171              
172 2 50       10 if ( is_coderef($self->{logging}) ){
173 2         4 my $lc = $self->{logging};
174 2         12 &$lc("Geo::What3Words -- " . $message);
175             }
176             else {
177 0         0 print "Geo::What3Words -- " . $message . "\n";
178             }
179 2         946 return;
180             }
181              
182              
183             1;
184              
185             __END__