google-geo 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/CHANGELOG +1 -0
  2. data/README +27 -0
  3. data/lib/google/geo.rb +190 -0
  4. data/test/geo_test.rb +88 -0
  5. metadata +50 -0
@@ -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
@@ -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
@@ -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
+