GUI-graticule 0.2.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.txt +46 -0
- data/LICENSE.txt +30 -0
- data/Manifest.txt +73 -0
- data/README.txt +29 -0
- data/Rakefile +86 -0
- data/bin/geocode +5 -0
- data/init.rb +2 -0
- data/lib/graticule.rb +26 -0
- data/lib/graticule/cli.rb +64 -0
- data/lib/graticule/distance.rb +29 -0
- data/lib/graticule/distance/haversine.rb +40 -0
- data/lib/graticule/distance/spherical.rb +52 -0
- data/lib/graticule/distance/vincenty.rb +76 -0
- data/lib/graticule/geocoder.rb +21 -0
- data/lib/graticule/geocoder/base.rb +138 -0
- data/lib/graticule/geocoder/bogus.rb +15 -0
- data/lib/graticule/geocoder/geocoder_ca.rb +54 -0
- data/lib/graticule/geocoder/geocoder_us.rb +49 -0
- data/lib/graticule/geocoder/google.rb +122 -0
- data/lib/graticule/geocoder/host_ip.rb +41 -0
- data/lib/graticule/geocoder/local_search_maps.rb +45 -0
- data/lib/graticule/geocoder/map_quest.rb +111 -0
- data/lib/graticule/geocoder/meta_carta.rb +33 -0
- data/lib/graticule/geocoder/multi.rb +80 -0
- data/lib/graticule/geocoder/postcode_anywhere.rb +63 -0
- data/lib/graticule/geocoder/rest.rb +18 -0
- data/lib/graticule/geocoder/yahoo.rb +102 -0
- data/lib/graticule/location.rb +488 -0
- data/lib/graticule/version.rb +9 -0
- data/site/index.html +114 -0
- data/site/plugin.html +82 -0
- data/site/stylesheets/style.css +73 -0
- data/test/config.yml.default +36 -0
- data/test/fixtures/responses/geocoder_us/success.xml +18 -0
- data/test/fixtures/responses/geocoder_us/unknown.xml +1 -0
- data/test/fixtures/responses/google/badkey.xml +1 -0
- data/test/fixtures/responses/google/limit.xml +10 -0
- data/test/fixtures/responses/google/missing_address.xml +1 -0
- data/test/fixtures/responses/google/only_coordinates.xml +1 -0
- data/test/fixtures/responses/google/partial.xml +1 -0
- data/test/fixtures/responses/google/server_error.xml +10 -0
- data/test/fixtures/responses/google/success.xml +1 -0
- data/test/fixtures/responses/google/unavailable.xml +1 -0
- data/test/fixtures/responses/google/unknown_address.xml +1 -0
- data/test/fixtures/responses/host_ip/private.txt +4 -0
- data/test/fixtures/responses/host_ip/success.txt +4 -0
- data/test/fixtures/responses/host_ip/unknown.txt +4 -0
- data/test/fixtures/responses/local_search_maps/empty.txt +1 -0
- data/test/fixtures/responses/local_search_maps/not_found.txt +1 -0
- data/test/fixtures/responses/local_search_maps/success.txt +1 -0
- data/test/fixtures/responses/meta_carta/bad_address.xml +17 -0
- data/test/fixtures/responses/meta_carta/multiple.xml +33 -0
- data/test/fixtures/responses/meta_carta/success.xml +31 -0
- data/test/fixtures/responses/postcode_anywhere/badkey.xml +9 -0
- data/test/fixtures/responses/postcode_anywhere/canada.xml +16 -0
- data/test/fixtures/responses/postcode_anywhere/empty.xml +16 -0
- data/test/fixtures/responses/postcode_anywhere/success.xml +16 -0
- data/test/fixtures/responses/postcode_anywhere/uk.xml +18 -0
- data/test/fixtures/responses/yahoo/success.xml +3 -0
- data/test/fixtures/responses/yahoo/unknown_address.xml +6 -0
- data/test/mocks/uri.rb +52 -0
- data/test/test_helper.rb +32 -0
- data/test/unit/graticule/distance_test.rb +58 -0
- data/test/unit/graticule/geocoder/geocoder_us_test.rb +43 -0
- data/test/unit/graticule/geocoder/google_test.rb +126 -0
- data/test/unit/graticule/geocoder/host_ip_test.rb +40 -0
- data/test/unit/graticule/geocoder/local_search_maps_test.rb +30 -0
- data/test/unit/graticule/geocoder/meta_carta_test.rb +44 -0
- data/test/unit/graticule/geocoder/multi_test.rb +43 -0
- data/test/unit/graticule/geocoder/postcode_anywhere_test.rb +50 -0
- data/test/unit/graticule/geocoder/yahoo_test.rb +58 -0
- data/test/unit/graticule/geocoder_test.rb +27 -0
- data/test/unit/graticule/location_test.rb +66 -0
- metadata +158 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Graticule #:nodoc:
|
4
|
+
module Geocoder #:nodoc:
|
5
|
+
|
6
|
+
class HostIp < Base
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@url = URI.parse 'http://api.hostip.info/get_html.php'
|
10
|
+
end
|
11
|
+
|
12
|
+
# Geocode an IP address using http://hostip.info
|
13
|
+
def locate(address)
|
14
|
+
get :ip => address, :position => true
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def prepare_response(response)
|
20
|
+
# add new line so YAML.load doesn't puke
|
21
|
+
YAML.load(response + "\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_response(parse_type, response) #:nodoc:
|
25
|
+
returning Location.new do |location|
|
26
|
+
location.latitude = response['Latitude']
|
27
|
+
location.longitude = response['Longitude']
|
28
|
+
location.locality, location.region = response['City'].split(', ')
|
29
|
+
country = response['Country'].match(/\((\w+)\)$/)
|
30
|
+
location.country = country[1] if country
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_error(response) #:nodoc:
|
35
|
+
raise AddressError, 'Unknown' if response['City'] =~ /Unknown City/
|
36
|
+
raise AddressError, 'Private Address' if response['City'] =~ /Private Address/
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Graticule #:nodoc:
|
2
|
+
module Geocoder #:nodoc:
|
3
|
+
|
4
|
+
# A library for lookup of coordinates with http://geo.localsearchmaps.com/
|
5
|
+
#
|
6
|
+
# See http://emad.fano.us/blog/?p=277
|
7
|
+
class LocalSearchMaps < Base
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@url = URI.parse 'http://geo.localsearchmaps.com/'
|
11
|
+
end
|
12
|
+
|
13
|
+
# This web service will handle some addresses outside the US
|
14
|
+
# if given more structured arguments than just a string address
|
15
|
+
# So allow input as a hash for the different arguments (:city, :country, :zip)
|
16
|
+
def locate(params)
|
17
|
+
get params.is_a?(String) ? {:loc => params} : map_attributes(location_from_params(params))
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def map_attributes(location)
|
23
|
+
mapping = {:street => :street, :locality => :city, :region => :state, :postal_code => :zip, :country => :country}
|
24
|
+
mapping.keys.inject({}) do |result,attribute|
|
25
|
+
result[mapping[attribute]] = location.attributes[attribute] unless location.attributes[attribute].blank?
|
26
|
+
result
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def check_error(js)
|
31
|
+
raise AddressError, "Empty Response" if js.nil?
|
32
|
+
raise AddressError, 'Location not found' if js =~ /location not found/
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_response(parse_type, js)
|
36
|
+
returning Location.new do |location|
|
37
|
+
coordinates = js.match(/map.centerAndZoom\(new GPoint\((.+?), (.+?)\)/)
|
38
|
+
location.longitude = coordinates[1].to_f
|
39
|
+
location.latitude = coordinates[2].to_f
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Graticule #:nodoc:
|
2
|
+
module Geocoder #:nodoc:
|
3
|
+
|
4
|
+
# First you need a Mapquest API key. You can register for one here:
|
5
|
+
# http://www.mapquest.com/features/main.adp?page=developer_tools_oapi
|
6
|
+
#
|
7
|
+
# Then you create a MapquestGeocode object and start locating addresses:
|
8
|
+
#
|
9
|
+
# gg = Graticule.service(:map_quest).new(MAPS_API_KEY)
|
10
|
+
# location = gg.locate :street => '1600 Amphitheater Pkwy', :locality => 'Mountain View', :region => 'CA'
|
11
|
+
# p location.coordinates
|
12
|
+
#
|
13
|
+
class MapQuest < Rest
|
14
|
+
# http://trc.mapquest.com
|
15
|
+
|
16
|
+
PRECISION = {
|
17
|
+
0 => Precision.unknown,
|
18
|
+
'COUNTRY' => Precision.country,
|
19
|
+
'STATE' => Precision.state,
|
20
|
+
'COUNTY' => Precision.state,
|
21
|
+
'CITY' => Precision.city,
|
22
|
+
'ZIP' => Precision.zip,
|
23
|
+
'ZIP7' => Precision.zip,
|
24
|
+
'ZIP9' => Precision.zip,
|
25
|
+
'INTERSECTIONS' => Precision.street,
|
26
|
+
'STREET' => Precision.street,
|
27
|
+
'ADDRESS' => Precision.address
|
28
|
+
}
|
29
|
+
|
30
|
+
# Creates a new MapquestGeocode that will use Mapquest API key +key+.
|
31
|
+
#
|
32
|
+
# WARNING: The MapQuest API Keys tend to be already URI encoded. If this is the case
|
33
|
+
# be sure to URI.unescape the key in the call to new
|
34
|
+
def initialize(key)
|
35
|
+
@key = key
|
36
|
+
@url = URI.parse 'http://web.openapi.mapquest.com/oapi/transaction'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Locates +address+ returning a Location
|
40
|
+
def locate(address)
|
41
|
+
get map_attributes(location_from_params(address))
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def map_attributes(location)
|
47
|
+
mapping = {:street => :address, :locality => :city, :region => :stateProvince, :postal_code => :postalcoe, :country => :country}
|
48
|
+
mapping.keys.inject({}) do |result,attribute|
|
49
|
+
result[mapping[attribute]] = location.attributes[attribute] unless location.attributes[attribute].blank?
|
50
|
+
result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Extracts a Location from +xml+.
|
55
|
+
def parse_response(parse_type, xml) #:nodoc:
|
56
|
+
address = REXML::XPath.first(xml, '/advantage/geocode/locations/location')
|
57
|
+
|
58
|
+
Location.new \
|
59
|
+
:street => value(address.elements['//address/text()']),
|
60
|
+
:locality => value(address.elements['//city/text()']),
|
61
|
+
:region => value(address.elements['//stateProvince/text()']),
|
62
|
+
:postal_code => value(address.elements['//postalCode/text()']),
|
63
|
+
:country => value(address.elements['//country/text()']),
|
64
|
+
:latitude => value(address.elements['//latitude/text()']),
|
65
|
+
:longitude => value(address.elements['//longitude/text()']),
|
66
|
+
:precision => PRECISION[address.elements['//geocodeQuality'].text] || :unknown
|
67
|
+
end
|
68
|
+
|
69
|
+
# Extracts and raises an error from +xml+, if any.
|
70
|
+
def check_error(xml) #:nodoc:
|
71
|
+
return unless xml.elements['//error']
|
72
|
+
status = xml.elements['//error/code'].text.to_i
|
73
|
+
msg = xml.elements['//error/text'].text
|
74
|
+
case status
|
75
|
+
when 255..299 then
|
76
|
+
raise CredentialsError, msg
|
77
|
+
when 400..500 then
|
78
|
+
raise AddressError, msg
|
79
|
+
when 600.699 then
|
80
|
+
raise Error, msg
|
81
|
+
when 900 then
|
82
|
+
raise AddressError, 'invalid latitude'
|
83
|
+
when 901 then
|
84
|
+
raise AddressError, 'invalid longitude'
|
85
|
+
when 902 then
|
86
|
+
raise AddressError, 'error parsing params'
|
87
|
+
when 9902 then
|
88
|
+
raise CredentialsError, 'invalid key'
|
89
|
+
when 9904 then
|
90
|
+
raise CredentialsError, 'key missing'
|
91
|
+
else
|
92
|
+
raise Error, "unknown error #{status}: #{msg}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Creates a URL from the Hash +params+. Automatically adds the key and
|
97
|
+
# sets the output type to 'xml'.
|
98
|
+
def make_url(params) #:nodoc:
|
99
|
+
super params.merge({:key => @key, :transaction => 'geocode', :ambiguities => 0})
|
100
|
+
end
|
101
|
+
|
102
|
+
def value(element)
|
103
|
+
element.value if element
|
104
|
+
end
|
105
|
+
|
106
|
+
def text(element)
|
107
|
+
element.text if element
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
module Graticule
|
3
|
+
module Geocoder
|
4
|
+
|
5
|
+
# Library for looking up coordinates with MetaCarta's GeoParser API.
|
6
|
+
#
|
7
|
+
# http://labs.metacarta.com/GeoParser/documentation.html
|
8
|
+
class MetaCarta < Rest
|
9
|
+
|
10
|
+
def initialize # :nodoc:
|
11
|
+
@url = URI.parse 'http://labs.metacarta.com/GeoParser/'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Finds +location+ and returns a Location object.
|
15
|
+
def locate(location)
|
16
|
+
get :q => location.is_a?(String) ? location : location_from_params(location).to_s, :output => 'locations'
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def check_error(xml) # :nodoc:
|
22
|
+
raise AddressError, 'bad location' unless xml.elements['Locations/Location']
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_response(parse_type, xml) # :nodoc:
|
26
|
+
result = xml.elements['/Locations/Location[1]']
|
27
|
+
coords = result.elements['Centroid/gml:Point/gml:coordinates'].text.split ','
|
28
|
+
Location.new :latitude => coords.first.to_f, :longitude => coords.last.to_f
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Graticule #:nodoc:
|
2
|
+
module Geocoder #:nodoc:
|
3
|
+
class Multi
|
4
|
+
|
5
|
+
# The Multi geocoder allows you to use multiple geocoders in succession.
|
6
|
+
#
|
7
|
+
# geocoder = Graticule.service(:multi).new(
|
8
|
+
# Graticule.service(:google).new("api_key"),
|
9
|
+
# Graticule.service(:yahoo).new("api_key"),
|
10
|
+
# )
|
11
|
+
# geocoder.locate '49423' # <= tries geocoders in succession
|
12
|
+
#
|
13
|
+
# The Multi geocoder will try the geocoders in order if a Graticule::AddressError
|
14
|
+
# is raised. You can customize this behavior by passing in a block to the Multi
|
15
|
+
# geocoder. For example, to try the geocoders until one returns a result with a
|
16
|
+
# high enough precision:
|
17
|
+
#
|
18
|
+
# geocoder = Graticule.service(:multi).new(geocoders) do |result|
|
19
|
+
# result.precision >= Graticule::Precision.street
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Geocoders will be tried in order until the block returned true for one of the results
|
23
|
+
#
|
24
|
+
def initialize(*geocoders, &acceptable)
|
25
|
+
@acceptable = acceptable || lambda { true }
|
26
|
+
@geocoders = geocoders.flatten
|
27
|
+
end
|
28
|
+
|
29
|
+
def locate(*args)
|
30
|
+
mode, address = nil, nil
|
31
|
+
case args.first
|
32
|
+
when :first
|
33
|
+
mode = :first
|
34
|
+
address = args[1]
|
35
|
+
when :all
|
36
|
+
mode = :all
|
37
|
+
address = args[1]
|
38
|
+
else
|
39
|
+
mode = :first
|
40
|
+
address = args.first
|
41
|
+
end
|
42
|
+
|
43
|
+
locations = Locations.new
|
44
|
+
last_error = nil
|
45
|
+
|
46
|
+
catch :found_first do
|
47
|
+
@geocoders.each do |geocoder|
|
48
|
+
begin
|
49
|
+
geocoder_locations = geocoder.locate(:all, address)
|
50
|
+
|
51
|
+
geocoder_locations.each do |location|
|
52
|
+
if(@acceptable.call(location))
|
53
|
+
locations << location
|
54
|
+
|
55
|
+
if(mode == :first)
|
56
|
+
throw :found_first
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
rescue Errno::ECONNREFUSED
|
61
|
+
logger.error("Connection refused to #{service}")
|
62
|
+
rescue Error => e
|
63
|
+
last_error = e
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if(mode == :first)
|
69
|
+
if(locations.first)
|
70
|
+
locations.first
|
71
|
+
else
|
72
|
+
raise last_error || AddressError.new("Couldn't find '#{address}' with any of the services")
|
73
|
+
end
|
74
|
+
else
|
75
|
+
locations
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Graticule #:nodoc:
|
2
|
+
module Geocoder #:nodoc:
|
3
|
+
|
4
|
+
class PostcodeAnywhere < Rest
|
5
|
+
|
6
|
+
# http://www.postcodeanywhere.com/register/
|
7
|
+
def initialize(account_code, license_code)
|
8
|
+
@url = URI.parse 'http://services.postcodeanywhere.co.uk/xml.aspx'
|
9
|
+
@account_code = account_code
|
10
|
+
@license_code = license_code
|
11
|
+
end
|
12
|
+
|
13
|
+
def locate(params)
|
14
|
+
location = location_from_params(params)
|
15
|
+
get :address => location.to_s(:country => false), :country => location.country
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def make_url(params) #:nodoc:
|
21
|
+
params[:account_code] = @account_code
|
22
|
+
params[:license_code] = @license_code
|
23
|
+
params[:action] = 'geocode'
|
24
|
+
super params
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse_response(parse_type, xml) #:nodoc:
|
28
|
+
result = xml.elements['/PostcodeAnywhere/Data/Item[1]']
|
29
|
+
returning Location.new do |location|
|
30
|
+
location.latitude = result.attribute('latitude').value.to_f
|
31
|
+
location.longitude = result.attribute('longitude').value.to_f
|
32
|
+
location.street = value(result.attribute('line1'))
|
33
|
+
location.locality = value(result.attribute('city'))
|
34
|
+
location.region = value(result.attribute('state'))
|
35
|
+
location.postal_code = value(result.attribute('postal_code'))
|
36
|
+
location.country = value(result.attribute('country'))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def value(attribute)
|
41
|
+
attribute.value if attribute
|
42
|
+
end
|
43
|
+
|
44
|
+
# http://www.postcodeanywhere.co.uk/developers/documentation/errors.aspx
|
45
|
+
def check_error(xml) #:nodoc:
|
46
|
+
#raise AddressError, xml.text if xml.text == 'couldn\'t find this address! sorry'
|
47
|
+
if error = xml.elements['/PostcodeAnywhere/Data/Item[@error_number][1]']
|
48
|
+
error_number = error.attribute('error_number').value.to_i
|
49
|
+
message = error.attribute('message').value
|
50
|
+
if (1..11).include?(error_number) || (34..38).include?(error_number)
|
51
|
+
raise CredentialsError, message
|
52
|
+
else
|
53
|
+
raise Error, message
|
54
|
+
end
|
55
|
+
elsif xml.elements['/PostcodeAnywhere/Data'].elements.empty?
|
56
|
+
raise AddressError, 'No results returned'
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module Graticule #:nodoc:
|
4
|
+
module Geocoder #:nodoc:
|
5
|
+
|
6
|
+
# Abstract class for implementing REST geocoders. Passes on a REXML::Document
|
7
|
+
# to +check_errors+ and +parse_response+.
|
8
|
+
class Rest < Base
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def prepare_response(response)
|
13
|
+
REXML::Document.new(response)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Graticule #:nodoc:
|
2
|
+
module Geocoder #:nodoc:
|
3
|
+
|
4
|
+
# Yahoo geocoding API.
|
5
|
+
#
|
6
|
+
# http://developer.yahoo.com/maps/rest/V1/geocode.html
|
7
|
+
class Yahoo < Rest
|
8
|
+
|
9
|
+
PRECISION = {
|
10
|
+
"country"=> Precision.country,
|
11
|
+
"state" => Precision.state,
|
12
|
+
"city" => Precision.city,
|
13
|
+
"zip+4" => Precision.zip,
|
14
|
+
"zip+2" => Precision.zip,
|
15
|
+
"zip" => Precision.zip,
|
16
|
+
"street" => Precision.street,
|
17
|
+
"address" => Precision.address
|
18
|
+
}
|
19
|
+
|
20
|
+
# Web services initializer.
|
21
|
+
#
|
22
|
+
# The +appid+ is the Application ID that uniquely identifies your
|
23
|
+
# application. See: http://developer.yahoo.com/faq/index.html#appid
|
24
|
+
#
|
25
|
+
# See http://developer.yahoo.com/search/rest.html
|
26
|
+
def initialize(appid)
|
27
|
+
@appid = appid
|
28
|
+
@url = URI.parse "http://api.local.yahoo.com/MapsService/V1/geocode"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a Location for +address+.
|
32
|
+
#
|
33
|
+
# The +address+ can be any of:
|
34
|
+
# * city, state
|
35
|
+
# * city, state, zip
|
36
|
+
# * zip
|
37
|
+
# * street, city, state
|
38
|
+
# * street, city, state, zip
|
39
|
+
# * street, zip
|
40
|
+
def locate(*args)
|
41
|
+
case args.first
|
42
|
+
when :first then get :first, :location => extract_location(args[1])
|
43
|
+
when :all then get :all, :location => extract_location(args[1])
|
44
|
+
else get :first, :location => extract_location(args.first)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_location(address)
|
49
|
+
location = (address.is_a?(String) ? address : location_from_params(address).to_s(:country => false))
|
50
|
+
# yahoo pukes on line breaks
|
51
|
+
location.gsub("\n", ', ')
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_response(parse_type, xml)
|
55
|
+
if parse_type == :all
|
56
|
+
locations = []
|
57
|
+
xml.elements['ResultSet'].each do |element|
|
58
|
+
locations << parse_location_xml(element)
|
59
|
+
end
|
60
|
+
return locations
|
61
|
+
else
|
62
|
+
return parse_location_xml(xml.elements['ResultSet/Result[1]'])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_location_xml(element)
|
67
|
+
returning Location.new do |location|
|
68
|
+
location.precision = PRECISION[element.attributes['precision']] || Precision.unknown
|
69
|
+
|
70
|
+
if element.attributes.include? 'warning' then
|
71
|
+
location.warning = element.attributes['warning']
|
72
|
+
end
|
73
|
+
location.latitude = element.elements['Latitude'].text.to_f
|
74
|
+
location.longitude = element.elements['Longitude'].text.to_f
|
75
|
+
|
76
|
+
location.street = element.elements['Address'].text unless element.elements['Address'].text.blank?
|
77
|
+
location.locality = element.elements['City'].text unless element.elements['City'].text.blank?
|
78
|
+
location.region = element.elements['State'].text
|
79
|
+
location.postal_code = element.elements['Zip'].text
|
80
|
+
location.country = element.elements['Country'].text
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Extracts and raises an error from +xml+, if any.
|
85
|
+
def check_error(xml) #:nodoc:
|
86
|
+
err = xml.elements['Error']
|
87
|
+
raise Error, err.elements['Message'].text if err
|
88
|
+
end
|
89
|
+
|
90
|
+
# Creates a URL from the Hash +params+. Automatically adds the appid and
|
91
|
+
# sets the output type to 'xml'.
|
92
|
+
def make_url(params) #:nodoc:
|
93
|
+
params[:appid] = @appid
|
94
|
+
params[:output] = 'xml'
|
95
|
+
|
96
|
+
super params
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|