geocoder 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of geocoder might be problematic. Click here for more details.
- data/.gitignore +1 -0
- data/CHANGELOG.rdoc +11 -0
- data/README.rdoc +24 -19
- data/lib/generators/geocoder/config/config_generator.rb +14 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +25 -0
- data/lib/geocoder.rb +4 -4
- data/lib/geocoder/cache.rb +12 -2
- data/lib/geocoder/calculations.rb +45 -17
- data/lib/geocoder/configuration.rb +87 -42
- data/lib/geocoder/lookups/base.rb +23 -20
- data/lib/geocoder/lookups/freegeoip.rb +4 -0
- data/lib/geocoder/lookups/geocoder_ca.rb +1 -0
- data/lib/geocoder/models/active_record.rb +7 -2
- data/lib/geocoder/models/base.rb +4 -2
- data/lib/geocoder/models/mongo_base.rb +13 -8
- data/lib/geocoder/models/mongo_mapper.rb +4 -2
- data/lib/geocoder/models/mongoid.rb +4 -2
- data/lib/geocoder/results/base.rb +2 -1
- data/lib/geocoder/results/nominatim.rb +1 -1
- data/lib/geocoder/stores/active_record.rb +57 -28
- data/lib/geocoder/stores/base.rb +6 -3
- data/lib/geocoder/stores/mongo_base.rb +3 -1
- data/lib/geocoder/version.rb +1 -1
- data/lib/tasks/geocoder.rake +14 -1
- data/test/calculations_test.rb +36 -1
- data/test/configuration_test.rb +90 -0
- data/test/custom_block_test.rb +1 -0
- data/test/input_handling_test.rb +2 -0
- data/test/lookup_test.rb +7 -0
- data/test/mongoid_test.rb +15 -8
- data/test/mongoid_test_helper.rb +11 -0
- data/test/test_helper.rb +2 -1
- metadata +5 -5
data/.gitignore
CHANGED
data/CHANGELOG.rdoc
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
Per-release changes to Geocoder.
|
4
4
|
|
5
|
+
== 1.1.2 (2012 May 24)
|
6
|
+
|
7
|
+
* Add ability to specify default units and distance calculation method (thanks github.com/abravalheri).
|
8
|
+
* Add new (optional) configuration syntax (thanks github.com/abravalheri).
|
9
|
+
* Add support for cache stores that provide :get and :set methods.
|
10
|
+
* Add support for custom HTTP request headers (thanks github.com/robotmay).
|
11
|
+
* Add Result#cache_hit attribute (thanks github.com/s01ipsist).
|
12
|
+
* Fix: rake geocode:all wasn't properly loading namespaced classes.
|
13
|
+
* Fix: properly recognize IP addresses with ::ffff: prefix (thanks github.com/brian-ewell).
|
14
|
+
* Fix: avoid exception during calculations when coordinates not known (thanks github.com/flori).
|
15
|
+
|
5
16
|
== 1.1.1 (2012 Feb 16)
|
6
17
|
|
7
18
|
* Add distance_from_sql class method to geocoded class (thanks github.com/dwilkie).
|
data/README.rdoc
CHANGED
@@ -83,6 +83,13 @@ Be sure to read <i>Latitude/Longitude Order</i> in the <i>Notes on MongoDB</i> s
|
|
83
83
|
|
84
84
|
MongoMapper is very similar to Mongoid, just be sure to include <tt>Geocoder::Model::MongoMapper</tt>.
|
85
85
|
|
86
|
+
=== Mongo Indices
|
87
|
+
|
88
|
+
By default, the methods <tt>geocoded_by</tt> and <tt>reverse_geocoded_by</tt> create a geospatial index. You can avoid index creation with the <tt>:skip_index option</tt>, for example:
|
89
|
+
|
90
|
+
include Geocoder::Model::Mongoid
|
91
|
+
geocoded_by :address, :skip_index => true
|
92
|
+
|
86
93
|
=== Bulk Geocoding
|
87
94
|
|
88
95
|
If you have just added geocoding to an existing application with a lot of objects you can use this Rake task to geocode them all:
|
@@ -191,7 +198,7 @@ If your model has +street+, +city+, +state+, and +country+ attributes you might
|
|
191
198
|
For reverse geocoding you can also specify an alternate name attribute where the address will be stored, for example:
|
192
199
|
|
193
200
|
reverse_geocoded_by :latitude, :longitude, :address => :location # ActiveRecord
|
194
|
-
reverse_geocoded_by :coordinates, :address => :loc
|
201
|
+
reverse_geocoded_by :coordinates, :address => :loc # MongoDB
|
195
202
|
|
196
203
|
|
197
204
|
== Advanced Geocoding
|
@@ -225,32 +232,30 @@ If you're familiar with the results returned by the geocoding service you're usi
|
|
225
232
|
|
226
233
|
== Geocoding Services
|
227
234
|
|
228
|
-
By default Geocoder uses Google's geocoding API to fetch coordinates and street addresses (FreeGeoIP is used for IP address info). However there are several other APIs supported, as well as a variety of settings. Please see the listing and comparison below for details on specific geocoding services (not all settings are supported by all services).
|
235
|
+
By default Geocoder uses Google's geocoding API to fetch coordinates and street addresses (FreeGeoIP is used for IP address info). However there are several other APIs supported, as well as a variety of settings. Please see the listing and comparison below for details on specific geocoding services (not all settings are supported by all services). Some common configuration options are:
|
229
236
|
|
230
237
|
# config/initializers/geocoder.rb
|
238
|
+
Geocoder.configure do |config|
|
231
239
|
|
232
|
-
|
233
|
-
|
240
|
+
# geocoding service (see below for supported options):
|
241
|
+
config.lookup = :yahoo
|
234
242
|
|
235
|
-
|
236
|
-
|
243
|
+
# to use an API key:
|
244
|
+
config.api_key = "..."
|
237
245
|
|
238
|
-
|
239
|
-
|
246
|
+
# geocoding service request timeout, in seconds (default 3):
|
247
|
+
config.timeout = 5
|
240
248
|
|
241
|
-
|
242
|
-
|
249
|
+
# set default units to kilometers:
|
250
|
+
config.units = :km
|
243
251
|
|
244
|
-
|
245
|
-
|
252
|
+
# caching (see below for details):
|
253
|
+
config.cache = Redis.new
|
254
|
+
config.cache_prefix = "..."
|
246
255
|
|
247
|
-
|
248
|
-
Geocoder::Configuration.http_proxy = "127.4.4.1"
|
249
|
-
Geocoder::Configuration.https_proxy = "127.4.4.2" # only if HTTPS is needed
|
256
|
+
end
|
250
257
|
|
251
|
-
|
252
|
-
Geocoder::Configuration.cache = Redis.new
|
253
|
-
Geocoder::Configuration.cache_prefix = "..."
|
258
|
+
Please see lib/geocoder/configuration.rb for a complete list of configuration options.
|
254
259
|
|
255
260
|
|
256
261
|
=== Listing and Comparison
|
@@ -491,4 +496,4 @@ You cannot use the +near+ scope with another scope that provides an +includes+ o
|
|
491
496
|
If anyone has a more elegant solution to this problem I am very interested in seeing it.
|
492
497
|
|
493
498
|
|
494
|
-
Copyright (c) 2009-
|
499
|
+
Copyright (c) 2009-12 Alex Reisner, released under the MIT license
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Geocoder
|
4
|
+
class ConfigGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path("../templates", __FILE__)
|
6
|
+
|
7
|
+
desc "This generator creates an initializer file at config/initializers, " +
|
8
|
+
"with the default configuration options for Geocoder."
|
9
|
+
def add_initializer
|
10
|
+
template "initializer.rb", "config/initializers/geocoder.rb"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Geocoder.configure do
|
2
|
+
## Configurable parameters: if you wish to change some configurable
|
3
|
+
## behaviour in Geocoder, feel free to uncomment the following lines
|
4
|
+
## and provide custom parameters.
|
5
|
+
|
6
|
+
# config.timeout = 3 # geocoding service timeout (secs)
|
7
|
+
# config.lookup = :google # name of geocoding service (symbol)
|
8
|
+
# config.language = :en # ISO-639 language code
|
9
|
+
# config.use_https = false # use HTTPS for lookup requests? (if supported)
|
10
|
+
# config.http_proxy = nil # HTTP proxy server (user:pass@host:port)
|
11
|
+
# config.https_proxy = nil # HTTPS proxy server (user:pass@host:port)
|
12
|
+
# config.api_key = nil # API key for geocoding service
|
13
|
+
# config.cache = nil # cache object (must respond to #[], #[]=, and #keys)
|
14
|
+
# config.cache_prefix = "geocoder:" # prefix (string) to use for all cache keys
|
15
|
+
|
16
|
+
## exceptions that should not be rescued by default
|
17
|
+
## (if you want to implement custom error handling);
|
18
|
+
## supports SocketError and TimeoutError
|
19
|
+
# config.always_raise = []
|
20
|
+
|
21
|
+
## Calculation options
|
22
|
+
# config.units = :mi # :km for kilometers or :mi for miles
|
23
|
+
# config.method = :linear # :spherical or :linear
|
24
|
+
end
|
25
|
+
|
data/lib/geocoder.rb
CHANGED
@@ -3,9 +3,9 @@ require "geocoder/calculations"
|
|
3
3
|
require "geocoder/exceptions"
|
4
4
|
require "geocoder/cache"
|
5
5
|
require "geocoder/request"
|
6
|
-
require "geocoder/models/active_record"
|
7
|
-
require "geocoder/models/mongoid"
|
8
|
-
require "geocoder/models/mongo_mapper"
|
6
|
+
require "geocoder/models/active_record" if defined?(::ActiveRecord)
|
7
|
+
require "geocoder/models/mongoid" if defined?(::Mongoid)
|
8
|
+
require "geocoder/models/mongo_mapper" if defined?(::MongoMapper)
|
9
9
|
|
10
10
|
module Geocoder
|
11
11
|
extend self
|
@@ -115,7 +115,7 @@ module Geocoder
|
|
115
115
|
# dot-delimited numbers.
|
116
116
|
#
|
117
117
|
def ip_address?(value)
|
118
|
-
!!value.to_s.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)
|
118
|
+
!!value.to_s.match(/^(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)
|
119
119
|
end
|
120
120
|
|
121
121
|
##
|
data/lib/geocoder/cache.rb
CHANGED
@@ -10,14 +10,24 @@ module Geocoder
|
|
10
10
|
# Read from the Cache.
|
11
11
|
#
|
12
12
|
def [](url)
|
13
|
-
interpret
|
13
|
+
interpret case
|
14
|
+
when store.respond_to?(:[])
|
15
|
+
store[key_for(url)]
|
16
|
+
when store.respond_to?(:get)
|
17
|
+
store.get key_for(url)
|
18
|
+
end
|
14
19
|
end
|
15
20
|
|
16
21
|
##
|
17
22
|
# Write to the Cache.
|
18
23
|
#
|
19
24
|
def []=(url, value)
|
20
|
-
|
25
|
+
case
|
26
|
+
when store.respond_to?(:[]=)
|
27
|
+
store[key_for(url)] = value
|
28
|
+
when store.respond_to?(:set)
|
29
|
+
store.set key_for(url), value
|
30
|
+
end
|
21
31
|
end
|
22
32
|
|
23
33
|
##
|
@@ -21,10 +21,14 @@ module Geocoder
|
|
21
21
|
#
|
22
22
|
KM_IN_MI = 0.621371192
|
23
23
|
|
24
|
+
# Not a number constant
|
25
|
+
NAN = defined?(::Float::NAN) ? ::Float::NAN : 0 / 0.0
|
26
|
+
|
24
27
|
##
|
25
28
|
# Distance spanned by one degree of latitude in the given units.
|
26
29
|
#
|
27
|
-
def latitude_degree_distance(units =
|
30
|
+
def latitude_degree_distance(units = nil)
|
31
|
+
units ||= Geocoder::Configuration.units
|
28
32
|
2 * Math::PI * earth_radius(units) / 360
|
29
33
|
end
|
30
34
|
|
@@ -32,7 +36,8 @@ module Geocoder
|
|
32
36
|
# Distance spanned by one degree of longitude at the given latitude.
|
33
37
|
# This ranges from around 69 miles at the equator to zero at the poles.
|
34
38
|
#
|
35
|
-
def longitude_degree_distance(latitude, units =
|
39
|
+
def longitude_degree_distance(latitude, units = nil)
|
40
|
+
units ||= Geocoder::Configuration.units
|
36
41
|
latitude_degree_distance(units) * Math.cos(to_radians(latitude))
|
37
42
|
end
|
38
43
|
|
@@ -49,12 +54,13 @@ module Geocoder
|
|
49
54
|
#
|
50
55
|
# The options hash supports:
|
51
56
|
#
|
52
|
-
# * <tt>:units</tt> - <tt>:mi</tt>
|
57
|
+
# * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>
|
58
|
+
# See Geocoder::Configuration to know how configure default units.
|
53
59
|
#
|
54
60
|
def distance_between(point1, point2, options = {})
|
55
61
|
|
56
62
|
# set default options
|
57
|
-
options[:units] ||=
|
63
|
+
options[:units] ||= Geocoder::Configuration.units
|
58
64
|
|
59
65
|
# convert to coordinate arrays
|
60
66
|
point1 = extract_coordinates(point1)
|
@@ -81,17 +87,18 @@ module Geocoder
|
|
81
87
|
# See Geocoder::Calculations.distance_between for
|
82
88
|
# ways of specifying the points. Also accepts an options hash:
|
83
89
|
#
|
84
|
-
# * <tt>:method</tt> - <tt>:linear</tt>
|
90
|
+
# * <tt>:method</tt> - <tt>:linear</tt> or <tt>:spherical</tt>;
|
85
91
|
# the spherical method is "correct" in that it returns the shortest path
|
86
|
-
# (one along a great circle) but the linear method is
|
87
|
-
#
|
88
|
-
#
|
92
|
+
# (one along a great circle) but the linear method is less confusing
|
93
|
+
# (returns due east or west when given two points with the same latitude).
|
94
|
+
# See Geocoder::Configuration to know how configure default method.
|
89
95
|
#
|
90
96
|
# Based on: http://www.movable-type.co.uk/scripts/latlong.html
|
91
97
|
#
|
92
98
|
def bearing_between(point1, point2, options = {})
|
93
99
|
|
94
100
|
# set default options
|
101
|
+
options[:method] ||= Geocoder::Configuration.distances
|
95
102
|
options[:method] = :linear unless options[:method] == :spherical
|
96
103
|
|
97
104
|
# convert to coordinate arrays
|
@@ -177,12 +184,13 @@ module Geocoder
|
|
177
184
|
# See Geocoder::Calculations.distance_between for
|
178
185
|
# ways of specifying the point. Also accepts an options hash:
|
179
186
|
#
|
180
|
-
# * <tt>:units</tt> - <tt>:mi</tt>
|
187
|
+
# * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>.
|
188
|
+
# See Geocoder::Configuration to know how configure default units.
|
181
189
|
#
|
182
190
|
def bounding_box(point, radius, options = {})
|
183
191
|
lat,lon = extract_coordinates(point)
|
184
192
|
radius = radius.to_f
|
185
|
-
units = options[:units] ||
|
193
|
+
units = options[:units] || Geocoder::Configuration.units
|
186
194
|
[
|
187
195
|
lat - (radius / latitude_degree_distance(units)),
|
188
196
|
lon - (radius / longitude_degree_distance(lat, units)),
|
@@ -219,11 +227,13 @@ module Geocoder
|
|
219
227
|
end
|
220
228
|
end
|
221
229
|
|
222
|
-
def distance_to_radians(distance, units =
|
230
|
+
def distance_to_radians(distance, units = nil)
|
231
|
+
units ||= Geocoder::Configuration.units
|
223
232
|
distance.to_f / earth_radius(units)
|
224
233
|
end
|
225
234
|
|
226
|
-
def radians_to_distance(radians, units =
|
235
|
+
def radians_to_distance(radians, units = nil)
|
236
|
+
units ||= Geocoder::Configuration.units
|
227
237
|
radians * earth_radius(units)
|
228
238
|
end
|
229
239
|
|
@@ -242,9 +252,11 @@ module Geocoder
|
|
242
252
|
end
|
243
253
|
|
244
254
|
##
|
245
|
-
# Radius of the Earth in the given units (:mi or :km).
|
255
|
+
# Radius of the Earth in the given units (:mi or :km).
|
256
|
+
# See Geocoder::Configuration to know how configure default units.
|
246
257
|
#
|
247
|
-
def earth_radius(units =
|
258
|
+
def earth_radius(units = nil)
|
259
|
+
units ||= Geocoder::Configuration.units
|
248
260
|
units == :km ? EARTH_RADIUS : to_miles(EARTH_RADIUS)
|
249
261
|
end
|
250
262
|
|
@@ -270,10 +282,26 @@ module Geocoder
|
|
270
282
|
#
|
271
283
|
def extract_coordinates(point)
|
272
284
|
case point
|
273
|
-
|
274
|
-
|
275
|
-
|
285
|
+
when Array
|
286
|
+
if point.size == 2
|
287
|
+
lat, lon = point
|
288
|
+
if !lat.nil? && lat.respond_to?(:to_f) and
|
289
|
+
!lon.nil? && lon.respond_to?(:to_f)
|
290
|
+
then
|
291
|
+
return [ lat.to_f, lon.to_f ]
|
292
|
+
end
|
293
|
+
end
|
294
|
+
when String
|
295
|
+
point = Geocoder.coordinates(point) and return point
|
296
|
+
else
|
297
|
+
if point.respond_to?(:to_coordinates)
|
298
|
+
if Array === array = point.to_coordinates
|
299
|
+
return extract_coordinates(array)
|
300
|
+
end
|
301
|
+
end
|
276
302
|
end
|
303
|
+
[ NAN, NAN ]
|
277
304
|
end
|
278
305
|
end
|
279
306
|
end
|
307
|
+
|
@@ -1,58 +1,103 @@
|
|
1
|
-
|
2
|
-
class Configuration
|
3
|
-
|
4
|
-
def self.options_and_defaults
|
5
|
-
[
|
6
|
-
# geocoding service timeout (secs)
|
7
|
-
[:timeout, 3],
|
1
|
+
require 'singleton'
|
8
2
|
|
9
|
-
|
10
|
-
[:lookup, :google],
|
3
|
+
module Geocoder
|
11
4
|
|
12
|
-
|
13
|
-
|
5
|
+
##
|
6
|
+
# Provides convenient access to the Configuration singleton.
|
7
|
+
#
|
8
|
+
def self.configure(&block)
|
9
|
+
if block_given?
|
10
|
+
block.call(Configuration.instance)
|
11
|
+
else
|
12
|
+
Configuration.instance
|
13
|
+
end
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
##
|
17
|
+
# This class handles geocoder Geocoder configuration
|
18
|
+
# (geocoding service provider, caching, units of measurement, etc).
|
19
|
+
# Configuration can be done in two ways:
|
20
|
+
#
|
21
|
+
# 1) Using Geocoder.configure and passing a block
|
22
|
+
# (useful for configuring multiple things at once):
|
23
|
+
#
|
24
|
+
# Geocoder.configure do |config|
|
25
|
+
# config.timeout = 5
|
26
|
+
# config.lookup = :yahoo
|
27
|
+
# config.api_key = "2a9fsa983jaslfj982fjasd"
|
28
|
+
# config.units = :km
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# 2) Using the Geocoder::Configuration singleton directly:
|
32
|
+
#
|
33
|
+
# Geocoder::Configuration.language = 'pt-BR'
|
34
|
+
#
|
35
|
+
# Default values are defined in Configuration#set_defaults.
|
36
|
+
#
|
37
|
+
class Configuration
|
38
|
+
include Singleton
|
17
39
|
|
18
|
-
|
19
|
-
|
40
|
+
OPTIONS = [
|
41
|
+
:timeout,
|
42
|
+
:lookup,
|
43
|
+
:language,
|
44
|
+
:http_headers,
|
45
|
+
:use_https,
|
46
|
+
:http_proxy,
|
47
|
+
:https_proxy,
|
48
|
+
:api_key,
|
49
|
+
:cache,
|
50
|
+
:cache_prefix,
|
51
|
+
:always_raise,
|
52
|
+
:units,
|
53
|
+
:distances
|
54
|
+
]
|
20
55
|
|
21
|
-
|
22
|
-
[:https_proxy, nil],
|
56
|
+
attr_accessor *OPTIONS
|
23
57
|
|
24
|
-
|
25
|
-
|
26
|
-
|
58
|
+
def initialize # :nodoc
|
59
|
+
set_defaults
|
60
|
+
end
|
27
61
|
|
28
|
-
|
29
|
-
|
62
|
+
def set_defaults
|
63
|
+
@timeout = 3 # geocoding service timeout (secs)
|
64
|
+
@lookup = :google # name of geocoding service (symbol)
|
65
|
+
@language = :en # ISO-639 language code
|
66
|
+
@http_headers = {} # HTTP headers for lookup
|
67
|
+
@use_https = false # use HTTPS for lookup requests? (if supported)
|
68
|
+
@http_proxy = nil # HTTP proxy server (user:pass@host:port)
|
69
|
+
@https_proxy = nil # HTTPS proxy server (user:pass@host:port)
|
70
|
+
@api_key = nil # API key for geocoding service
|
71
|
+
@cache = nil # cache object (must respond to #[], #[]=, and #keys)
|
72
|
+
@cache_prefix = "geocoder:" # prefix (string) to use for all cache keys
|
30
73
|
|
31
|
-
|
32
|
-
|
74
|
+
# exceptions that should not be rescued by default
|
75
|
+
# (if you want to implement custom error handling);
|
76
|
+
# supports SocketError and TimeoutError
|
77
|
+
@always_raise = []
|
33
78
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
[:always_raise, []]
|
38
|
-
]
|
79
|
+
# calculation options
|
80
|
+
@units = :mi # :mi or :km
|
81
|
+
@distances = :linear # :linear or :spherical
|
39
82
|
end
|
40
83
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
def self.#{option}
|
48
|
-
@@#{option}
|
49
|
-
end
|
84
|
+
instance_eval(OPTIONS.map do |option|
|
85
|
+
o = option.to_s
|
86
|
+
<<-EOS
|
87
|
+
def #{o}
|
88
|
+
instance.#{o}
|
89
|
+
end
|
50
90
|
|
51
|
-
|
52
|
-
|
53
|
-
|
91
|
+
def #{o}=(value)
|
92
|
+
instance.#{o} = value
|
93
|
+
end
|
94
|
+
EOS
|
95
|
+
end.join("\n\n"))
|
54
96
|
|
55
|
-
|
97
|
+
class << self
|
98
|
+
def set_defaults
|
99
|
+
instance.set_defaults
|
100
|
+
end
|
56
101
|
end
|
57
102
|
end
|
58
103
|
end
|