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 CHANGED
@@ -2,3 +2,4 @@ pkg/*
2
2
  rdoc/*
3
3
  *.gem
4
4
  .bundle
5
+ Gemfile.lock
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 # MongoDB
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). The configuration options are:
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
- # geocoding service (see below for supported options):
233
- Geocoder::Configuration.lookup = :yahoo
240
+ # geocoding service (see below for supported options):
241
+ config.lookup = :yahoo
234
242
 
235
- # to use an API key:
236
- Geocoder::Configuration.api_key = "..."
243
+ # to use an API key:
244
+ config.api_key = "..."
237
245
 
238
- # geocoding service request timeout, in seconds (default 3):
239
- Geocoder::Configuration.timeout = 5
246
+ # geocoding service request timeout, in seconds (default 3):
247
+ config.timeout = 5
240
248
 
241
- # use HTTPS for geocoding service connections:
242
- Geocoder::Configuration.use_https = true
249
+ # set default units to kilometers:
250
+ config.units = :km
243
251
 
244
- # language to use (for search queries and reverse geocoding):
245
- Geocoder::Configuration.language = :de
252
+ # caching (see below for details):
253
+ config.cache = Redis.new
254
+ config.cache_prefix = "..."
246
255
 
247
- # use a proxy to access the service:
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
- # caching (see below for details)
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-11 Alex Reisner, released under the MIT license
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
  ##
@@ -10,14 +10,24 @@ module Geocoder
10
10
  # Read from the Cache.
11
11
  #
12
12
  def [](url)
13
- interpret store[key_for(url)]
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
- store[key_for(url)] = value
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 = :mi)
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 = :mi)
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> (default) or <tt>:km</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] ||= :mi
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> (default) or <tt>:spherical</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 the default as it
87
- # is less confusing (returns due east or west when given two points with
88
- # the same latitude)
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> (default) or <tt>:km</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] || :mi
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 = :mi)
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 = :mi)
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). Default is :mi.
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 = :mi)
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
- when Array; point
274
- when String; Geocoder.coordinates(point)
275
- else point.to_coordinates
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
- module Geocoder
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
- # name of geocoding service (symbol)
10
- [:lookup, :google],
3
+ module Geocoder
11
4
 
12
- # ISO-639 language code
13
- [:language, :en],
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
- # use HTTPS for lookup requests? (if supported)
16
- [:use_https, false],
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
- # HTTP proxy server (user:pass@host:port)
19
- [:http_proxy, nil],
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
- # HTTPS proxy server (user:pass@host:port)
22
- [:https_proxy, nil],
56
+ attr_accessor *OPTIONS
23
57
 
24
- # API key for geocoding service
25
- # for Google Premier use a 3-element array: [key, client, channel]
26
- [:api_key, nil],
58
+ def initialize # :nodoc
59
+ set_defaults
60
+ end
27
61
 
28
- # cache object (must respond to #[], #[]=, and #keys)
29
- [:cache, nil],
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
- # prefix (string) to use for all cache keys
32
- [:cache_prefix, "geocoder:"],
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
- # exceptions that should not be rescued by default
35
- # (if you want to implement custom error handling);
36
- # supports SocketError and TimeoutError
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
- # define getters and setters for all configuration settings
42
- self.options_and_defaults.each do |option, default|
43
- class_eval(<<-END, __FILE__, __LINE__ + 1)
44
-
45
- @@#{option} = default unless defined? @@#{option}
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
- def self.#{option}=(obj)
52
- @@#{option} = obj
53
- end
91
+ def #{o}=(value)
92
+ instance.#{o} = value
93
+ end
94
+ EOS
95
+ end.join("\n\n"))
54
96
 
55
- END
97
+ class << self
98
+ def set_defaults
99
+ instance.set_defaults
100
+ end
56
101
  end
57
102
  end
58
103
  end