acts_as_geocodable 2.0.3 → 2.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.
@@ -1,7 +1,10 @@
1
- require 'graticule'
2
- require 'acts_as_geocodable/geocoding'
3
- require 'acts_as_geocodable/geocode'
4
- require 'acts_as_geocodable/remote_location'
1
+ require "active_record"
2
+ require "active_support"
3
+ require "graticule"
4
+
5
+ require "acts_as_geocodable/geocoding"
6
+ require "acts_as_geocodable/geocode"
7
+ require "acts_as_geocodable/remote_location"
5
8
 
6
9
  module ActiveSupport::Callbacks::ClassMethods
7
10
  def without_callback(*args, &block)
@@ -11,7 +14,7 @@ module ActiveSupport::Callbacks::ClassMethods
11
14
  end
12
15
  end
13
16
 
14
- module ActsAsGeocodable #:nodoc:
17
+ module ActsAsGeocodable
15
18
  # Make a model geocodable.
16
19
  #
17
20
  # class Event < ActiveRecord::Base
@@ -29,25 +32,24 @@ module ActsAsGeocodable #:nodoc:
29
32
  #
30
33
  def acts_as_geocodable(options = {})
31
34
  options = {
32
- :address => {
33
- :street => :street, :locality => :locality, :region => :region,
34
- :postal_code => :postal_code, :country => :country},
35
- :normalize_address => false,
36
- :distance_column => 'distance',
37
- :units => :miles
35
+ address: {
36
+ street: :street, locality: :locality, region: :region,
37
+ postal_code: :postal_code, country: :country},
38
+ normalize_address: false,
39
+ distance_column: "distance",
40
+ units: :miles
38
41
  }.merge(options)
39
42
 
40
- if ActiveRecord::VERSION::MAJOR >= 3
41
- class_attribute :acts_as_geocodable_options
42
- self.acts_as_geocodable_options = options
43
- else
44
- write_inheritable_attribute :acts_as_geocodable_options, options
45
- class_inheritable_reader :acts_as_geocodable_options
46
- end
43
+ class_attribute :acts_as_geocodable_options
44
+ self.acts_as_geocodable_options = options
47
45
 
48
46
  define_callbacks :geocoding
49
47
 
50
- has_one :geocoding, :as => :geocodable, :include => :geocode, :dependent => :destroy
48
+ if ActiveRecord::VERSION::MAJOR >= 4
49
+ has_one :geocoding, -> { includes :geocode }, as: :geocodable, dependent: :destroy
50
+ else
51
+ has_one :geocoding, as: :geocodable, include: :geocode, dependent: :destroy
52
+ end
51
53
 
52
54
  after_save :attach_geocode
53
55
 
@@ -63,7 +65,7 @@ module ActsAsGeocodable #:nodoc:
63
65
 
64
66
  # Use ActiveRecord ARel style syntax for finding records.
65
67
  #
66
- # Model.origin("Chicago, IL", :within => 10)
68
+ # Model.origin("Chicago, IL", within: 10)
67
69
  #
68
70
  # a +distance+ attribute indicating the distance
69
71
  # to the origin is added to each of the results:
@@ -80,34 +82,35 @@ module ActsAsGeocodable #:nodoc:
80
82
  # Default is <tt>:miles</tt> unless specified otherwise in the +acts_as_geocodable+
81
83
  # declaration.
82
84
  #
83
- scope :origin, lambda {|*args|
85
+ scope :origin, lambda { |*args|
84
86
  origin = location_to_geocode(args[0])
85
87
  options = {
86
- :units => acts_as_geocodable_options[:units],
88
+ units: acts_as_geocodable_options[:units],
87
89
  }.merge(args[1] || {})
88
90
  distance_sql = sql_for_distance(origin, options[:units])
89
91
 
90
92
  scope = with_geocode_fields.select("#{table_name}.*, #{distance_sql} AS
91
93
  #{acts_as_geocodable_options[:distance_column]}")
92
94
 
93
- scope = scope.where("#{distance_sql} > #{options[:beyond]}") if options[:beyond]
95
+ scope = scope.where("#{distance_sql} > #{options[:beyond]}") if options[:beyond]
94
96
  if options[:within]
95
- scope = scope.where("(geocodes.latitude = :lat AND geocodes.longitude = :long) OR (#{distance_sql} <= #{options[:within]})", {:lat => origin.latitude, :long => origin.longitude})
97
+ scope = scope.where("(geocodes.latitude = :lat AND geocodes.longitude = :long) OR (#{distance_sql} <= #{options[:within]})", { lat: origin.latitude, long: origin.longitude })
96
98
  end
97
99
  scope
98
100
  }
99
101
 
100
- scope :near, order("#{acts_as_geocodable_options[:distance_column]} ASC")
101
- scope :far, order("#{acts_as_geocodable_options[:distance_column]} DESC")
102
+ scope :near, -> { order("#{acts_as_geocodable_options[:distance_column]} ASC") }
103
+ scope :far, -> { order("#{acts_as_geocodable_options[:distance_column]} DESC") }
102
104
 
103
105
  include ActsAsGeocodable::Model
104
106
  end
105
107
 
106
108
  module Model
107
- extend ActiveSupport::Concern
109
+ def self.included(base)
110
+ base.extend(ClassMethods)
111
+ end
108
112
 
109
113
  module ClassMethods
110
-
111
114
  # Find the nearest location to the given origin
112
115
  #
113
116
  # Model.origin("Grand Rapids, MI").nearest
@@ -128,7 +131,7 @@ module ActsAsGeocodable #:nodoc:
128
131
  def location_to_geocode(location)
129
132
  case location
130
133
  when Geocode then location
131
- when InstanceMethods then location.geocode
134
+ when ActsAsGeocodable::Model then location.geocode
132
135
  when String, Fixnum then Geocode.find_or_create_by_query(location.to_s)
133
136
  end
134
137
  end
@@ -149,120 +152,116 @@ module ActsAsGeocodable #:nodoc:
149
152
  # end
150
153
  #
151
154
  def validates_as_geocodable(options = {})
152
- options = options.reverse_merge :message => "Address could not be geocoded.", :allow_nil => false
155
+ options = options.reverse_merge message: "Address could not be geocoded.", allow_nil: false
153
156
  validate do |model|
154
157
  is_blank = model.to_location.attributes.except(:precision).all?(&:blank?)
155
158
  unless options[:allow_nil] && is_blank
156
- geocode = model.send :attach_geocode
159
+ geocode = model.send(:attach_geocode)
157
160
  if !geocode ||
158
161
  (options[:precision] && geocode.precision < options[:precision]) ||
159
162
  (block_given? && yield(geocode) == false)
160
- model.errors.add :base, options[:message]
163
+ model.errors.add(:base, options[:message])
161
164
  end
162
165
  end
163
166
  end
164
167
  end
165
168
 
166
- private
169
+ private
167
170
 
168
171
  def sql_for_distance(origin, units = acts_as_geocodable_options[:units])
169
172
  Graticule::Distance::Spherical.to_sql(
170
- :latitude => origin.latitude,
171
- :longitude => origin.longitude,
172
- :latitude_column => "geocodes.latitude",
173
- :longitude_column => "geocodes.longitude",
174
- :units => units
173
+ latitude: origin.latitude,
174
+ longitude: origin.longitude,
175
+ latitude_column: "geocodes.latitude",
176
+ longitude_column: "geocodes.longitude",
177
+ units: units
175
178
  )
176
179
  end
177
180
  end
178
181
 
179
- module InstanceMethods
180
-
181
- # Get the geocode for this model
182
- def geocode
183
- geocoding.geocode if geocoding
184
- end
182
+ # Get the geocode for this model
183
+ def geocode
184
+ geocoding.geocode if geocoding
185
+ end
185
186
 
186
- # Create a Graticule::Location
187
- def to_location
188
- Graticule::Location.new.tap do |location|
189
- [:street, :locality, :region, :postal_code, :country].each do |attr|
190
- location.send "#{attr}=", geo_attribute(attr)
191
- end
187
+ # Create a Graticule::Location
188
+ def to_location
189
+ Graticule::Location.new.tap do |location|
190
+ [:street, :locality, :region, :postal_code, :country].each do |attr|
191
+ location.send("#{attr}=", geo_attribute(attr))
192
192
  end
193
193
  end
194
+ end
194
195
 
195
- # Get the distance to the given destination. The destination can be an
196
- # acts_as_geocodable model, a Geocode, or a string
197
- #
198
- # myhome.distance_to "Chicago, IL"
199
- # myhome.distance_to "49423"
200
- # myhome.distance_to other_model
201
- #
202
- # == Options
203
- # * <tt>:units</tt>: <tt>:miles</tt> or <tt>:kilometers</tt>
204
- # * <tt>:formula</tt>: The formula to use to calculate the distance. This can
205
- # be any formula supported by Graticule. The default is <tt>:haversine</tt>.
206
- #
207
- def distance_to(destination, options = {})
208
- units = options[:units] || acts_as_geocodable_options[:units]
209
- formula = options[:formula] || :haversine
196
+ # Get the distance to the given destination. The destination can be an
197
+ # acts_as_geocodable model, a Geocode, or a string
198
+ #
199
+ # myhome.distance_to "Chicago, IL"
200
+ # myhome.distance_to "49423"
201
+ # myhome.distance_to other_model
202
+ #
203
+ # == Options
204
+ # * <tt>:units</tt>: <tt>:miles</tt> or <tt>:kilometers</tt>
205
+ # * <tt>:formula</tt>: The formula to use to calculate the distance. This can
206
+ # be any formula supported by Graticule. The default is <tt>:haversine</tt>.
207
+ #
208
+ def distance_to(destination, options = {})
209
+ units = options[:units] || acts_as_geocodable_options[:units]
210
+ formula = options[:formula] || :haversine
210
211
 
211
- geocode = self.class.location_to_geocode(destination)
212
- self.geocode.distance_to(geocode, units, formula)
213
- end
212
+ geocode = self.class.location_to_geocode(destination)
213
+ self.geocode.distance_to(geocode, units, formula)
214
+ end
214
215
 
215
216
  protected
216
217
 
217
- # Perform the geocoding
218
- def attach_geocode
219
- new_geocode = Geocode.find_or_create_by_location self.to_location unless self.to_location.blank?
220
- if new_geocode && self.geocode != new_geocode
221
- run_callbacks :geocoding do
222
- self.geocoding = Geocoding.new :geocode => new_geocode
223
- self.update_address self.acts_as_geocodable_options[:normalize_address]
224
- end
225
- elsif !new_geocode && self.geocoding
226
- self.geocoding.destroy
218
+ # Perform the geocoding
219
+ def attach_geocode
220
+ new_geocode = Geocode.find_or_create_by_location(self.to_location) unless self.to_location.blank?
221
+ if new_geocode && self.geocode != new_geocode
222
+ run_callbacks :geocoding do
223
+ self.geocoding = Geocoding.new(geocode: new_geocode)
224
+ self.update_address self.acts_as_geocodable_options[:normalize_address]
227
225
  end
228
- new_geocode
229
- rescue Graticule::Error => e
230
- logger.warn e.message
226
+ elsif !new_geocode && self.geocoding
227
+ self.geocoding.destroy
231
228
  end
229
+ new_geocode
230
+ rescue Graticule::Error => error
231
+ logger.warn error.message
232
+ end
232
233
 
233
-
234
- def update_address(force = false) #:nodoc:
235
- unless self.geocode.blank?
236
- if self.acts_as_geocodable_options[:address].is_a? Symbol
237
- method = self.acts_as_geocodable_options[:address]
234
+ def update_address(force = false)
235
+ unless self.geocode.blank?
236
+ if self.acts_as_geocodable_options[:address].is_a? Symbol
237
+ method = self.acts_as_geocodable_options[:address]
238
+ if self.respond_to?("#{method}=") && (self.send(method).blank? || force)
239
+ self.send("#{method}=", self.geocode.to_location.to_s)
240
+ end
241
+ else
242
+ self.acts_as_geocodable_options[:address].each do |attribute,method|
238
243
  if self.respond_to?("#{method}=") && (self.send(method).blank? || force)
239
- self.send "#{method}=", self.geocode.to_location.to_s
240
- end
241
- else
242
- self.acts_as_geocodable_options[:address].each do |attribute,method|
243
- if self.respond_to?("#{method}=") && (self.send(method).blank? || force)
244
- self.send "#{method}=", self.geocode.send(attribute)
245
- end
244
+ self.send("#{method}=", self.geocode.send(attribute))
246
245
  end
247
246
  end
247
+ end
248
248
 
249
- self.class.without_callback(:save, :after, :attach_geocode) do
250
- save
251
- end
249
+ self.class.without_callback(:save, :after, :attach_geocode) do
250
+ save
252
251
  end
253
252
  end
253
+ end
254
254
 
255
- def geo_attribute(attr_key) #:nodoc:
256
- if self.acts_as_geocodable_options[:address].is_a? Symbol
257
- attr_name = self.acts_as_geocodable_options[:address]
258
- attr_key == :street ? self.send(attr_name) : nil
259
- else
260
- attr_name = self.acts_as_geocodable_options[:address][attr_key]
261
- attr_name && self.respond_to?(attr_name) ? self.send(attr_name) : nil
262
- end
255
+ def geo_attribute(attr_key)
256
+ if self.acts_as_geocodable_options[:address].is_a? Symbol
257
+ attr_name = self.acts_as_geocodable_options[:address]
258
+ attr_key == :street ? self.send(attr_name) : nil
259
+ else
260
+ attr_name = self.acts_as_geocodable_options[:address][attr_key]
261
+ attr_name && self.respond_to?(attr_name) ? self.send(attr_name) : nil
263
262
  end
264
263
  end
265
264
  end
266
265
  end
267
266
 
268
- ActiveRecord::Base.send :extend, ActsAsGeocodable
267
+ ActiveRecord::Base.send(:extend, ActsAsGeocodable)
@@ -1,5 +1,5 @@
1
1
  class Geocode < ActiveRecord::Base
2
- has_many :geocodings, :dependent => :destroy
2
+ has_many :geocodings, dependent: :destroy
3
3
 
4
4
  validates_uniqueness_of :query
5
5
 
@@ -20,7 +20,7 @@ class Geocode < ActiveRecord::Base
20
20
  end
21
21
 
22
22
  def self.create_by_query(query)
23
- create geocoder.locate(query).attributes.merge(:query => query)
23
+ create geocoder.locate(query).attributes.merge(query: query)
24
24
  end
25
25
 
26
26
  def self.find_or_create_by_location(location)
@@ -28,9 +28,9 @@ class Geocode < ActiveRecord::Base
28
28
  end
29
29
 
30
30
  def self.create_from_location(location)
31
- create geocoder.locate(location).attributes.merge(:query => location.to_s)
32
- rescue Graticule::Error => e
33
- logger.warn e.message
31
+ create geocoder.locate(location).attributes.merge(query: location.to_s)
32
+ rescue Graticule::Error => error
33
+ logger.warn error.message
34
34
  nil
35
35
  end
36
36
 
@@ -47,7 +47,7 @@ class Geocode < ActiveRecord::Base
47
47
  end
48
48
 
49
49
  def on(geocodable)
50
- geocodings.create :geocodable => geocodable
50
+ geocodings.create(geocodable: geocodable)
51
51
  end
52
52
 
53
53
  def coordinates
@@ -60,6 +60,6 @@ class Geocode < ActiveRecord::Base
60
60
 
61
61
  # Create a Graticule::Location
62
62
  def to_location
63
- Graticule::Location.new(attributes.except('id', 'query'))
63
+ Graticule::Location.new(attributes.except("id", "query"))
64
64
  end
65
- end
65
+ end
@@ -1,12 +1,12 @@
1
1
  class Geocoding < ActiveRecord::Base
2
2
  belongs_to :geocode
3
- belongs_to :geocodable, :polymorphic => true
3
+ belongs_to :geocodable, polymorphic: true
4
4
 
5
5
  def self.geocoded_class(geocodable)
6
6
  ActiveRecord::Base.send(:class_name_of_active_record_descendant, geocodable.class).to_s
7
7
  end
8
-
8
+
9
9
  def self.find_geocodable(geocoded_class, geocoded_id)
10
10
  geocoded_class.constantize.find(geocoded_id)
11
11
  end
12
- end
12
+ end
@@ -1,20 +1,20 @@
1
- module ActsAsGeocodable #:nodoc:
2
- module RemoteLocation #:nodoc:
1
+ require "action_controller"
3
2
 
3
+ module ActsAsGeocodable
4
+ module RemoteLocation
4
5
  # Get the remote location of the request IP using http://hostip.info
5
6
  def remote_location
6
- if request.remote_ip == '127.0.0.1'
7
+ if request.remote_ip == "127.0.0.1"
7
8
  # otherwise people would complain that it doesn't work
8
- Graticule::Location.new(:locality => 'localhost')
9
+ Graticule::Location.new(locality: "localhost")
9
10
  else
10
11
  Graticule.service(:host_ip).new.locate(request.remote_ip)
11
12
  end
12
- rescue Graticule::Error => e
13
- logger.warn "An error occurred while looking up the location of '#{request.remote_ip}': #{e.message}"
13
+ rescue Graticule::Error => error
14
+ logger.warn "An error occurred while looking up the location of '#{request.remote_ip}': #{error.message}"
14
15
  nil
15
16
  end
16
-
17
17
  end
18
18
  end
19
19
 
20
- ActionController::Base.send :include, ActsAsGeocodable::RemoteLocation
20
+ ActionController::Base.send(:include, ActsAsGeocodable::RemoteLocation)
@@ -1,3 +1,3 @@
1
1
  module ActsAsGeocodable
2
- VERSION = '2.0.3' unless defined?(::ActsAsGeocodable::VERSION)
2
+ VERSION = "2.1.0" unless defined?(::ActsAsGeocodable::VERSION)
3
3
  end
@@ -9,4 +9,4 @@ Example:
9
9
  rails generate acts_as_geocodable
10
10
 
11
11
  With 4 existing migrations, this will create an AddGeocodableTables migration in the
12
- file db/migrate/5_add_geocodable_tables.rb
12
+ file db/migrate/5_add_geocodable_tables.rb
@@ -1,16 +1,16 @@
1
- require 'rails/generators'
2
- require 'rails/generators/migration'
1
+ require "rails/generators"
2
+ require "rails/generators/migration"
3
3
 
4
4
  class ActsAsGeocodableGenerator < Rails::Generators::Base
5
5
  include Rails::Generators::Migration
6
6
 
7
7
  def self.source_root
8
- @source_root ||= File.join(File.dirname(__FILE__), 'templates')
8
+ @source_root ||= File.join(File.dirname(__FILE__), "templates")
9
9
  end
10
10
 
11
11
  # Implement the required interface for Rails::Generators::Migration.
12
12
  #
13
- def self.next_migration_number(dirname) #:nodoc:
13
+ def self.next_migration_number(dirname)
14
14
  next_migration_number = current_migration_number(dirname) + 1
15
15
  if ActiveRecord::Base.timestamped_migrations
16
16
  [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
@@ -21,8 +21,7 @@ class ActsAsGeocodableGenerator < Rails::Generators::Base
21
21
 
22
22
  def create_migration_file
23
23
  if defined?(ActiveRecord)
24
- migration_template 'migration.rb', 'db/migrate/add_geocodable_tables.rb'
24
+ migration_template "migration.rb", "db/migrate/add_geocodable_tables.rb"
25
25
  end
26
26
  end
27
-
28
27
  end