File Coverage

blib/lib/Geo/Coder/Bing.pm
Criterion Covered Total %
statement 40 83 48.1
branch 13 50 26.0
condition 4 11 36.3
subroutine 9 14 64.2
pod 4 4 100.0
total 70 162 43.2


line stmt bran cond sub pod time code
1             package Geo::Coder::Bing;
2              
3 2     2   52215 use strict;
  2         7  
  2         95  
4 2     2   13 use warnings;
  2         6  
  2         76  
5              
6 2     2   12 use Carp qw(carp croak);
  2         17  
  2         217  
7 2     2   6104 use Encode ();
  2         35623  
  2         48  
8 2     2   2330 use JSON;
  2         55344  
  2         12  
9 2     2   3061 use LWP::UserAgent;
  2         126430  
  2         127  
10 2     2   26 use URI;
  2         3  
  2         2166  
11              
12             our $VERSION = '0.12';
13             $VERSION = eval $VERSION;
14              
15             sub new {
16 4     4 1 2386 my ($class, @params) = @_;
17 4 100       29 my %params = (@params % 2) ? (key => @params) : @params;
18              
19 4 50       13 carp 'Provide a Bing Maps key to use the new REST API'
20             unless $params{key};
21              
22 4         11 my $self = bless \ %params, $class;
23              
24 4   33     77 $self->ua(
25             $params{ua} || LWP::UserAgent->new(agent => "$class/$VERSION")
26             );
27              
28 4 100       14 if ($self->{debug}) {
29 2     0   8 my $dump_sub = sub { $_[0]->dump(maxlength => 0); return };
  0         0  
  0         0  
30 2         5 $self->ua->set_my_handler(request_send => $dump_sub);
31 2         116 $self->ua->set_my_handler(response_done => $dump_sub);
32 2   50     77 $self->{compress} ||= 0;
33             }
34 4 100       18 if (exists $self->{compress} ? $self->{compress} : 1) {
    100          
35 2         8 $self->ua->default_header(accept_encoding => 'gzip,deflate');
36             }
37              
38 4 50 33     126 croak q('https' requires LWP::Protocol::https)
39             if $self->{https} and not $self->ua->is_protocol_supported('https');
40              
41 4         16 return $self;
42             }
43              
44 0     0 1 0 sub response { $_[0]->{response} }
45              
46             sub ua {
47 10     10 1 4554 my ($self, $ua) = @_;
48 10 100       25 if ($ua) {
49 4 50 33     44 croak q('ua' must be (or derived from) an LWP::UserAgent')
50             unless ref $ua and $ua->isa(q(LWP::UserAgent));
51 4         14 $self->{ua} = $ua;
52             }
53 10         38 return $self->{ua};
54             }
55              
56             sub geocode {
57 0 0   0 1   return $_[0]->{key} ? &_geocode_rest : &_geocode_ajax;
58             }
59              
60             sub _geocode_rest {
61 0     0     my ($self, @params) = @_;
62 0 0         my %params = (@params % 2) ? (location => @params) : @params;
63              
64 0 0         $params{query} = delete $params{location} or return;
65 0           $_ = Encode::encode('utf-8', $_) for values %params;
66              
67 0           my $uri = URI->new('http://dev.virtualearth.net/REST/v1/Locations');
68 0 0         $uri->scheme('https') if $self->{https};
69 0           $uri->query_form(
70             key => $self->{key},
71             %params,
72             );
73              
74 0           my $res = $self->{response} = $self->ua->get($uri);
75 0 0         return unless $res->is_success;
76              
77             # Change the content type of the response from 'application/json' so
78             # HTTP::Message will decode the character encoding.
79 0           $res->content_type('text/plain');
80              
81 0           my $content = $res->decoded_content;
82 0 0         return unless $content;
83              
84 0           my $data = eval { from_json($content) };
  0            
85 0 0         return unless $data;
86              
87 0 0         my @results = @{ $data->{resourceSets}[0]{resources} || [] };
  0            
88 0 0         return wantarray ? @results : $results[0];
89             }
90              
91              
92             # Support AJAX API for backwards compatibility.
93              
94             sub _geocode_ajax {
95 0     0     my ($self, @params) = @_;
96 0 0         my %params = (@params % 2) ? (location => @params) : @params;
97              
98 0 0         my $location = $params{location} or return;
99 0           $location = Encode::encode('utf-8', $location);
100              
101 0           my $uri = URI->new('http://dev.virtualearth.net/');
102 0 0         $uri->scheme('https') if $self->{https};
103 0           $uri->path_segments(qw(
104             services v1 geocodeservice geocodeservice.asmx Geocode
105             ));
106 0           $uri->query_form(
107             format => 'json',
108              
109             # Note: the quotes around the location parameter are required.
110             query => qq("$location"),
111              
112             # These are all required, even if empty.
113 0           map { $_ => '' } qw(
114             addressLine adminDistrict count countryRegion culture
115             curLocAccuracy currentLocation district entityTypes landmark
116             locality mapBounds postalCode postalTown rankBy
117             ),
118             );
119              
120 0           my $res = $self->{response} = $self->ua->get($uri);
121 0 0         return unless $res->is_success;
122              
123             # Change the content type of the response from 'application/json' so
124             # HTTP::Message will decode the character encoding.
125 0           $res->content_type('text/plain');
126              
127 0           my $content = $res->decoded_content;
128 0 0         return unless $content;
129              
130             # Workaround invalid data.
131 0           $content =~ s[ \}\.d $ ][}]x;
132              
133 0           my $data = eval { from_json($content) };
  0            
134 0 0         return unless $data;
135              
136 0 0         my @results = @{ $data->{d}{Results} || [] };
  0            
137 0 0         return wantarray ? @results : $results[0];
138             }
139              
140              
141             1;
142              
143             __END__