geokit-rails3 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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