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.
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
+