rails-geocoder 0.9.4 → 0.9.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +7 -0
- data/README.rdoc +19 -25
- data/VERSION +1 -1
- data/lib/geocoder.rb +91 -108
- data/rails-geocoder.gemspec +7 -7
- data/test/fixtures/madison_square_garden.json +57 -0
- data/test/geocoder_test.rb +2 -2
- data/test/test_helper.rb +10 -11
- metadata +11 -6
- data/test/fixtures/madison_square_garden.xml +0 -69
data/CHANGELOG.rdoc
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
Per-release changes to Geocoder.
|
4
4
|
|
5
|
+
== 0.9.5 (2010 Oct 15)
|
6
|
+
|
7
|
+
* Fix broken PostgreSQL compatibility (now 100% compatible).
|
8
|
+
* Switch from Google's XML to JSON geocoding API.
|
9
|
+
* Separate Rails 2 and Rails 3-compatible branches.
|
10
|
+
* Don't allow :conditions hash in 'options' argument to 'nearbys' method (was deprecated in 0.9.3).
|
11
|
+
|
5
12
|
== 0.9.4 (2010 Aug 2)
|
6
13
|
|
7
14
|
* Google Maps API key no longer required (uses geocoder v3).
|
data/README.rdoc
CHANGED
@@ -2,46 +2,33 @@
|
|
2
2
|
|
3
3
|
Geocoder adds object geocoding and database-agnostic distance calculations to Ruby on Rails. It's as simple as calling <tt>fetch_coordinates!</tt> on your objects, and then using a scope like <tt>Venue.near("Billings, MT")</tt>. Since it does not rely on proprietary database functions finding geocoded objects in a given area works with out-of-the-box MySQL or even SQLite.
|
4
4
|
|
5
|
-
|
5
|
+
Geocoder is compatible with Rails 2.x and 3.x. <b>This is the README for the 3.x branch.</b> Please see the 2.x branch for installation instructions, documentation, and issues.
|
6
6
|
|
7
7
|
|
8
8
|
== 1. Install
|
9
9
|
|
10
|
-
=== a
|
10
|
+
=== As a Gem
|
11
11
|
|
12
|
-
|
12
|
+
Add this to your Gemfile:
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
or as a gem:
|
14
|
+
gem "rails-geocoder", :require => "geocoder"
|
17
15
|
|
18
|
-
|
19
|
-
config.gem "rails-geocoder", :lib => "geocoder", :source => "http://gemcutter.org/"
|
20
|
-
|
21
|
-
# at command prompt:
|
22
|
-
sudo rake gems:install
|
16
|
+
and run this at the command prompt:
|
23
17
|
|
18
|
+
bundle install
|
24
19
|
|
25
|
-
===
|
20
|
+
=== Or As a Plugin
|
26
21
|
|
27
|
-
|
22
|
+
At the command prompt:
|
28
23
|
|
29
24
|
rails plugin install git://github.com/alexreisner/geocoder.git
|
30
25
|
|
31
|
-
or as a gem:
|
32
|
-
|
33
|
-
# add to Gemfile:
|
34
|
-
gem "rails-geocoder", :require => "geocoder"
|
35
|
-
|
36
|
-
# at command prompt:
|
37
|
-
bundle install
|
38
|
-
|
39
26
|
|
40
27
|
== 2. Configure
|
41
28
|
|
42
29
|
A) Add +latitude+ and +longitude+ columns to your model:
|
43
30
|
|
44
|
-
|
31
|
+
rails generate migration AddLatitudeAndLongitudeToYourModel latitude:float longitude:float
|
45
32
|
rake db:migrate
|
46
33
|
|
47
34
|
B) Tell geocoder where your model stores its address:
|
@@ -82,10 +69,10 @@ Some utility methods are also available:
|
|
82
69
|
|
83
70
|
# distance (in miles) between Eiffel Tower and Empire State Building
|
84
71
|
Geocoder.distance_between( 48.858205,2.294359, 40.748433,-73.985655 )
|
85
|
-
|
72
|
+
|
86
73
|
# look up coordinates of some location (like searching Google Maps)
|
87
74
|
Geocoder.fetch_coordinates("25 Main St, Cooperstown, NY")
|
88
|
-
|
75
|
+
|
89
76
|
# find the geographic center (aka center of gravity) of objects or points
|
90
77
|
Geocoder.geographic_center([ city1, city2, city3, [40.22,-73.99], city4 ])
|
91
78
|
|
@@ -144,9 +131,16 @@ If anyone has a more elegant solution to this problem I am very interested in se
|
|
144
131
|
|
145
132
|
== To-do List
|
146
133
|
|
147
|
-
*
|
134
|
+
* use completely separate "drivers" for different AR adapters?
|
135
|
+
* seems reasonable since we're using very DB-specific features
|
136
|
+
* also need to make sure 'mysql2' is supported
|
137
|
+
* add reverse geocoding
|
138
|
+
* make 'near' scope work with AR associations
|
139
|
+
* http://stackoverflow.com/questions/3266358/geocoder-rails-plugin-near-search-problem-with-activerecord
|
148
140
|
* prepend table names to column names in SQL distance expression (required
|
149
141
|
to do joins on another geocoded model)
|
142
|
+
* unobtrusively add ability to get a result with more data (Geocoder object?)
|
143
|
+
* the default usage should remain dead simple
|
150
144
|
|
151
145
|
|
152
146
|
Copyright (c) 2009-10 Alex Reisner, released under the MIT license
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.5
|
data/lib/geocoder.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
require 'rexml/document'
|
2
|
-
|
3
1
|
##
|
4
2
|
# Add geocoding functionality (via Google) to any object.
|
5
3
|
#
|
6
4
|
module Geocoder
|
7
|
-
|
5
|
+
|
8
6
|
##
|
9
7
|
# Implementation of 'included' hook method.
|
10
8
|
#
|
@@ -13,21 +11,21 @@ module Geocoder
|
|
13
11
|
base.class_eval do
|
14
12
|
|
15
13
|
# scope: geocoded objects
|
16
|
-
|
14
|
+
scope :geocoded,
|
17
15
|
:conditions => "#{geocoder_options[:latitude]} IS NOT NULL " +
|
18
|
-
"AND #{geocoder_options[:longitude]} IS NOT NULL"
|
16
|
+
"AND #{geocoder_options[:longitude]} IS NOT NULL"
|
19
17
|
|
20
18
|
# scope: not-geocoded objects
|
21
|
-
|
19
|
+
scope :not_geocoded,
|
22
20
|
:conditions => "#{geocoder_options[:latitude]} IS NULL " +
|
23
|
-
"OR #{geocoder_options[:longitude]} IS NULL"
|
24
|
-
|
21
|
+
"OR #{geocoder_options[:longitude]} IS NULL"
|
22
|
+
|
25
23
|
##
|
26
24
|
# Find all objects within a radius (in miles) of the given location
|
27
25
|
# (address string). Location (the first argument) may be either a string
|
28
26
|
# to geocode or an array of coordinates (<tt>[lat,long]</tt>).
|
29
27
|
#
|
30
|
-
|
28
|
+
scope :near, lambda{ |location, *args|
|
31
29
|
latitude, longitude = location.is_a?(Array) ?
|
32
30
|
location : Geocoder.fetch_coordinates(location)
|
33
31
|
if latitude and longitude
|
@@ -35,10 +33,10 @@ module Geocoder
|
|
35
33
|
else
|
36
34
|
{}
|
37
35
|
end
|
38
|
-
}
|
36
|
+
}
|
39
37
|
end
|
40
38
|
end
|
41
|
-
|
39
|
+
|
42
40
|
##
|
43
41
|
# Methods which will be class methods of the including class.
|
44
42
|
#
|
@@ -48,13 +46,16 @@ module Geocoder
|
|
48
46
|
# Get options hash suitable for passing to ActiveRecord.find to get
|
49
47
|
# records within a radius (in miles) of the given point.
|
50
48
|
# Options hash may include:
|
51
|
-
#
|
52
|
-
# +
|
53
|
-
# +
|
54
|
-
# +
|
55
|
-
# +
|
49
|
+
#
|
50
|
+
# +units+ :: <tt>:mi</tt> (default) or <tt>:km</tt>
|
51
|
+
# +exclude+ :: an object to exclude (used by the #nearbys method)
|
52
|
+
# +order+ :: column(s) for ORDER BY SQL clause
|
53
|
+
# +limit+ :: number of records to return (for LIMIT SQL clause)
|
54
|
+
# +offset+ :: number of records to skip (for OFFSET SQL clause)
|
55
|
+
# +select+ :: string with the SELECT SQL fragment (e.g. “id, name”)
|
56
56
|
#
|
57
57
|
def near_scope_options(latitude, longitude, radius = 20, options = {})
|
58
|
+
radius *= km_in_mi if options[:units] == :km
|
58
59
|
if ActiveRecord::Base.connection.adapter_name == "SQLite"
|
59
60
|
approx_near_scope_options(latitude, longitude, radius, options)
|
60
61
|
else
|
@@ -68,7 +69,7 @@ module Geocoder
|
|
68
69
|
##
|
69
70
|
# Scope options hash for use with a database that supports POWER(),
|
70
71
|
# SQRT(), PI(), and trigonometric functions (SIN(), COS(), and ASIN()).
|
71
|
-
#
|
72
|
+
#
|
72
73
|
# Taken from the excellent tutorial at:
|
73
74
|
# http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
|
74
75
|
#
|
@@ -99,7 +100,7 @@ module Geocoder
|
|
99
100
|
:select => options[:select] || nil
|
100
101
|
)
|
101
102
|
end
|
102
|
-
|
103
|
+
|
103
104
|
##
|
104
105
|
# Options used for any near-like scope.
|
105
106
|
#
|
@@ -109,27 +110,19 @@ module Geocoder
|
|
109
110
|
conditions = \
|
110
111
|
["#{lat_attr} BETWEEN ? AND ? AND #{lon_attr} BETWEEN ? AND ?"] +
|
111
112
|
coordinate_bounds(latitude, longitude, radius)
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
# exclude objects by ID from the nearbys method. This is incredibly
|
116
|
-
# ugly and doesn't work for a conditions hash: try using Arel?
|
117
|
-
if options[:conditions].is_a?(String)
|
118
|
-
options[:conditions] = [options[:conditions]]
|
119
|
-
end
|
120
|
-
if options[:conditions].is_a?(Array)
|
121
|
-
conditions[0] = "(#{conditions[0]}) AND #{options[:conditions][0]}"
|
122
|
-
conditions << options[:conditions][1]
|
113
|
+
if obj = options[:exclude]
|
114
|
+
conditions[0] << " AND id != ?"
|
115
|
+
conditions << obj.id
|
123
116
|
end
|
124
|
-
|
125
117
|
{
|
118
|
+
:group => columns.map{ |c| c.name}.join(','),
|
126
119
|
:order => options[:order],
|
127
120
|
:limit => options[:limit],
|
128
121
|
:offset => options[:offset],
|
129
122
|
:conditions => conditions
|
130
123
|
}
|
131
124
|
end
|
132
|
-
|
125
|
+
|
133
126
|
##
|
134
127
|
# Get the rough high/low lat/long bounds for a geographic point and
|
135
128
|
# radius. Returns an array: <tt>[lat_lo, lat_hi, lon_lo, lon_hi]</tt>.
|
@@ -145,6 +138,13 @@ module Geocoder
|
|
145
138
|
longitude + (radius / factor)
|
146
139
|
]
|
147
140
|
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Conversion factor: km to mi.
|
144
|
+
#
|
145
|
+
def km_in_mi
|
146
|
+
0.621371192
|
147
|
+
end
|
148
148
|
end
|
149
149
|
|
150
150
|
##
|
@@ -161,7 +161,7 @@ module Geocoder
|
|
161
161
|
def geocoded?
|
162
162
|
read_coordinates.compact.size > 0
|
163
163
|
end
|
164
|
-
|
164
|
+
|
165
165
|
##
|
166
166
|
# Calculate the distance from the object to a point (lat,lon).
|
167
167
|
# Valid units are defined in <tt>distance_between</tt> class method.
|
@@ -171,26 +171,17 @@ module Geocoder
|
|
171
171
|
mylat,mylon = read_coordinates
|
172
172
|
Geocoder.distance_between(mylat, mylon, lat, lon, :units => units)
|
173
173
|
end
|
174
|
-
|
174
|
+
|
175
175
|
##
|
176
|
-
# Get other geocoded objects within a given radius
|
177
|
-
#
|
178
|
-
# (<tt>:order</tt>, <tt>:limit</tt>, and <tt>:offset</tt>).
|
176
|
+
# Get other geocoded objects within a given radius.
|
177
|
+
# Valid units are defined in <tt>distance_between</tt> class method.
|
179
178
|
#
|
180
|
-
def nearbys(radius = 20,
|
181
|
-
if options != {}
|
182
|
-
warn "DEPRECATION WARNING: The 'options' argument to the nearbys " +
|
183
|
-
"method is deprecated and will be removed from rails-geocoder in " +
|
184
|
-
"a future version. Nearbys now returns a scope so you should " +
|
185
|
-
"specify more scopes and/or conditions via chaining. For example: " +
|
186
|
-
"city.nearbys(20).order('name').limit(10). Support for Rails 2.x " +
|
187
|
-
"will be discontinued soon."
|
188
|
-
end
|
179
|
+
def nearbys(radius = 20, units = :mi)
|
189
180
|
return [] unless geocoded?
|
190
|
-
options
|
181
|
+
options = {:exclude => self, :units => units}
|
191
182
|
self.class.near(read_coordinates, radius, options)
|
192
183
|
end
|
193
|
-
|
184
|
+
|
194
185
|
##
|
195
186
|
# Fetch coordinates and assign +latitude+ and +longitude+. Also returns
|
196
187
|
# coordinates as an array: <tt>[lat, lon]</tt>.
|
@@ -214,55 +205,36 @@ module Geocoder
|
|
214
205
|
fetch_coordinates(true)
|
215
206
|
end
|
216
207
|
|
217
|
-
##
|
218
|
-
# Query Google for the coordinates of the given phrase.
|
219
|
-
# Returns array [lat,lon] if found, nil if not found or if network error.
|
220
|
-
#
|
221
|
-
def self.fetch_coordinates(query)
|
222
|
-
return nil if query.blank?
|
223
|
-
return nil unless doc = self.search(query)
|
224
|
-
|
225
|
-
# make sure search found a result
|
226
|
-
e = doc.elements['GeocodeResponse/status']
|
227
|
-
return nil unless (e and e.text == "OK")
|
228
|
-
|
229
|
-
# isolate the relevant part of the result
|
230
|
-
place = doc.elements['GeocodeResponse/result/geometry/location']
|
231
|
-
|
232
|
-
# blindly use the first results (assume they are most accurate)
|
233
|
-
['lat', 'lng'].map{ |i| place.elements[i].text.to_f }
|
234
|
-
end
|
235
|
-
|
236
208
|
##
|
237
209
|
# Calculate the distance between two points on Earth (Haversine formula).
|
238
210
|
# Takes two sets of coordinates and an options hash:
|
239
|
-
#
|
211
|
+
#
|
240
212
|
# <tt>:units</tt> :: <tt>:mi</tt> (default) or <tt>:km</tt>
|
241
213
|
#
|
242
214
|
def self.distance_between(lat1, lon1, lat2, lon2, options = {})
|
243
|
-
|
215
|
+
|
244
216
|
# set default options
|
245
217
|
options[:units] ||= :mi
|
246
|
-
|
218
|
+
|
247
219
|
# define conversion factors
|
248
|
-
|
249
|
-
|
220
|
+
conversions = { :mi => 3956, :km => 6371 }
|
221
|
+
|
250
222
|
# convert degrees to radians
|
251
223
|
lat1 = to_radians(lat1)
|
252
224
|
lon1 = to_radians(lon1)
|
253
225
|
lat2 = to_radians(lat2)
|
254
226
|
lon2 = to_radians(lon2)
|
255
|
-
|
227
|
+
|
256
228
|
# compute distances
|
257
229
|
dlat = (lat1 - lat2).abs
|
258
230
|
dlon = (lon1 - lon2).abs
|
259
|
-
|
231
|
+
|
260
232
|
a = (Math.sin(dlat / 2))**2 + Math.cos(lat1) *
|
261
|
-
(Math.sin(dlon / 2))**2 * Math.cos(lat2)
|
262
|
-
c = 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a))
|
263
|
-
c *
|
233
|
+
(Math.sin(dlon / 2))**2 * Math.cos(lat2)
|
234
|
+
c = 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a))
|
235
|
+
c * conversions[options[:units]]
|
264
236
|
end
|
265
|
-
|
237
|
+
|
266
238
|
##
|
267
239
|
# Compute the geographic center (aka geographic midpoint, center of
|
268
240
|
# gravity) for an array of geocoded objects and/or [lat,lon] arrays
|
@@ -270,15 +242,15 @@ module Geocoder
|
|
270
242
|
# the procedure documented at http://www.geomidpoint.com/calculation.html.
|
271
243
|
#
|
272
244
|
def self.geographic_center(points)
|
273
|
-
|
245
|
+
|
274
246
|
# convert objects to [lat,lon] arrays and remove nils
|
275
247
|
points = points.map{ |p|
|
276
248
|
p.is_a?(Array) ? p : (p.geocoded?? p.read_coordinates : nil)
|
277
249
|
}.compact
|
278
|
-
|
250
|
+
|
279
251
|
# convert degrees to radians
|
280
252
|
points.map!{ |p| [to_radians(p[0]), to_radians(p[1])] }
|
281
|
-
|
253
|
+
|
282
254
|
# convert to Cartesian coordinates
|
283
255
|
x = []; y = []; z = []
|
284
256
|
points.each do |p|
|
@@ -291,12 +263,12 @@ module Geocoder
|
|
291
263
|
xa, ya, za = [x,y,z].map do |c|
|
292
264
|
c.inject(0){ |tot,i| tot += i } / c.size.to_f
|
293
265
|
end
|
294
|
-
|
266
|
+
|
295
267
|
# convert back to latitude/longitude
|
296
268
|
lon = Math.atan2(ya, xa)
|
297
269
|
hyp = Math.sqrt(xa**2 + ya**2)
|
298
270
|
lat = Math.atan2(za, hyp)
|
299
|
-
|
271
|
+
|
300
272
|
# return answer in degrees
|
301
273
|
[to_degrees(lat), to_degrees(lon)]
|
302
274
|
end
|
@@ -307,35 +279,57 @@ module Geocoder
|
|
307
279
|
def self.to_radians(degrees)
|
308
280
|
degrees * (Math::PI / 180)
|
309
281
|
end
|
310
|
-
|
282
|
+
|
311
283
|
##
|
312
284
|
# Convert radians to degrees.
|
313
285
|
#
|
314
286
|
def self.to_degrees(radians)
|
315
287
|
(radians * 180.0) / Math::PI
|
316
288
|
end
|
317
|
-
|
289
|
+
|
318
290
|
##
|
319
291
|
# Query Google for geographic information about the given phrase.
|
292
|
+
# Returns a hash representing a valid geocoder response.
|
293
|
+
# Returns nil if non-200 HTTP response, timeout, or other error.
|
320
294
|
#
|
321
295
|
def self.search(query)
|
322
|
-
|
323
|
-
|
296
|
+
doc = _fetch_parsed_response(query)
|
297
|
+
doc && doc['status'] == "OK" ? doc : nil
|
298
|
+
end
|
299
|
+
|
300
|
+
##
|
301
|
+
# Query Google for the coordinates of the given phrase.
|
302
|
+
# Returns array [lat,lon] if found, nil if not found or if network error.
|
303
|
+
#
|
304
|
+
def self.fetch_coordinates(query)
|
305
|
+
return nil unless doc = self.search(query)
|
306
|
+
# blindly use the first results (assume they are most accurate)
|
307
|
+
place = doc['results'].first['geometry']['location']
|
308
|
+
['lat', 'lng'].map{ |i| place[i] }
|
309
|
+
end
|
310
|
+
|
311
|
+
##
|
312
|
+
# Returns a parsed Google geocoder search result (hash).
|
313
|
+
# This method is not intended for general use (prefer Geocoder.search).
|
314
|
+
#
|
315
|
+
def self._fetch_parsed_response(query)
|
316
|
+
if doc = _fetch_raw_response(query)
|
317
|
+
ActiveSupport::JSON.decode(doc)
|
324
318
|
end
|
325
319
|
end
|
326
|
-
|
320
|
+
|
327
321
|
##
|
328
|
-
#
|
322
|
+
# Returns a raw Google geocoder search result (JSON).
|
329
323
|
# This method is not intended for general use (prefer Geocoder.search).
|
330
324
|
#
|
331
|
-
def self.
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
}
|
336
|
-
url = "http://maps.google.com/maps/api/geocode/
|
337
|
-
|
338
|
-
#
|
325
|
+
def self._fetch_raw_response(query)
|
326
|
+
return nil if query.blank?
|
327
|
+
|
328
|
+
# build URL
|
329
|
+
params = { :address => query, :sensor => "false" }
|
330
|
+
url = "http://maps.google.com/maps/api/geocode/json?" + params.to_query
|
331
|
+
|
332
|
+
# query geocoder and make sure it responds quickly
|
339
333
|
begin
|
340
334
|
resp = nil
|
341
335
|
timeout(3) do
|
@@ -345,24 +339,13 @@ module Geocoder
|
|
345
339
|
return nil
|
346
340
|
end
|
347
341
|
end
|
348
|
-
|
349
|
-
##
|
350
|
-
# Name of the ActiveRecord scope method.
|
351
|
-
#
|
352
|
-
def self.scope_method_name
|
353
|
-
begin
|
354
|
-
Rails.version.starts_with?("3") ? :scope : :named_scope
|
355
|
-
rescue NameError
|
356
|
-
:named_scope
|
357
|
-
end
|
358
|
-
end
|
359
342
|
end
|
360
343
|
|
361
344
|
##
|
362
345
|
# Add geocoded_by method to ActiveRecord::Base so Geocoder is accessible.
|
363
346
|
#
|
364
347
|
ActiveRecord::Base.class_eval do
|
365
|
-
|
348
|
+
|
366
349
|
##
|
367
350
|
# Set attribute names and include the Geocoder module.
|
368
351
|
#
|
data/rails-geocoder.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rails-geocoder}
|
8
|
-
s.version = "0.9.
|
8
|
+
s.version = "0.9.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Alex Reisner"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-15}
|
13
13
|
s.description = %q{Geocoder adds object geocoding and database-agnostic distance calculations to Ruby on Rails. It does not rely on proprietary database functions so finding geocoded objects in a given area is easily done using out-of-the-box MySQL or even SQLite.}
|
14
14
|
s.email = %q{alex@alexreisner.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -28,25 +28,25 @@ Gem::Specification.new do |s|
|
|
28
28
|
"lib/geocoder.rb",
|
29
29
|
"lib/tasks/geocoder_tasks.rake",
|
30
30
|
"rails-geocoder.gemspec",
|
31
|
-
"test/fixtures/madison_square_garden.
|
31
|
+
"test/fixtures/madison_square_garden.json",
|
32
32
|
"test/geocoder_test.rb",
|
33
33
|
"test/test_helper.rb"
|
34
34
|
]
|
35
35
|
s.homepage = %q{http://github.com/alexreisner/geocoder}
|
36
36
|
s.rdoc_options = ["--charset=UTF-8"]
|
37
37
|
s.require_paths = ["lib"]
|
38
|
-
s.rubygems_version = %q{1.3.
|
38
|
+
s.rubygems_version = %q{1.3.7}
|
39
39
|
s.summary = %q{Add geocoding functionality to Rails models.}
|
40
40
|
s.test_files = [
|
41
|
-
"test/
|
42
|
-
"test/
|
41
|
+
"test/test_helper.rb",
|
42
|
+
"test/geocoder_test.rb"
|
43
43
|
]
|
44
44
|
|
45
45
|
if s.respond_to? :specification_version then
|
46
46
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
47
|
s.specification_version = 3
|
48
48
|
|
49
|
-
if Gem::Version.new(Gem::
|
49
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
50
|
else
|
51
51
|
end
|
52
52
|
else
|
@@ -0,0 +1,57 @@
|
|
1
|
+
{
|
2
|
+
"status": "OK",
|
3
|
+
"results": [ {
|
4
|
+
"types": [ "street_address" ],
|
5
|
+
"formatted_address": "4 Penn Plaza, New York, NY 10001, USA",
|
6
|
+
"address_components": [ {
|
7
|
+
"long_name": "4",
|
8
|
+
"short_name": "4",
|
9
|
+
"types": [ "street_number" ]
|
10
|
+
}, {
|
11
|
+
"long_name": "Penn Plaza",
|
12
|
+
"short_name": "Penn Plaza",
|
13
|
+
"types": [ "route" ]
|
14
|
+
}, {
|
15
|
+
"long_name": "Manhattan",
|
16
|
+
"short_name": "Manhattan",
|
17
|
+
"types": [ "sublocality", "political" ]
|
18
|
+
}, {
|
19
|
+
"long_name": "New York",
|
20
|
+
"short_name": "New York",
|
21
|
+
"types": [ "locality", "political" ]
|
22
|
+
}, {
|
23
|
+
"long_name": "New York",
|
24
|
+
"short_name": "New York",
|
25
|
+
"types": [ "administrative_area_level_2", "political" ]
|
26
|
+
}, {
|
27
|
+
"long_name": "New York",
|
28
|
+
"short_name": "NY",
|
29
|
+
"types": [ "administrative_area_level_1", "political" ]
|
30
|
+
}, {
|
31
|
+
"long_name": "United States",
|
32
|
+
"short_name": "US",
|
33
|
+
"types": [ "country", "political" ]
|
34
|
+
}, {
|
35
|
+
"long_name": "10001",
|
36
|
+
"short_name": "10001",
|
37
|
+
"types": [ "postal_code" ]
|
38
|
+
} ],
|
39
|
+
"geometry": {
|
40
|
+
"location": {
|
41
|
+
"lat": 40.7503540,
|
42
|
+
"lng": -73.9933710
|
43
|
+
},
|
44
|
+
"location_type": "ROOFTOP",
|
45
|
+
"viewport": {
|
46
|
+
"southwest": {
|
47
|
+
"lat": 40.7473324,
|
48
|
+
"lng": -73.9965316
|
49
|
+
},
|
50
|
+
"northeast": {
|
51
|
+
"lat": 40.7536276,
|
52
|
+
"lng": -73.9902364
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
} ]
|
57
|
+
}
|
data/test/geocoder_test.rb
CHANGED
@@ -7,12 +7,12 @@ class GeocoderTest < Test::Unit::TestCase
|
|
7
7
|
assert_equal [40.750354, -73.993371], v.fetch_coordinates
|
8
8
|
assert_equal [40.750354, -73.993371], [v.latitude, v.longitude]
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
# sanity check
|
12
12
|
def test_distance_between
|
13
13
|
assert_equal 69, Geocoder.distance_between(0,0, 0,1).round
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
# sanity check
|
17
17
|
def test_geographic_center
|
18
18
|
assert_equal [0.0, 0.5],
|
data/test/test_helper.rb
CHANGED
@@ -10,24 +10,24 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
10
10
|
#
|
11
11
|
module ActiveRecord
|
12
12
|
class Base
|
13
|
-
|
13
|
+
|
14
14
|
def initialize
|
15
15
|
@attributes = {}
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def read_attribute(attr_name)
|
19
19
|
@attributes[attr_name.to_sym]
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def write_attribute(attr_name, value)
|
23
23
|
@attributes[attr_name.to_sym] = value
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def update_attribute(attr_name, value)
|
27
27
|
write_attribute(attr_name.to_sym, value)
|
28
28
|
end
|
29
|
-
|
30
|
-
def self.
|
29
|
+
|
30
|
+
def self.scope(*args); end
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -38,9 +38,8 @@ require 'geocoder'
|
|
38
38
|
# Mock HTTP request to Google.
|
39
39
|
#
|
40
40
|
module Geocoder
|
41
|
-
def self.
|
42
|
-
|
43
|
-
File.read(filename)
|
41
|
+
def self._fetch_raw_response(query)
|
42
|
+
File.read(File.join("test", "fixtures", "madison_square_garden.json"))
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
@@ -49,13 +48,13 @@ end
|
|
49
48
|
#
|
50
49
|
class Venue < ActiveRecord::Base
|
51
50
|
geocoded_by :address
|
52
|
-
|
51
|
+
|
53
52
|
def initialize(name, address)
|
54
53
|
super()
|
55
54
|
write_attribute :name, name
|
56
55
|
write_attribute :address, address
|
57
56
|
end
|
58
|
-
|
57
|
+
|
59
58
|
##
|
60
59
|
# If method not found, assume it's an ActiveRecord attribute reader.
|
61
60
|
#
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-geocoder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 49
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 9
|
8
|
-
-
|
9
|
-
version: 0.9.
|
9
|
+
- 5
|
10
|
+
version: 0.9.5
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Alex Reisner
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-10-15 00:00:00 -04:00
|
18
19
|
default_executable:
|
19
20
|
dependencies: []
|
20
21
|
|
@@ -39,7 +40,7 @@ files:
|
|
39
40
|
- lib/geocoder.rb
|
40
41
|
- lib/tasks/geocoder_tasks.rake
|
41
42
|
- rails-geocoder.gemspec
|
42
|
-
- test/fixtures/madison_square_garden.
|
43
|
+
- test/fixtures/madison_square_garden.json
|
43
44
|
- test/geocoder_test.rb
|
44
45
|
- test/test_helper.rb
|
45
46
|
has_rdoc: true
|
@@ -52,26 +53,30 @@ rdoc_options:
|
|
52
53
|
require_paths:
|
53
54
|
- lib
|
54
55
|
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
55
57
|
requirements:
|
56
58
|
- - ">="
|
57
59
|
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
58
61
|
segments:
|
59
62
|
- 0
|
60
63
|
version: "0"
|
61
64
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
62
66
|
requirements:
|
63
67
|
- - ">="
|
64
68
|
- !ruby/object:Gem::Version
|
69
|
+
hash: 3
|
65
70
|
segments:
|
66
71
|
- 0
|
67
72
|
version: "0"
|
68
73
|
requirements: []
|
69
74
|
|
70
75
|
rubyforge_project:
|
71
|
-
rubygems_version: 1.3.
|
76
|
+
rubygems_version: 1.3.7
|
72
77
|
signing_key:
|
73
78
|
specification_version: 3
|
74
79
|
summary: Add geocoding functionality to Rails models.
|
75
80
|
test_files:
|
76
|
-
- test/geocoder_test.rb
|
77
81
|
- test/test_helper.rb
|
82
|
+
- test/geocoder_test.rb
|
@@ -1,69 +0,0 @@
|
|
1
|
-
<GeocodeResponse>
|
2
|
-
<status>OK</status>
|
3
|
-
<result>
|
4
|
-
<type>street_address</type>
|
5
|
-
<formatted_address>4 Penn Plaza, New York, NY 10001, USA</formatted_address>
|
6
|
-
<address_component>
|
7
|
-
<long_name>4</long_name>
|
8
|
-
<short_name>4</short_name>
|
9
|
-
<type>street_number</type>
|
10
|
-
</address_component>
|
11
|
-
<address_component>
|
12
|
-
<long_name>Penn Plaza</long_name>
|
13
|
-
<short_name>Penn Plaza</short_name>
|
14
|
-
<type>route</type>
|
15
|
-
</address_component>
|
16
|
-
<address_component>
|
17
|
-
<long_name>Manhattan</long_name>
|
18
|
-
<short_name>Manhattan</short_name>
|
19
|
-
<type>sublocality</type>
|
20
|
-
<type>political</type>
|
21
|
-
</address_component>
|
22
|
-
<address_component>
|
23
|
-
<long_name>New York</long_name>
|
24
|
-
<short_name>New York</short_name>
|
25
|
-
<type>locality</type>
|
26
|
-
<type>political</type>
|
27
|
-
</address_component>
|
28
|
-
<address_component>
|
29
|
-
<long_name>New York</long_name>
|
30
|
-
<short_name>New York</short_name>
|
31
|
-
<type>administrative_area_level_2</type>
|
32
|
-
<type>political</type>
|
33
|
-
</address_component>
|
34
|
-
<address_component>
|
35
|
-
<long_name>New York</long_name>
|
36
|
-
<short_name>NY</short_name>
|
37
|
-
<type>administrative_area_level_1</type>
|
38
|
-
<type>political</type>
|
39
|
-
</address_component>
|
40
|
-
<address_component>
|
41
|
-
<long_name>United States</long_name>
|
42
|
-
<short_name>US</short_name>
|
43
|
-
<type>country</type>
|
44
|
-
<type>political</type>
|
45
|
-
</address_component>
|
46
|
-
<address_component>
|
47
|
-
<long_name>10001</long_name>
|
48
|
-
<short_name>10001</short_name>
|
49
|
-
<type>postal_code</type>
|
50
|
-
</address_component>
|
51
|
-
<geometry>
|
52
|
-
<location>
|
53
|
-
<lat>40.7503540</lat>
|
54
|
-
<lng>-73.9933710</lng>
|
55
|
-
</location>
|
56
|
-
<location_type>ROOFTOP</location_type>
|
57
|
-
<viewport>
|
58
|
-
<southwest>
|
59
|
-
<lat>40.7473324</lat>
|
60
|
-
<lng>-73.9965316</lng>
|
61
|
-
</southwest>
|
62
|
-
<northeast>
|
63
|
-
<lat>40.7536276</lat>
|
64
|
-
<lng>-73.9902364</lng>
|
65
|
-
</northeast>
|
66
|
-
</viewport>
|
67
|
-
</geometry>
|
68
|
-
</result>
|
69
|
-
</GeocodeResponse>
|