geokit-rails3 0.0.5 → 0.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.
@@ -48,38 +48,6 @@ module Geokit
48
48
  # set the actual callback here
49
49
  before_validation :auto_geocode_address, :on => :create
50
50
  end
51
-
52
- scope :select_with_distance, lambda { |origin, units, formula|
53
- distance_formula = distance_sql(origin, units, formula)
54
-
55
- select('*').
56
- select("#{distance_formula} AS #{distance_column_name}")
57
- }
58
-
59
- scope :within, lambda { |options|
60
- origin = extract_origin_from_options(options)
61
- units = extract_units_from_options(options)
62
- formula = extract_formula_from_options(options)
63
-
64
- distance_formula = distance_sql(origin, units, formula)
65
-
66
- within = options.delete(:within)
67
-
68
- select_with_distance(origin, units, formula).
69
- where("#{distance_formula} < #{within}")
70
- }
71
-
72
- scope :closest, lambda { |options|
73
- origin = extract_origin_from_options(options)
74
- units = extract_units_from_options(options)
75
- formula = extract_formula_from_options(options)
76
-
77
- distance_formula = distance_sql(origin, units, formula)
78
-
79
- select_with_distance(origin, units, formula).
80
- order("#{distance_formula} ASC").
81
- limit(1)
82
- }
83
51
  end
84
52
  end
85
53
  end
@@ -106,6 +74,68 @@ module Geokit
106
74
  end
107
75
  end
108
76
 
77
+ def within(distance, options = {})
78
+ options[:within] = distance
79
+ geo_scope(options)
80
+ end
81
+ alias inside within
82
+
83
+ def beyond(distance, options = {})
84
+ options[:beyond] = distance
85
+ geo_scope(options)
86
+ end
87
+ alias outside beyond
88
+
89
+ def in_range(range, options = {})
90
+ options[:range] = range
91
+ geo_scope(options)
92
+ end
93
+
94
+ def in_bounds(bounds, options = {})
95
+ options[:bounds] = bounds
96
+ geo_scope(options)
97
+ end
98
+
99
+ def closest(options = {})
100
+ geo_scope(options).order("#{distance_column_name} asc").limit(1)
101
+ end
102
+ alias nearest closest
103
+
104
+ def farthest(options = {})
105
+ geo_scope(options).order("#{distance_column_name} desc").limit(1)
106
+ end
107
+
108
+ def geo_scope(options = {})
109
+ arel = self.is_a?(ActiveRecord::Relation) ? self : self.scoped
110
+
111
+ origin = extract_origin_from_options(options)
112
+ units = extract_units_from_options(options)
113
+ formula = extract_formula_from_options(options)
114
+ bounds = extract_bounds_from_options(options)
115
+
116
+ if origin || bounds
117
+ bounds = formulate_bounds_from_distance(options, origin, units) unless bounds
118
+
119
+ if origin
120
+ distance_formula = distance_sql(origin, units, formula)
121
+ arel = arel.select('*') if arel.select_values.blank?
122
+ arel = arel.select("#{distance_formula} AS #{distance_column_name}")
123
+ end
124
+
125
+ if bounds
126
+ bound_conditions = bound_conditions(bounds)
127
+ arel = arel.where(bound_conditions) if bound_conditions
128
+ end
129
+
130
+ distance_conditions = distance_conditions(options)
131
+ arel = arel.where(distance_conditions) if distance_conditions
132
+
133
+ arel = substitute_distance_in_where_values(arel, origin, units, formula)
134
+ end
135
+
136
+ arel
137
+ end
138
+
109
139
  # Returns the distance calculation to be used as a display column or a condition. This
110
140
  # is provide for anyone wanting access to the raw SQL.
111
141
  def distance_sql(origin, units=default_units, formula=default_formula)
@@ -131,30 +161,21 @@ module Geokit
131
161
  nil
132
162
  end
133
163
  end
134
-
135
- # Replace :within, :beyond and :range distance tokens with the appropriate distance
136
- # where clauses. Removes these tokens from the options hash.
137
- def apply_distance_scope(options)
138
- distance_condition = if options.has_key?(:within)
164
+
165
+ def distance_conditions(options)
166
+ if options.has_key?(:within)
139
167
  "#{distance_column_name} <= #{options[:within]}"
140
168
  elsif options.has_key?(:beyond)
141
169
  "#{distance_column_name} > #{options[:beyond]}"
142
170
  elsif options.has_key?(:range)
143
171
  "#{distance_column_name} >= #{options[:range].first} AND #{distance_column_name} <#{'=' unless options[:range].exclude_end?} #{options[:range].last}"
144
172
  end
145
-
146
- if distance_condition
147
- [:within, :beyond, :range].each { |option| options.delete(option) }
148
- options[:conditions] = merge_conditions(options[:conditions], distance_condition)
149
- end
150
173
  end
151
-
152
- # Alters the conditions to include rectangular bounds conditions.
153
- def apply_bounds_conditions(options,bounds)
174
+
175
+ def bound_conditions(bounds)
154
176
  sw,ne = bounds.sw, bounds.ne
155
177
  lng_sql = bounds.crosses_meridian? ? "(#{qualified_lng_column_name}<#{ne.lng} OR #{qualified_lng_column_name}>#{sw.lng})" : "#{qualified_lng_column_name}>#{sw.lng} AND #{qualified_lng_column_name}<#{ne.lng}"
156
- bounds_sql = "#{qualified_lat_column_name}>#{sw.lat} AND #{qualified_lat_column_name}<#{ne.lat} AND #{lng_sql}"
157
- options[:conditions] = merge_conditions(options[:conditions], bounds_sql)
178
+ "#{qualified_lat_column_name}>#{sw.lat} AND #{qualified_lat_column_name}<#{ne.lat} AND #{lng_sql}"
158
179
  end
159
180
 
160
181
  # Extracts the origin instance out of the options if it exists and returns
@@ -207,23 +228,21 @@ module Geokit
207
228
  res
208
229
  end
209
230
 
210
- # Augments the select with the distance SQL.
211
- def add_distance_to_select(options, origin, units=default_units, formula=default_formula)
212
- if origin
213
- distance_selector = distance_sql(origin, units, formula) + " AS #{distance_column_name}"
214
- selector = options.has_key?(:select) && options[:select] ? options[:select] : "*"
215
- options[:select] = "#{selector}, #{distance_selector}"
216
- end
217
- end
218
-
219
231
  # Looks for the distance column and replaces it with the distance sql. If an origin was not
220
232
  # passed in and the distance column exists, we leave it to be flagged as bad SQL by the database.
221
233
  # Conditions are either a string or an array. In the case of an array, the first entry contains
222
234
  # the condition.
223
- def substitute_distance_in_conditions(options, origin, units=default_units, formula=default_formula)
224
- condition = options[:conditions].is_a?(String) ? options[:conditions] : options[:conditions].first
235
+ def substitute_distance_in_where_values(arel, origin, units=default_units, formula=default_formula)
225
236
  pattern = Regexp.new("\\b#{distance_column_name}\\b")
226
- condition.gsub!(pattern, distance_sql(origin, units, formula))
237
+ value = distance_sql(origin, units, formula)
238
+ arel.where_values.map! do |where_value|
239
+ if where_value.is_a?(String)
240
+ where_value.gsub(pattern, value)
241
+ else
242
+ where_value
243
+ end
244
+ end
245
+ arel
227
246
  end
228
247
 
229
248
  # Returns the distance SQL using the spherical world formula (Haversine). The SQL is tuned
@@ -1,3 +1,3 @@
1
1
  module GeokitRails3
2
- VERSION = "0.0.5"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geokit-rails3
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
+ - 1
8
9
  - 0
9
- - 5
10
- version: 0.0.5
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andre Lewis
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2010-10-12 00:00:00 +02:00
20
+ date: 2010-10-14 00:00:00 +02:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency