geokit-rails3 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +30 -0
  2. data/CHANGELOG.rdoc +46 -0
  3. data/CONFIG.markdown +67 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +89 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.markdown +554 -0
  8. data/Rakefile +17 -0
  9. data/geokit-rails3.gemspec +29 -0
  10. data/lib/geokit-rails.rb +10 -0
  11. data/lib/geokit-rails3/acts_as_mappable.rb +433 -0
  12. data/lib/geokit-rails3/adapters/abstract.rb +31 -0
  13. data/lib/geokit-rails3/adapters/mysql.rb +22 -0
  14. data/lib/geokit-rails3/adapters/postgresql.rb +22 -0
  15. data/lib/geokit-rails3/adapters/sqlserver.rb +43 -0
  16. data/lib/geokit-rails3/core_extensions.rb +14 -0
  17. data/lib/geokit-rails3/defaults.rb +21 -0
  18. data/lib/geokit-rails3/geocoder_control.rb +18 -0
  19. data/lib/geokit-rails3/ip_geocode_lookup.rb +44 -0
  20. data/lib/geokit-rails3/railtie.rb +38 -0
  21. data/lib/geokit-rails3/version.rb +3 -0
  22. data/test/acts_as_mappable_test.rb +473 -0
  23. data/test/boot.rb +32 -0
  24. data/test/database.yml +20 -0
  25. data/test/fixtures/companies.yml +7 -0
  26. data/test/fixtures/custom_locations.yml +54 -0
  27. data/test/fixtures/locations.yml +54 -0
  28. data/test/fixtures/mock_addresses.yml +17 -0
  29. data/test/fixtures/mock_families.yml +2 -0
  30. data/test/fixtures/mock_houses.yml +9 -0
  31. data/test/fixtures/mock_organizations.yml +5 -0
  32. data/test/fixtures/mock_people.yml +5 -0
  33. data/test/fixtures/stores.yml +0 -0
  34. data/test/models/company.rb +3 -0
  35. data/test/models/custom_location.rb +12 -0
  36. data/test/models/location.rb +4 -0
  37. data/test/models/mock_address.rb +4 -0
  38. data/test/models/mock_family.rb +3 -0
  39. data/test/models/mock_house.rb +3 -0
  40. data/test/models/mock_organization.rb +4 -0
  41. data/test/models/mock_person.rb +4 -0
  42. data/test/models/store.rb +3 -0
  43. data/test/schema.rb +60 -0
  44. data/test/tasks.rake +38 -0
  45. data/test/test_helper.rb +23 -0
  46. metadata +236 -0
@@ -0,0 +1,31 @@
1
+ module Geokit
2
+ module Adapters
3
+ class Abstract
4
+ class NotImplementedError < StandardError ; end
5
+
6
+ cattr_accessor :loaded
7
+
8
+ class << self
9
+ def load(klass) ; end
10
+ end
11
+
12
+ def initialize(klass)
13
+ @owner = klass
14
+ end
15
+
16
+ def method_missing(method, *args, &block)
17
+ return @owner.send(method, *args, &block) if @owner.respond_to?(method)
18
+ super
19
+ end
20
+
21
+ def sphere_distance_sql(lat, lng, multiplier)
22
+ raise NotImplementedError, '#sphere_distance_sql is not implemented'
23
+ end
24
+
25
+ def flat_distance_sql(origin, lat_degree_units, lng_degree_units)
26
+ raise NotImplementedError, '#flat_distance_sql is not implemented'
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ module Geokit
2
+ module Adapters
3
+ class MySQL < Abstract
4
+
5
+ def sphere_distance_sql(lat, lng, multiplier)
6
+ %|
7
+ (ACOS(least(1,COS(#{lat})*COS(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*COS(RADIANS(#{qualified_lng_column_name}))+
8
+ COS(#{lat})*SIN(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*SIN(RADIANS(#{qualified_lng_column_name}))+
9
+ SIN(#{lat})*SIN(RADIANS(#{qualified_lat_column_name}))))*#{multiplier})
10
+ |
11
+ end
12
+
13
+ def flat_distance_sql(origin, lat_degree_units, lng_degree_units)
14
+ %|
15
+ SQRT(POW(#{lat_degree_units}*(#{origin.lat}-#{qualified_lat_column_name}),2)+
16
+ POW(#{lng_degree_units}*(#{origin.lng}-#{qualified_lng_column_name}),2))
17
+ |
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module Geokit
2
+ module Adapters
3
+ class PostgreSQL < Abstract
4
+
5
+ def sphere_distance_sql(lat, lng, multiplier)
6
+ %|
7
+ (ACOS(least(1,COS(#{lat})*COS(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*COS(RADIANS(#{qualified_lng_column_name}))+
8
+ COS(#{lat})*SIN(#{lng})*COS(RADIANS(#{qualified_lat_column_name}))*SIN(RADIANS(#{qualified_lng_column_name}))+
9
+ SIN(#{lat})*SIN(RADIANS(#{qualified_lat_column_name}))))*#{multiplier})
10
+ |
11
+ end
12
+
13
+ def flat_distance_sql(origin, lat_degree_units, lng_degree_units)
14
+ %|
15
+ SQRT(POW(#{lat_degree_units}*(#{origin.lat}-#{qualified_lat_column_name}),2)+
16
+ POW(#{lng_degree_units}*(#{origin.lng}-#{qualified_lng_column_name}),2))
17
+ |
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -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,18 @@
1
+ require 'active_support/concern'
2
+
3
+ module Geokit
4
+ module GeocoderControl
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ if self.respond_to? :before_filter
9
+ self.send :before_filter, :set_geokit_domain
10
+ end
11
+ end
12
+
13
+ def set_geokit_domain
14
+ Geokit::Geocoders::domain = request.domain
15
+ logger.debug("Geokit is using the domain: #{Geokit::Geocoders::domain}")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,44 @@
1
+ require 'yaml'
2
+ require 'active_support/concern'
3
+
4
+ module Geokit
5
+ # Contains a class method geocode_ip_address which can be used to enable automatic geocoding
6
+ # for request IP addresses. The geocoded information is stored in a cookie and in the
7
+ # session to minimize web service calls. The point of the helper is to enable location-based
8
+ # websites to have a best-guess for new visitors.
9
+ module IpGeocodeLookup
10
+ extend ActiveSupport::Concern
11
+
12
+ # Class method to mix into active record.
13
+ module ClassMethods # :nodoc:
14
+ def geocode_ip_address(filter_options = {})
15
+ before_filter :store_ip_location, filter_options
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ # Places the IP address' geocode location into the session if it
22
+ # can be found. Otherwise, looks for a geo location cookie and
23
+ # uses that value. The last resort is to call the web service to
24
+ # get the value.
25
+ def store_ip_location
26
+ session[:geo_location] ||= retrieve_location_from_cookie_or_service
27
+ cookies[:geo_location] = { :value => session[:geo_location].to_yaml, :expires => 30.days.from_now } if session[:geo_location]
28
+ end
29
+
30
+ # Uses the stored location value from the cookie if it exists. If
31
+ # no cookie exists, calls out to the web service to get the location.
32
+ def retrieve_location_from_cookie_or_service
33
+ return YAML.load(cookies[:geo_location]) if cookies[:geo_location]
34
+ location = Geocoders::MultiGeocoder.geocode(get_ip_address)
35
+ return location.success ? location : nil
36
+ end
37
+
38
+ # Returns the real ip address, though this could be the localhost ip
39
+ # address. No special handling here anymore.
40
+ def get_ip_address
41
+ request.remote_ip
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,38 @@
1
+ require 'geokit-rails3'
2
+ require 'rails'
3
+
4
+ module Geokit
5
+
6
+ class Railtie < Rails::Railtie
7
+
8
+ config.geokit = ActiveSupport::OrderedOptions.new
9
+ config.geokit.geocoders = ActiveSupport::OrderedOptions.new
10
+
11
+ initializer 'geokit-rails3.insert_into_active_record' do
12
+ ActiveSupport.on_load :active_record do
13
+ ActiveRecord::Base.send(:include, Geokit::ActsAsMappable::Glue)
14
+ Geokit::Geocoders.logger = ActiveRecord::Base.logger
15
+ end
16
+ end
17
+
18
+ initializer 'geokit-rails3.insert_into_action_controller' do
19
+ ActiveSupport.on_load :action_controller do
20
+ ActionController::Base.send(:include, Geokit::GeocoderControl)
21
+ ActionController::Base.send(:include, GeoKit::IpGeocodeLookup)
22
+ end
23
+ end
24
+
25
+ config.after_initialize do |app|
26
+ options = app.config.geokit
27
+ geocoders_options = options.delete(:geocoders)
28
+
29
+ options.each do |k,v|
30
+ Geokit::send("#{k}=", v)
31
+ end
32
+ geocoders_options.each do |k,v|
33
+ Geokit::Geocoders::send("#{k}=", v)
34
+ end
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,3 @@
1
+ module GeokitRails3
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,473 @@
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.find(:all, :origin => @loc_a, :conditions => "distance < 3.97")
35
+ assert_equal 5, locations.size
36
+ locations = Location.count(:origin => @loc_a, :conditions => "distance < 3.97")
37
+ assert_equal 5, locations
38
+ Location.default_units = :miles
39
+ end
40
+
41
+ def test_include
42
+ locations = Location.find(:all, :origin => @loc_a, :include => :company, :conditions => "company_id = 1")
43
+ assert !locations.empty?
44
+ assert_equal 1, locations[0].company.id
45
+ assert_equal 'Starbucks', locations[0].company.name
46
+ end
47
+
48
+ def test_distance_between_geocoded
49
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
50
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("San Francisco, CA").returns(@location_a)
51
+ assert_equal 0, Location.distance_between("Irving, TX", "San Francisco, CA")
52
+ end
53
+
54
+ def test_distance_to_geocoded
55
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
56
+ assert_equal 0, @custom_loc_a.distance_to("Irving, TX")
57
+ end
58
+
59
+ def test_distance_to_geocoded_error
60
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(GeoKit::GeoLoc.new)
61
+ assert_raise(GeoKit::Geocoders::GeocodeError) { @custom_loc_a.distance_to("Irving, TX") }
62
+ end
63
+
64
+ def test_custom_attributes_distance_calculations
65
+ assert_equal 0, @custom_loc_a.distance_to(@loc_a)
66
+ assert_equal 0, CustomLocation.distance_between(@custom_loc_a, @loc_a)
67
+ end
68
+
69
+ def test_distance_column_in_select
70
+ locations = Location.find(:all, :origin => @loc_a, :order => "distance ASC")
71
+ assert_equal 6, locations.size
72
+ assert_equal 0, @loc_a.distance_to(locations.first)
73
+ assert_in_delta 3.97, @loc_a.distance_to(locations.last, :units => :miles, :formula => :sphere), 0.01
74
+ end
75
+
76
+ def test_find_with_distance_condition
77
+ locations = Location.find(:all, :origin => @loc_a, :conditions => "distance < 3.97")
78
+ assert_equal 5, locations.size
79
+ locations = Location.count(:origin => @loc_a, :conditions => "distance < 3.97")
80
+ assert_equal 5, locations
81
+ end
82
+
83
+ def test_find_with_distance_condition_with_units_override
84
+ locations = Location.find(:all, :origin => @loc_a, :units => :kms, :conditions => "distance < 6.387")
85
+ assert_equal 5, locations.size
86
+ locations = Location.count(:origin => @loc_a, :units => :kms, :conditions => "distance < 6.387")
87
+ assert_equal 5, locations
88
+ end
89
+
90
+ def test_find_with_distance_condition_with_formula_override
91
+ locations = Location.find(:all, :origin => @loc_a, :formula => :flat, :conditions => "distance < 6.387")
92
+ assert_equal 6, locations.size
93
+ locations = Location.count(:origin => @loc_a, :formula => :flat, :conditions => "distance < 6.387")
94
+ assert_equal 6, locations
95
+ end
96
+
97
+ def test_find_within
98
+ locations = Location.find_within(3.97, :origin => @loc_a)
99
+ assert_equal 5, locations.size
100
+ locations = Location.count_within(3.97, :origin => @loc_a)
101
+ assert_equal 5, locations
102
+ end
103
+
104
+ def test_find_within_with_token
105
+ locations = Location.find(:all, :within => 3.97, :origin => @loc_a)
106
+ assert_equal 5, locations.size
107
+ locations = Location.count(:within => 3.97, :origin => @loc_a)
108
+ assert_equal 5, locations
109
+ end
110
+
111
+ def test_find_within_with_coordinates
112
+ locations = Location.find_within(3.97, :origin =>[@loc_a.lat,@loc_a.lng])
113
+ assert_equal 5, locations.size
114
+ locations = Location.count_within(3.97, :origin =>[@loc_a.lat,@loc_a.lng])
115
+ assert_equal 5, locations
116
+ end
117
+
118
+ def test_find_with_compound_condition
119
+ locations = Location.find(:all, :origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
120
+ assert_equal 2, locations.size
121
+ locations = Location.count(:origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
122
+ assert_equal 2, locations
123
+ end
124
+
125
+ def test_find_with_secure_compound_condition
126
+ locations = Location.find(:all, :origin => @loc_a, :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
127
+ assert_equal 2, locations.size
128
+ locations = Location.count(:origin => @loc_a, :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
129
+ assert_equal 2, locations
130
+ end
131
+
132
+ def test_find_beyond
133
+ locations = Location.find_beyond(3.95, :origin => @loc_a)
134
+ assert_equal 1, locations.size
135
+ locations = Location.count_beyond(3.95, :origin => @loc_a)
136
+ assert_equal 1, locations
137
+ end
138
+
139
+ def test_find_beyond_with_token
140
+ locations = Location.find(:all, :beyond => 3.95, :origin => @loc_a)
141
+ assert_equal 1, locations.size
142
+ locations = Location.count(:beyond => 3.95, :origin => @loc_a)
143
+ assert_equal 1, locations
144
+ end
145
+
146
+ def test_find_beyond_with_coordinates
147
+ locations = Location.find_beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
148
+ assert_equal 1, locations.size
149
+ locations = Location.count_beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
150
+ assert_equal 1, locations
151
+ end
152
+
153
+ def test_find_range_with_token
154
+ locations = Location.find(:all, :range => 0..10, :origin => @loc_a)
155
+ assert_equal 6, locations.size
156
+ locations = Location.count(:range => 0..10, :origin => @loc_a)
157
+ assert_equal 6, locations
158
+ end
159
+
160
+ def test_find_range_with_token_with_conditions
161
+ locations = Location.find(:all, :origin => @loc_a, :range => 0..10, :conditions => ["city = ?", 'Coppell'])
162
+ assert_equal 2, locations.size
163
+ locations = Location.count(:origin => @loc_a, :range => 0..10, :conditions => ["city = ?", 'Coppell'])
164
+ assert_equal 2, locations
165
+ end
166
+
167
+ def test_find_range_with_token_with_hash_conditions
168
+ locations = Location.find(:all, :origin => @loc_a, :range => 0..10, :conditions => {:city => 'Coppell'})
169
+ assert_equal 2, locations.size
170
+ locations = Location.count(:origin => @loc_a, :range => 0..10, :conditions => {:city => 'Coppell'})
171
+ assert_equal 2, locations
172
+ end
173
+
174
+ def test_find_range_with_token_excluding_end
175
+ locations = Location.find(:all, :range => 0...10, :origin => @loc_a)
176
+ assert_equal 6, locations.size
177
+ locations = Location.count(:range => 0...10, :origin => @loc_a)
178
+ assert_equal 6, locations
179
+ end
180
+
181
+ def test_find_nearest
182
+ assert_equal @loc_a, Location.find_nearest(:origin => @loc_a)
183
+ end
184
+
185
+ def test_find_nearest_through_find
186
+ assert_equal @loc_a, Location.find(:nearest, :origin => @loc_a)
187
+ end
188
+
189
+ def test_find_nearest_with_coordinates
190
+ assert_equal @loc_a, Location.find_nearest(:origin =>[@loc_a.lat, @loc_a.lng])
191
+ end
192
+
193
+ def test_find_farthest
194
+ assert_equal @loc_e, Location.find_farthest(:origin => @loc_a)
195
+ end
196
+
197
+ def test_find_farthest_through_find
198
+ assert_equal @loc_e, Location.find(:farthest, :origin => @loc_a)
199
+ end
200
+
201
+ def test_find_farthest_with_coordinates
202
+ assert_equal @loc_e, Location.find_farthest(:origin =>[@loc_a.lat, @loc_a.lng])
203
+ end
204
+
205
+ def test_scoped_distance_column_in_select
206
+ locations = @starbucks.locations.find(:all, :origin => @loc_a, :order => "distance ASC")
207
+ assert_equal 5, locations.size
208
+ assert_equal 0, @loc_a.distance_to(locations.first)
209
+ assert_in_delta 3.97, @loc_a.distance_to(locations.last, :units => :miles, :formula => :sphere), 0.01
210
+ end
211
+
212
+ def test_scoped_find_with_distance_condition
213
+ locations = @starbucks.locations.find(:all, :origin => @loc_a, :conditions => "distance < 3.97")
214
+ assert_equal 4, locations.size
215
+ locations = @starbucks.locations.count(:origin => @loc_a, :conditions => "distance < 3.97")
216
+ assert_equal 4, locations
217
+ end
218
+
219
+ def test_scoped_find_within
220
+ locations = @starbucks.locations.find_within(3.97, :origin => @loc_a)
221
+ assert_equal 4, locations.size
222
+ locations = @starbucks.locations.count_within(3.97, :origin => @loc_a)
223
+ assert_equal 4, locations
224
+ end
225
+
226
+ def test_scoped_find_with_compound_condition
227
+ locations = @starbucks.locations.find(:all, :origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
228
+ assert_equal 2, locations.size
229
+ locations = @starbucks.locations.count( :origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
230
+ assert_equal 2, locations
231
+ end
232
+
233
+ def test_scoped_find_beyond
234
+ locations = @starbucks.locations.find_beyond(3.95, :origin => @loc_a)
235
+ assert_equal 1, locations.size
236
+ locations = @starbucks.locations.count_beyond(3.95, :origin => @loc_a)
237
+ assert_equal 1, locations
238
+ end
239
+
240
+ def test_scoped_find_nearest
241
+ assert_equal @loc_a, @starbucks.locations.find_nearest(:origin => @loc_a)
242
+ end
243
+
244
+ def test_scoped_find_farthest
245
+ assert_equal @loc_e, @starbucks.locations.find_farthest(:origin => @loc_a)
246
+ end
247
+
248
+ def test_ip_geocoded_distance_column_in_select
249
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
250
+ locations = Location.find(:all, :origin => LOCATION_A_IP, :order => "distance ASC")
251
+ assert_equal 6, locations.size
252
+ assert_equal 0, @loc_a.distance_to(locations.first)
253
+ assert_in_delta 3.97, @loc_a.distance_to(locations.last, :units => :miles, :formula => :sphere), 0.01
254
+ end
255
+
256
+ def test_ip_geocoded_find_with_distance_condition
257
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
258
+ locations = Location.find(:all, :origin => LOCATION_A_IP, :conditions => "distance < 3.97")
259
+ assert_equal 5, locations.size
260
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
261
+ locations = Location.count(:origin => LOCATION_A_IP, :conditions => "distance < 3.97")
262
+ assert_equal 5, locations
263
+ end
264
+
265
+ def test_ip_geocoded_find_within
266
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
267
+ locations = Location.find_within(3.97, :origin => LOCATION_A_IP)
268
+ assert_equal 5, locations.size
269
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
270
+ locations = Location.count_within(3.97, :origin => LOCATION_A_IP)
271
+ assert_equal 5, locations
272
+ end
273
+
274
+ def test_ip_geocoded_find_with_compound_condition
275
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
276
+ locations = Location.find(:all, :origin => LOCATION_A_IP, :conditions => "distance < 5 and city = 'Coppell'")
277
+ assert_equal 2, locations.size
278
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
279
+ locations = Location.count(:origin => LOCATION_A_IP, :conditions => "distance < 5 and city = 'Coppell'")
280
+ assert_equal 2, locations
281
+ end
282
+
283
+ def test_ip_geocoded_find_with_secure_compound_condition
284
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
285
+ locations = Location.find(:all, :origin => LOCATION_A_IP, :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
286
+ assert_equal 2, locations.size
287
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
288
+ locations = Location.count(:origin => LOCATION_A_IP, :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
289
+ assert_equal 2, locations
290
+ end
291
+
292
+ def test_ip_geocoded_find_beyond
293
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
294
+ locations = Location.find_beyond(3.95, :origin => LOCATION_A_IP)
295
+ assert_equal 1, locations.size
296
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
297
+ locations = Location.count_beyond(3.95, :origin => LOCATION_A_IP)
298
+ assert_equal 1, locations
299
+ end
300
+
301
+ def test_ip_geocoded_find_nearest
302
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
303
+ assert_equal @loc_a, Location.find_nearest(:origin => LOCATION_A_IP)
304
+ end
305
+
306
+ def test_ip_geocoded_find_farthest
307
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with(LOCATION_A_IP).returns(@location_a)
308
+ assert_equal @loc_e, Location.find_farthest(:origin => LOCATION_A_IP)
309
+ end
310
+
311
+ def test_ip_geocoder_exception
312
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with('127.0.0.1').returns(GeoKit::GeoLoc.new)
313
+ assert_raises GeoKit::Geocoders::GeocodeError do
314
+ Location.find_farthest(:origin => '127.0.0.1')
315
+ end
316
+ end
317
+
318
+ def test_address_geocode
319
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with('Irving, TX').returns(@location_a)
320
+ locations = Location.find(:all, :origin => 'Irving, TX', :conditions => ["distance < ? and city = ?", 5, 'Coppell'])
321
+ assert_equal 2, locations.size
322
+ end
323
+
324
+ def test_find_with_custom_distance_condition
325
+ locations = CustomLocation.find(:all, :origin => @loc_a, :conditions => "dist < 3.97")
326
+ assert_equal 5, locations.size
327
+ locations = CustomLocation.count(:origin => @loc_a, :conditions => "dist < 3.97")
328
+ assert_equal 5, locations
329
+ end
330
+
331
+ def test_find_with_custom_distance_condition_using_custom_origin
332
+ locations = CustomLocation.find(:all, :origin => @custom_loc_a, :conditions => "dist < 3.97")
333
+ assert_equal 5, locations.size
334
+ locations = CustomLocation.count(:origin => @custom_loc_a, :conditions => "dist < 3.97")
335
+ assert_equal 5, locations
336
+ end
337
+
338
+ def test_find_within_with_custom
339
+ locations = CustomLocation.find_within(3.97, :origin => @loc_a)
340
+ assert_equal 5, locations.size
341
+ locations = CustomLocation.count_within(3.97, :origin => @loc_a)
342
+ assert_equal 5, locations
343
+ end
344
+
345
+ def test_find_within_with_coordinates_with_custom
346
+ locations = CustomLocation.find_within(3.97, :origin =>[@loc_a.lat, @loc_a.lng])
347
+ assert_equal 5, locations.size
348
+ locations = CustomLocation.count_within(3.97, :origin =>[@loc_a.lat, @loc_a.lng])
349
+ assert_equal 5, locations
350
+ end
351
+
352
+ def test_find_with_compound_condition_with_custom
353
+ locations = CustomLocation.find(:all, :origin => @loc_a, :conditions => "dist < 5 and city = 'Coppell'")
354
+ assert_equal 1, locations.size
355
+ locations = CustomLocation.count(:origin => @loc_a, :conditions => "dist < 5 and city = 'Coppell'")
356
+ assert_equal 1, locations
357
+ end
358
+
359
+ def test_find_with_secure_compound_condition_with_custom
360
+ locations = CustomLocation.find(:all, :origin => @loc_a, :conditions => ["dist < ? and city = ?", 5, 'Coppell'])
361
+ assert_equal 1, locations.size
362
+ locations = CustomLocation.count(:origin => @loc_a, :conditions => ["dist < ? and city = ?", 5, 'Coppell'])
363
+ assert_equal 1, locations
364
+ end
365
+
366
+ def test_find_beyond_with_custom
367
+ locations = CustomLocation.find_beyond(3.95, :origin => @loc_a)
368
+ assert_equal 1, locations.size
369
+ locations = CustomLocation.count_beyond(3.95, :origin => @loc_a)
370
+ assert_equal 1, locations
371
+ end
372
+
373
+ def test_find_beyond_with_coordinates_with_custom
374
+ locations = CustomLocation.find_beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
375
+ assert_equal 1, locations.size
376
+ locations = CustomLocation.count_beyond(3.95, :origin =>[@loc_a.lat, @loc_a.lng])
377
+ assert_equal 1, locations
378
+ end
379
+
380
+ def test_find_nearest_with_custom
381
+ assert_equal @custom_loc_a, CustomLocation.find_nearest(:origin => @loc_a)
382
+ end
383
+
384
+ def test_find_nearest_with_coordinates_with_custom
385
+ assert_equal @custom_loc_a, CustomLocation.find_nearest(:origin =>[@loc_a.lat, @loc_a.lng])
386
+ end
387
+
388
+ def test_find_farthest_with_custom
389
+ assert_equal @custom_loc_e, CustomLocation.find_farthest(:origin => @loc_a)
390
+ end
391
+
392
+ def test_find_farthest_with_coordinates_with_custom
393
+ assert_equal @custom_loc_e, CustomLocation.find_farthest(:origin =>[@loc_a.lat, @loc_a.lng])
394
+ end
395
+
396
+ def test_find_with_array_origin
397
+ locations = Location.find(:all, :origin =>[@loc_a.lat,@loc_a.lng], :conditions => "distance < 3.97")
398
+ assert_equal 5, locations.size
399
+ locations = Location.count(:origin =>[@loc_a.lat,@loc_a.lng], :conditions => "distance < 3.97")
400
+ assert_equal 5, locations
401
+ end
402
+
403
+
404
+ # Bounding box tests
405
+
406
+ def test_find_within_bounds
407
+ locations = Location.find_within_bounds([@sw,@ne])
408
+ assert_equal 2, locations.size
409
+ locations = Location.count_within_bounds([@sw,@ne])
410
+ assert_equal 2, locations
411
+ end
412
+
413
+ def test_find_within_bounds_ordered_by_distance
414
+ locations = Location.find_within_bounds([@sw,@ne], :origin=>@bounds_center, :order=>'distance asc')
415
+ assert_equal locations[0], locations(:d)
416
+ assert_equal locations[1], locations(:a)
417
+ end
418
+
419
+ def test_find_within_bounds_with_token
420
+ locations = Location.find(:all, :bounds=>[@sw,@ne])
421
+ assert_equal 2, locations.size
422
+ locations = Location.count(:bounds=>[@sw,@ne])
423
+ assert_equal 2, locations
424
+ end
425
+
426
+ def test_find_within_bounds_with_string_conditions
427
+ locations = Location.find(:all, :bounds=>[@sw,@ne], :conditions=>"id !=#{locations(:a).id}")
428
+ assert_equal 1, locations.size
429
+ end
430
+
431
+ def test_find_within_bounds_with_array_conditions
432
+ locations = Location.find(:all, :bounds=>[@sw,@ne], :conditions=>["id != ?", locations(:a).id])
433
+ assert_equal 1, locations.size
434
+ end
435
+
436
+ def test_find_within_bounds_with_hash_conditions
437
+ locations = Location.find(:all, :bounds=>[@sw,@ne], :conditions=>{:id => locations(:a).id})
438
+ assert_equal 1, locations.size
439
+ end
440
+
441
+ def test_auto_geocode
442
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("Irving, TX").returns(@location_a)
443
+ store=Store.new(:address=>'Irving, TX')
444
+ store.save
445
+ assert_equal store.lat,@location_a.lat
446
+ assert_equal store.lng,@location_a.lng
447
+ assert_equal 0, store.errors.size
448
+ end
449
+
450
+ def test_auto_geocode_failure
451
+ GeoKit::Geocoders::MultiGeocoder.expects(:geocode).with("BOGUS").returns(GeoKit::GeoLoc.new)
452
+ store=Store.new(:address=>'BOGUS')
453
+ store.save
454
+ assert store.new_record?
455
+ assert_equal 1, store.errors.size
456
+ end
457
+
458
+ # Test :through
459
+
460
+ def test_find_with_through
461
+ organizations = MockOrganization.find(:all, :origin => @location_a, :order => 'distance ASC')
462
+ assert_equal 2, organizations.size
463
+ organizations = MockOrganization.count(:origin => @location_a, :conditions => "distance < 3.97")
464
+ assert_equal 1, organizations
465
+ end
466
+
467
+ def test_find_with_through_with_hash
468
+ people = MockPerson.find(:all, :origin => @location_a, :order => 'distance ASC')
469
+ assert_equal 2, people.size
470
+ people = MockPerson.count(:origin => @location_a, :conditions => "distance < 3.97")
471
+ assert_equal 2, people
472
+ end
473
+ end