geokit-ar 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ module Geokit
2
+ module Adapters
3
+ class SQLServer < Abstract
4
+
5
+ class << self
6
+
7
+ def load(klass)
8
+ klass.connection.execute <<-EOS
9
+ if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[geokit_least]') and xtype in (N'FN', N'IF', N'TF'))
10
+ drop function [dbo].[geokit_least]
11
+ EOS
12
+
13
+ klass.connection.execute <<-EOS
14
+ CREATE FUNCTION [dbo].geokit_least (@value1 float,@value2 float) RETURNS float AS BEGIN
15
+ return (SELECT CASE WHEN @value1 < @value2 THEN @value1 ELSE @value2 END) END
16
+ EOS
17
+ self.loaded = true
18
+ end
19
+
20
+ end
21
+
22
+ def initialize(*args)
23
+ super(*args)
24
+ end
25
+
26
+ def sphere_distance_sql(lat, lng, multiplier)
27
+ %|
28
+ (ACOS([dbo].geokit_least(1,COS(#{lat})*COS(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*COS(RADIANS(#{qualified_lng_column_name}))+
29
+ COS(#{lat})*SIN(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*SIN(RADIANS(#{qualified_lng_column_name}))+
30
+ SIN(#{lat})*SIN(RADIANS(#{qualified_lat_column_name}))))*#{multiplier})
31
+ |
32
+ end
33
+
34
+ def flat_distance_sql(origin, lat_degree_units, lng_degree_units)
35
+ %|
36
+ SQRT(POWER(#{lat_degree_units}*(#{origin.lat}-#{qualified_lat_column_name}),2)+
37
+ POWER(#{lng_degree_units}*(#{origin.lng}-#{qualified_lng_column_name}),2))
38
+ |
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,14 @@
1
+ # Extend Array with a sort_by_distance method.
2
+ class Array
3
+ # This method creates a "distance" attribute on each object, calculates the
4
+ # distance from the passed origin, and finally sorts the array by the
5
+ # resulting distance.
6
+ def sort_by_distance_from(origin, opts={})
7
+ distance_attribute_name = opts.delete(:distance_attribute_name) || 'distance'
8
+ self.each do |e|
9
+ e.class.send(:attr_accessor, distance_attribute_name) if !e.respond_to?("#{distance_attribute_name}=")
10
+ e.send("#{distance_attribute_name}=", e.distance_to(origin,opts))
11
+ end
12
+ self.sort!{|a,b|a.send(distance_attribute_name) <=> b.send(distance_attribute_name)}
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module Geokit
2
+ # These defaults are used in Geokit::Mappable.distance_to and in acts_as_mappable
3
+ @@default_units = :miles
4
+ @@default_formula = :sphere
5
+
6
+ [:default_units, :default_formula].each do |sym|
7
+ class_eval <<-EOS, __FILE__, __LINE__
8
+ def self.#{sym}
9
+ if defined?(#{sym.to_s.upcase})
10
+ #{sym.to_s.upcase}
11
+ else
12
+ @@#{sym}
13
+ end
14
+ end
15
+
16
+ def self.#{sym}=(obj)
17
+ @@#{sym} = obj
18
+ end
19
+ EOS
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module GeokitAr
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,420 @@
1
+ require 'test_helper'
2
+
3
+ Geokit::Geocoders::provider_order = [:google, :us]
4
+
5
+ class ActsAsMappableTest < GeokitTestCase
6
+
7
+ LOCATION_A_IP = "217.10.83.5"
8
+
9
+ def setup
10
+ @location_a = GeoKit::GeoLoc.new
11
+ @location_a.lat = 32.918593
12
+ @location_a.lng = -96.958444
13
+ @location_a.city = "Irving"
14
+ @location_a.state = "TX"
15
+ @location_a.country_code = "US"
16
+ @location_a.success = true
17
+
18
+ @sw = GeoKit::LatLng.new(32.91663,-96.982841)
19
+ @ne = GeoKit::LatLng.new(32.96302,-96.919495)
20
+ @bounds_center=GeoKit::LatLng.new((@sw.lat+@ne.lat)/2,(@sw.lng+@ne.lng)/2)
21
+
22
+ @starbucks = companies(:starbucks)
23
+ @loc_a = locations(:a)
24
+ @custom_loc_a = custom_locations(:a)
25
+ @loc_e = locations(:e)
26
+ @custom_loc_e = custom_locations(:e)
27
+
28
+ @barnes_and_noble = mock_organizations(:barnes_and_noble)
29
+ @address = mock_addresses(:address_barnes_and_noble)
30
+ end
31
+
32
+ def test_override_default_units_the_hard_way
33
+ Location.default_units = :kms
34
+ locations = Location.geo_scope(:origin => @loc_a).where("distance < 3.97")
35
+ assert_equal 5, locations.all.size
36
+ assert_equal 5, locations.count
37
+ Location.default_units = :miles
38
+ end
39
+
40
+ def test_include
41
+ locations = Location.geo_scope(:origin => @loc_a).includes(:company).where("company_id = 1").all
42
+ assert !locations.empty?
43
+ assert_equal 1, locations[0].company.id
44
+ assert_equal 'Starbucks', locations[0].company.name
45
+ end
46
+
47
+ def test_distance_between_geocoded
48
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
49
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("San Francisco, CA").returns(@location_a)
50
+ assert_equal 0, Location.distance_between("Irving, TX", "San Francisco, CA")
51
+ end
52
+
53
+ def test_distance_to_geocoded
54
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
55
+ assert_equal 0, @custom_loc_a.distance_to("Irving, TX")
56
+ end
57
+
58
+ def test_distance_to_geocoded_error
59
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(GeoKit::GeoLoc.new)
60
+ assert_raise(GeoKit::Geocoders::GeocodeError) { @custom_loc_a.distance_to("Irving, TX") }
61
+ end
62
+
63
+ def test_custom_attributes_distance_calculations
64
+ assert_equal 0, @custom_loc_a.distance_to(@loc_a)
65
+ assert_equal 0, CustomLocation.distance_between(@custom_loc_a, @loc_a)
66
+ end
67
+
68
+ def test_distance_column_in_select
69
+ locations = Location.geo_scope(:origin => @loc_a).order("distance ASC")
70
+ assert_equal 6, locations.all.size
71
+ assert_equal 0, @loc_a.distance_to(locations.first)
72
+ assert_in_delta 3.97, @loc_a.distance_to(locations.last, :units => :miles, :formula => :sphere), 0.01
73
+ end
74
+
75
+ def test_find_with_distance_condition
76
+ locations = Location.geo_scope(:origin => @loc_a, :within => 3.97)
77
+ assert_equal 5, locations.all.size
78
+ assert_equal 5, locations.count
79
+ end
80
+
81
+ def test_find_with_distance_condition_with_units_override
82
+ locations = Location.geo_scope(:origin => @loc_a, :units => :kms, :within => 6.387)
83
+ assert_equal 5, locations.all.size
84
+ assert_equal 5, locations.count
85
+ end
86
+
87
+ def test_find_with_distance_condition_with_formula_override
88
+ locations = Location.geo_scope(:origin => @loc_a, :formula => :flat, :within => 6.387)
89
+ assert_equal 6, locations.all.size
90
+ assert_equal 6, locations.count
91
+ end
92
+
93
+ def test_find_within
94
+ locations = Location.within(3.97, :origin => @loc_a)
95
+ assert_equal 5, locations.all.size
96
+ assert_equal 5, locations.count
97
+ end
98
+
99
+ def test_find_within_with_coordinates
100
+ locations = Location.within(3.97, :origin =>[@loc_a.lat,@loc_a.lng])
101
+ assert_equal 5, locations.all.size
102
+ assert_equal 5, locations.count
103
+ end
104
+
105
+ def test_find_with_compound_condition
106
+ locations = Location.geo_scope(:origin => @loc_a).where("distance < 5 and city = 'Coppell'")
107
+ assert_equal 2, locations.all.size
108
+ assert_equal 2, locations.count
109
+ end
110
+
111
+ def test_find_with_secure_compound_condition
112
+ locations = Location.geo_scope(:origin => @loc_a).where(["distance < ? and city = ?", 5, 'Coppell'])
113
+ assert_equal 2, locations.all.size
114
+ assert_equal 2, locations.count
115
+ end
116
+
117
+ def test_find_beyond
118
+ locations = Location.beyond(3.95, :origin => @loc_a)
119
+ assert_equal 1, locations.all.size
120
+ assert_equal 1, locations.count
121
+ end
122
+
123
+ def test_find_beyond_with_token
124
+ # locations = Location.find(:all, :beyond => 3.95, :origin => @loc_a)
125
+ locations = Location.geo_scope(:beyond => 3.95, :origin => @loc_a)
126
+ assert_equal 1, locations.all.size
127
+ assert_equal 1, locations.count
128
+ end
129
+
130
+ def test_find_beyond_with_coordinates
131
+ locations = Location.beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
132
+ assert_equal 1, locations.all.size
133
+ assert_equal 1, locations.count
134
+ end
135
+
136
+ def test_find_range_with_token
137
+ locations = Location.geo_scope(:range => 0..10, :origin => @loc_a)
138
+ assert_equal 6, locations.all.size
139
+ assert_equal 6, locations.count
140
+ end
141
+
142
+ def test_find_range_with_token_with_conditions
143
+ locations = Location.geo_scope(:origin => @loc_a, :range => 0..10).where(["city = ?", 'Coppell'])
144
+ assert_equal 2, locations.all.size
145
+ assert_equal 2, locations.count
146
+ end
147
+
148
+ def test_find_range_with_token_with_hash_conditions
149
+ locations = Location.geo_scope(:origin => @loc_a, :range => 0..10).where(:city => 'Coppell')
150
+ assert_equal 2, locations.all.size
151
+ assert_equal 2, locations.count
152
+ end
153
+
154
+ def test_find_range_with_token_excluding_end
155
+ locations = Location.geo_scope(:range => 0...10, :origin => @loc_a)
156
+ assert_equal 6, locations.all.size
157
+ assert_equal 6, locations.count
158
+ end
159
+
160
+ def test_find_nearest
161
+ assert_equal @loc_a, Location.nearest(:origin => @loc_a).first
162
+ end
163
+
164
+ def test_find_nearest_with_coordinates
165
+ assert_equal @loc_a, Location.nearest(:origin =>[@loc_a.lat, @loc_a.lng]).first
166
+ end
167
+
168
+ def test_find_farthest
169
+ assert_equal @loc_e, Location.farthest(:origin => @loc_a).first
170
+ end
171
+
172
+ def test_find_farthest_with_coordinates
173
+ assert_equal @loc_e, Location.farthest(:origin =>[@loc_a.lat, @loc_a.lng]).first
174
+ end
175
+
176
+ def test_scoped_distance_column_in_select
177
+ locations = @starbucks.locations.geo_scope(:origin => @loc_a).order("distance ASC")
178
+ assert_equal 5, locations.all.size
179
+ assert_equal 0, @loc_a.distance_to(locations.first)
180
+ assert_in_delta 3.97, @loc_a.distance_to(locations.last, :units => :miles, :formula => :sphere), 0.01
181
+ end
182
+
183
+ def test_scoped_find_with_distance_condition
184
+ locations = @starbucks.locations.geo_scope(:origin => @loc_a).where("distance < 3.97")
185
+ assert_equal 4, locations.all.size
186
+ assert_equal 4, locations.count
187
+ end
188
+
189
+ def test_scoped_find_within
190
+ locations = @starbucks.locations.within(3.97, :origin => @loc_a)
191
+ assert_equal 4, locations.all.size
192
+ assert_equal 4, locations.count
193
+ end
194
+
195
+ def test_scoped_find_with_compound_condition
196
+ locations = @starbucks.locations.geo_scope(:origin => @loc_a).where("distance < 5 and city = 'Coppell'")
197
+ assert_equal 2, locations.all.size
198
+ assert_equal 2, locations.count
199
+ end
200
+
201
+ def test_scoped_find_beyond
202
+ locations = @starbucks.locations.beyond(3.95, :origin => @loc_a)
203
+ assert_equal 1, locations.all.size
204
+ assert_equal 1, locations.count
205
+ end
206
+
207
+ def test_scoped_find_nearest
208
+ assert_equal @loc_a, @starbucks.locations.nearest(:origin => @loc_a).first
209
+ end
210
+
211
+ def test_scoped_find_farthest
212
+ assert_equal @loc_e, @starbucks.locations.farthest(:origin => @loc_a).first
213
+ end
214
+
215
+ def test_ip_geocoded_distance_column_in_select
216
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
217
+ locations = Location.geo_scope(:origin => LOCATION_A_IP).order("distance ASC")
218
+ assert_equal 6, locations.all.size
219
+ assert_equal 0, @loc_a.distance_to(locations.first)
220
+ assert_in_delta 3.97, @loc_a.distance_to(locations.last, :units => :miles, :formula => :sphere), 0.01
221
+ end
222
+
223
+ def test_ip_geocoded_find_with_distance_condition
224
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
225
+ locations = Location.geo_scope(:origin => LOCATION_A_IP).where2("distance < 3.97")
226
+ assert_equal 5, locations.all.size
227
+ assert_equal 5, locations.count
228
+ end
229
+
230
+ def test_ip_geocoded_find_within
231
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
232
+ locations = Location.within(3.97, :origin => LOCATION_A_IP)
233
+ assert_equal 5, locations.all.size
234
+ assert_equal 5, locations.count
235
+ end
236
+
237
+ def test_ip_geocoded_find_with_compound_condition
238
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
239
+ locations = Location.geo_scope(:origin => LOCATION_A_IP).where("distance < 5 and city = 'Coppell'")
240
+ assert_equal 2, locations.all.size
241
+ assert_equal 2, locations.count
242
+ end
243
+
244
+ def test_ip_geocoded_find_with_secure_compound_condition
245
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
246
+ locations = Location.geo_scope(:origin => LOCATION_A_IP).where(["distance < ? and city = ?", 5, 'Coppell'])
247
+ assert_equal 2, locations.all.size
248
+ assert_equal 2, locations.count
249
+ end
250
+
251
+ def test_ip_geocoded_find_beyond
252
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
253
+ locations = Location.beyond(3.95, :origin => LOCATION_A_IP)
254
+ assert_equal 1, locations.all.size
255
+ assert_equal 1, locations.count
256
+ end
257
+
258
+ def test_ip_geocoded_find_nearest
259
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
260
+ assert_equal @loc_a, Location.nearest(:origin => LOCATION_A_IP).first
261
+ end
262
+
263
+ def test_ip_geocoded_find_farthest
264
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
265
+ assert_equal @loc_e, Location.farthest(:origin => LOCATION_A_IP).first
266
+ end
267
+
268
+ def test_ip_geocoder_exception
269
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with('127.0.0.1').returns(GeoKit::GeoLoc.new)
270
+ assert_raises GeoKit::Geocoders::GeocodeError do
271
+ Location.farthest(:origin => '127.0.0.1').first
272
+ end
273
+ end
274
+
275
+ def test_address_geocode
276
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with('Irving, TX').returns(@location_a)
277
+ locations = Location.geo_scope(:origin => 'Irving, TX').where(["distance < ? and city = ?", 5, 'Coppell'])
278
+ assert_equal 2, locations.all.size
279
+ assert_equal 2, locations.count
280
+ end
281
+
282
+ def test_find_with_custom_distance_condition
283
+ locations = CustomLocation.geo_scope(:origin => @loc_a).where("dist < 3.97")
284
+ assert_equal 5, locations.all.size
285
+ assert_equal 5, locations.count
286
+ end
287
+
288
+ def test_find_with_custom_distance_condition_using_custom_origin
289
+ locations = CustomLocation.geo_scope(:origin => @custom_loc_a).where("dist < 3.97")
290
+ assert_equal 5, locations.all.size
291
+ locations = CustomLocation.count(:origin => @custom_loc_a).where("dist < 3.97")
292
+ assert_equal 5, locations.count
293
+ end
294
+
295
+ def test_find_within_with_custom
296
+ locations = CustomLocation.within(3.97, :origin => @loc_a)
297
+ assert_equal 5, locations.all.size
298
+ assert_equal 5, locations.count
299
+ end
300
+
301
+ def test_find_within_with_coordinates_with_custom
302
+ locations = CustomLocation.within(3.97, :origin =>[@loc_a.lat, @loc_a.lng])
303
+ assert_equal 5, locations.all.size
304
+ assert_equal 5, locations.count
305
+ end
306
+
307
+ def test_find_with_compound_condition_with_custom
308
+ locations = CustomLocation.geo_scope(:origin => @loc_a).where("dist < 5 and city = 'Coppell'")
309
+ assert_equal 1, locations.all.size
310
+ assert_equal 1, locations.count
311
+ end
312
+
313
+ def test_find_with_secure_compound_condition_with_custom
314
+ locations = CustomLocation.geo_scope(:origin => @loc_a).where(["dist < ? and city = ?", 5, 'Coppell'])
315
+ assert_equal 1, locations.all.size
316
+ assert_equal 1, locations.count
317
+ end
318
+
319
+ def test_find_beyond_with_custom
320
+ locations = CustomLocation.beyond(3.95, :origin => @loc_a)
321
+ assert_equal 1, locations.all.size
322
+ assert_equal 1, locations.count
323
+ end
324
+
325
+ def test_find_beyond_with_coordinates_with_custom
326
+ locations = CustomLocation.beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
327
+ assert_equal 1, locations.all.size
328
+ assert_equal 1, locations.count
329
+ end
330
+
331
+ def test_find_nearest_with_custom
332
+ assert_equal @custom_loc_a, CustomLocation.nearest(:origin => @loc_a).first
333
+ end
334
+
335
+ def test_find_nearest_with_coordinates_with_custom
336
+ assert_equal @custom_loc_a, CustomLocation.nearest(:origin =>[@loc_a.lat, @loc_a.lng]).first
337
+ end
338
+
339
+ def test_find_farthest_with_custom
340
+ assert_equal @custom_loc_e, CustomLocation.farthest(:origin => @loc_a).first
341
+ end
342
+
343
+ def test_find_farthest_with_coordinates_with_custom
344
+ assert_equal @custom_loc_e, CustomLocation.farthest(:origin =>[@loc_a.lat, @loc_a.lng]).first
345
+ end
346
+
347
+ def test_find_with_array_origin
348
+ locations = Location.geo_scope(:origin =>[@loc_a.lat,@loc_a.lng]).where("distance < 3.97")
349
+ assert_equal 5, locations.all.size
350
+ assert_equal 5, locations.count
351
+ end
352
+
353
+
354
+ # Bounding box tests
355
+
356
+ def test_find_within_bounds
357
+ locations = Location.in_bounds([@sw,@ne])
358
+ assert_equal 2, locations.all.size
359
+ assert_equal 2, locations.count
360
+ end
361
+
362
+ def test_find_within_bounds_ordered_by_distance
363
+ locations = Location.in_bounds([@sw,@ne], :origin=>@bounds_center).order('distance asc')
364
+ assert_equal locations[0], locations(:d)
365
+ assert_equal locations[1], locations(:a)
366
+ end
367
+
368
+ def test_find_within_bounds_with_token
369
+ locations = Location.geo_scope(:bounds=>[@sw,@ne])
370
+ assert_equal 2, locations.all.size
371
+ assert_equal 2, locations.count
372
+ end
373
+
374
+ def test_find_within_bounds_with_string_conditions
375
+ locations = Location.geo_scope(:bounds=>[@sw,@ne]).where("id !=#{locations(:a).id}")
376
+ assert_equal 1, locations.all.size
377
+ end
378
+
379
+ def test_find_within_bounds_with_array_conditions
380
+ locations = Location.geo_scope(:bounds=>[@sw,@ne]).where(["id != ?", locations(:a).id])
381
+ assert_equal 1, locations.all.size
382
+ end
383
+
384
+ def test_find_within_bounds_with_hash_conditions
385
+ locations = Location.geo_scope(:bounds=>[@sw,@ne]).where({:id => locations(:a).id})
386
+ assert_equal 1, locations.all.size
387
+ end
388
+
389
+ def test_auto_geocode
390
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
391
+ store=Store.new(:address=>'Irving, TX')
392
+ store.save
393
+ assert_equal store.lat,@location_a.lat
394
+ assert_equal store.lng,@location_a.lng
395
+ assert_equal 0, store.errors.size
396
+ end
397
+
398
+ def test_auto_geocode_failure
399
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("BOGUS").returns(GeoKit::GeoLoc.new)
400
+ store=Store.new(:address=>'BOGUS')
401
+ store.save
402
+ assert store.new_record?
403
+ assert_equal 1, store.errors.size
404
+ end
405
+
406
+ # Test :through
407
+
408
+ def test_find_with_through
409
+ organizations = MockOrganization.geo_scope(:origin => @location_a).order('distance ASC')
410
+ assert_equal 2, organizations.all.size
411
+ organizations = MockOrganization.geo_scope(:origin => @location_a).where("distance < 3.97")
412
+ assert_equal 1, organizations.count
413
+ end
414
+
415
+ def test_find_with_through_with_hash
416
+ people = MockPerson.geo_scope(:origin => @location_a).order('distance ASC')
417
+ assert_equal 2, people.size
418
+ assert_equal 2, people
419
+ end
420
+ end