rails-geocoder 0.9.4 → 0.9.5
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.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>
|