google-geo 1.0
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 +1 -0
- data/README +27 -0
- data/lib/google/geo.rb +190 -0
- data/test/geo_test.rb +88 -0
- metadata +50 -0
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
= 1.0 Initial Release
|
data/README
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
= Google::Geo
|
2
|
+
|
3
|
+
A simple, elegant library for getting geocoding information from Google Maps. Very much inspired by the google-geocode gem, but completely dependency free!
|
4
|
+
|
5
|
+
== Examples
|
6
|
+
|
7
|
+
geo = Google::Geo.new API_KEY
|
8
|
+
|
9
|
+
address = geo.locate '1600 Amphitheatre Parkway, Mountain View, CA'
|
10
|
+
|
11
|
+
address.country # 'US'
|
12
|
+
address.city # 'Mountain View'
|
13
|
+
address.full_address # '1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA'
|
14
|
+
|
15
|
+
address.query # '1600 Amphitheatre Parkway, Mountain View, CA'
|
16
|
+
address.accuracy # 8
|
17
|
+
|
18
|
+
In the case of sufficiently vague queries, +Google::Geo+ will return an +Array+:
|
19
|
+
|
20
|
+
addresses = geo.locate 'hell'
|
21
|
+
|
22
|
+
addresses.size # 2
|
23
|
+
addresses.map { |a| a.country } # ['US', 'NO']
|
24
|
+
|
25
|
+
== Contributors
|
26
|
+
|
27
|
+
Seth Thomas Rasmussen - http://sethrasmussen.com - sethrasmussen@gmail.com
|
data/lib/google/geo.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module Google
|
4
|
+
|
5
|
+
# = Google::Geo
|
6
|
+
#
|
7
|
+
# A simple, elegant library for getting geocoding information from Google Maps. Very much inspired by the google-geocode gem, but completely dependency free!
|
8
|
+
#
|
9
|
+
# == Examples
|
10
|
+
#
|
11
|
+
# geo = Google::Geo.new API_KEY
|
12
|
+
#
|
13
|
+
# address = geo.locate '1600 Amphitheatre Parkway, Mountain View, CA'
|
14
|
+
#
|
15
|
+
# address.country # 'US'
|
16
|
+
# address.city # 'Mountain View'
|
17
|
+
# address.full_address # '1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA'
|
18
|
+
#
|
19
|
+
# address.query # '1600 Amphitheatre Parkway, Mountain View, CA'
|
20
|
+
# address.accuracy # 8
|
21
|
+
#
|
22
|
+
# In the case of sufficiently vague queries, +Google::Geo+ will return an +Array+:
|
23
|
+
#
|
24
|
+
# addresses = geo.locate 'hell'
|
25
|
+
#
|
26
|
+
# addresses.size # 2
|
27
|
+
# addresses.map { |a| a.country } # ['US', 'NO']
|
28
|
+
#
|
29
|
+
# == Contributors
|
30
|
+
#
|
31
|
+
# Seth Thomas Rasmussen - http://sethrasmussen.com - sethrasmussen@gmail.com
|
32
|
+
class Geo
|
33
|
+
# API key provided by Google allowing access to the Geocode API
|
34
|
+
attr_accessor :key
|
35
|
+
|
36
|
+
def initialize(key)
|
37
|
+
@key = key
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns an +Address+ object with accessors for all the components of a location.
|
41
|
+
# The +query+ argument should be a string.
|
42
|
+
def locate(query)
|
43
|
+
xml = open(uri(query)).read
|
44
|
+
res = Response.new(xml, key)
|
45
|
+
|
46
|
+
res.placemarks.map { |place| Address.new place, res.query }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Generate a request URI from a given search string.
|
50
|
+
def uri(address) #:nodoc:
|
51
|
+
"http://maps.google.com/maps/geo?q=#{URI.escape address}&key=#{key}&output=xml"
|
52
|
+
end
|
53
|
+
private :uri
|
54
|
+
|
55
|
+
###
|
56
|
+
|
57
|
+
module Parser #:nodoc:
|
58
|
+
# Fetch contents of an XML element of the response.
|
59
|
+
def fetch(element) #:nodoc:
|
60
|
+
@xml.slice %r{<#{element}>(.+?)</#{element}>}, 1
|
61
|
+
end
|
62
|
+
|
63
|
+
# Like fetch, but for the only piece of data locked away in an attribute.
|
64
|
+
def fetch_accuracy #:nodoc:
|
65
|
+
@xml.slice(%r{Accuracy="([^"]+)">}, 1).to_i
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
###
|
70
|
+
|
71
|
+
# Represents locations returned in response to geocoding queries.
|
72
|
+
class Address
|
73
|
+
include Parser
|
74
|
+
|
75
|
+
attr_reader :street
|
76
|
+
alias :thoroughfare :street
|
77
|
+
|
78
|
+
attr_reader :city
|
79
|
+
alias :locality :city
|
80
|
+
|
81
|
+
attr_reader :zip
|
82
|
+
alias :postal_code :zip
|
83
|
+
|
84
|
+
attr_reader :county
|
85
|
+
alias :subadministrative_area :county
|
86
|
+
|
87
|
+
attr_reader :state
|
88
|
+
alias :administrative_area :state
|
89
|
+
|
90
|
+
attr_reader :country
|
91
|
+
alias :country_code :country
|
92
|
+
|
93
|
+
# An array containing the standard three elements of a coordinate triple: latitude, longitude, elevation.
|
94
|
+
attr_reader :coordinates
|
95
|
+
|
96
|
+
# A float, the standard first element of a coordinate triple.
|
97
|
+
attr_reader :longitude
|
98
|
+
alias :lng :longitude
|
99
|
+
|
100
|
+
# A float, the standard second element of a coordinate triple.
|
101
|
+
attr_reader :latitude
|
102
|
+
alias :lat :latitude
|
103
|
+
|
104
|
+
# A float, the standard third element of a coordinate triple.
|
105
|
+
attr_reader :elevation
|
106
|
+
|
107
|
+
# An integer, Google's rating of the accuracy of the supplied address.
|
108
|
+
attr_reader :accuracy
|
109
|
+
|
110
|
+
# All address attributes as one string, formatted by the service.
|
111
|
+
attr_reader :full_address
|
112
|
+
alias :to_s :full_address
|
113
|
+
|
114
|
+
# The address query sent to the service. i.e. The user input.
|
115
|
+
attr_reader :query
|
116
|
+
|
117
|
+
def initialize(placemark, query) #:nodoc
|
118
|
+
@xml = placemark
|
119
|
+
@query = query
|
120
|
+
|
121
|
+
{
|
122
|
+
:@street => :ThoroughfareName,
|
123
|
+
:@city => :LocalityName,
|
124
|
+
:@zip => :PostalCodeNumber,
|
125
|
+
:@county => :SubAdministrativeAreaName,
|
126
|
+
:@state => :AdministrativeAreaName,
|
127
|
+
:@country => :CountryNameCode,
|
128
|
+
|
129
|
+
:@full_address => :address
|
130
|
+
}.each do |attribute, element|
|
131
|
+
instance_variable_set(attribute, (fetch(element) rescue nil))
|
132
|
+
end
|
133
|
+
|
134
|
+
@longitude, @latitude, @elevation = @coordinates = fetch(:coordinates).split(',').map { |x| x.to_f }
|
135
|
+
|
136
|
+
@accuracy = fetch_accuracy
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
###
|
141
|
+
|
142
|
+
class Response #:nodoc:
|
143
|
+
include Parser
|
144
|
+
|
145
|
+
attr_reader :query, :status, :placemarks
|
146
|
+
|
147
|
+
def initialize(xml, geo_key) #:nodoc
|
148
|
+
@xml, @geo_key = xml, geo_key
|
149
|
+
|
150
|
+
@query = fetch(:name)
|
151
|
+
@status = fetch(:code).to_i
|
152
|
+
|
153
|
+
check_for_errors
|
154
|
+
|
155
|
+
@placemarks = @xml.scan %r{<Placemark(?: id="p\d+")?>.+?</Placemark>}m
|
156
|
+
end
|
157
|
+
|
158
|
+
def check_for_errors #:nodoc:
|
159
|
+
case status
|
160
|
+
when 200 then # Success
|
161
|
+
when 500 then raise ServerError, "Unknown error from Google's server"
|
162
|
+
when 601 then raise MissingAddressError, "Missing address"
|
163
|
+
when 602 then raise UnknownAddressError, "Unknown address: #{@query}"
|
164
|
+
when 603 then raise UnavailableAddressError, "Unavailable address: #{@query}"
|
165
|
+
when 610 then raise InvalidMapKeyError, "Invalid map key: #{@geo_key}"
|
166
|
+
when 620 then raise TooManyQueriesError, "Too many queries for map key: #{@geo_key}"
|
167
|
+
else raise UnknownError, "Unknown error: #{@status}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
###
|
173
|
+
|
174
|
+
class Error < Exception; end
|
175
|
+
|
176
|
+
class ServerError < Error; end
|
177
|
+
|
178
|
+
class AddressError < Error; end
|
179
|
+
class MissingAddressError < AddressError; end
|
180
|
+
class UnknownAddressError < AddressError; end
|
181
|
+
class UnavailableAddressError < AddressError; end
|
182
|
+
|
183
|
+
class MapKeyError < Error; end
|
184
|
+
class InvalidMapKeyError < MapKeyError; end
|
185
|
+
class TooManyQueriesError < MapKeyError; end
|
186
|
+
|
187
|
+
class UnknownError < Error; end
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
data/test/geo_test.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
$:.unshift "#{File.dirname __FILE__}/../vendor/mocha-0.4.0/lib"
|
3
|
+
require 'mocha'
|
4
|
+
require "#{File.dirname __FILE__}/../lib/google/geo"
|
5
|
+
|
6
|
+
class Google::GeoTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@geo = Google::Geo.new 'API_KEY'
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_success
|
12
|
+
@geo.expects(:open).
|
13
|
+
with("http://maps.google.com/maps/geo?q=1600%20Amphitheatre%20Parkway,%20Mountain%20View,%20CA&key=API_KEY&output=xml"). # show that query is escaped
|
14
|
+
returns(response(:success))
|
15
|
+
|
16
|
+
query = '1600 Amphitheatre Parkway, Mountain View, CA'
|
17
|
+
|
18
|
+
address = @geo.locate(query).first
|
19
|
+
|
20
|
+
assert_equal '1600 Amphitheatre Pkwy', address.street
|
21
|
+
assert_equal address.street, address.thoroughfare
|
22
|
+
|
23
|
+
assert_equal 'Mountain View', address.city
|
24
|
+
assert_equal address.city, address.locality
|
25
|
+
|
26
|
+
assert_equal '94043', address.zip
|
27
|
+
assert_equal address.zip, address.postal_code
|
28
|
+
|
29
|
+
assert_equal 'Santa Clara', address.county
|
30
|
+
assert_equal address.county, address.subadministrative_area
|
31
|
+
|
32
|
+
assert_equal 'CA', address.state
|
33
|
+
assert_equal address.state, address.administrative_area
|
34
|
+
|
35
|
+
assert_equal 'US', address.country
|
36
|
+
assert_equal address.country, address.country_code
|
37
|
+
|
38
|
+
assert_equal -122.083739, address.longitude
|
39
|
+
assert_equal address.longitude, address.lng
|
40
|
+
|
41
|
+
assert_equal 37.423021, address.latitude
|
42
|
+
assert_equal address.latitude, address.lat
|
43
|
+
|
44
|
+
assert_equal 0, address.elevation
|
45
|
+
|
46
|
+
assert_equal [address.longitude, address.latitude, address.elevation], address.coordinates
|
47
|
+
|
48
|
+
assert_equal 8, address.accuracy
|
49
|
+
|
50
|
+
assert_equal '1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA', address.full_address
|
51
|
+
assert_equal query, address.query
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_invalid_map_key
|
55
|
+
@geo.expects(:open).returns(response(:invalid_map_key))
|
56
|
+
assert_raises(Google::Geo::InvalidMapKeyError) { @geo.locate 'foo' }
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_missing_address
|
60
|
+
@geo.expects(:open).returns(response(:missing_address))
|
61
|
+
assert_raises(Google::Geo::MissingAddressError) { @geo.locate 'foo' }
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_server_error
|
65
|
+
@geo.expects(:open).returns(response(:server_error))
|
66
|
+
assert_raises(Google::Geo::ServerError) { @geo.locate 'foo' }
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_too_many_queries
|
70
|
+
@geo.expects(:open).returns(response(:too_many_queries))
|
71
|
+
assert_raises(Google::Geo::TooManyQueriesError) { @geo.locate 'foo' }
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_unavailable_address
|
75
|
+
@geo.expects(:open).returns(response(:unavailable_address))
|
76
|
+
assert_raises(Google::Geo::UnavailableAddressError) { @geo.locate 'foo' }
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_unknown_address
|
80
|
+
@geo.expects(:open).returns(response(:unknown_address))
|
81
|
+
assert_raises(Google::Geo::UnknownAddressError) { @geo.locate 'foo' }
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def response(filename)
|
86
|
+
File.new "#{File.dirname __FILE__}/fixtures/#{filename}.xml"
|
87
|
+
end
|
88
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: google-geo
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "1.0"
|
7
|
+
date: 2007-05-24 00:00:00 -07:00
|
8
|
+
summary: A simple, elegant library for getting geocoding information from Google Maps. Very much inspired by the google-geocode gem, but completely dependency free!
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email:
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- " \n"
|
31
|
+
files:
|
32
|
+
- lib/google
|
33
|
+
- lib/google/geo.rb
|
34
|
+
- README
|
35
|
+
- CHANGELOG
|
36
|
+
test_files:
|
37
|
+
- test/geo_test.rb
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README
|
42
|
+
- CHANGELOG
|
43
|
+
executables: []
|
44
|
+
|
45
|
+
extensions: []
|
46
|
+
|
47
|
+
requirements: []
|
48
|
+
|
49
|
+
dependencies: []
|
50
|
+
|