geokit-rails3-1beta 0.2.0.beta1

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.
Files changed (40) hide show
  1. data/lib/geokit-rails3.rb +10 -0
  2. data/lib/geokit-rails3/acts_as_mappable.old.rb +437 -0
  3. data/lib/geokit-rails3/acts_as_mappable.rb +318 -0
  4. data/lib/geokit-rails3/adapters/abstract.rb +31 -0
  5. data/lib/geokit-rails3/adapters/mysql.rb +22 -0
  6. data/lib/geokit-rails3/adapters/mysql2.rb +22 -0
  7. data/lib/geokit-rails3/adapters/postgresql.rb +22 -0
  8. data/lib/geokit-rails3/adapters/sqlserver.rb +43 -0
  9. data/lib/geokit-rails3/core_extensions.rb +14 -0
  10. data/lib/geokit-rails3/defaults.rb +21 -0
  11. data/lib/geokit-rails3/geocoder_control.rb +18 -0
  12. data/lib/geokit-rails3/ip_geocode_lookup.rb +44 -0
  13. data/lib/geokit-rails3/railtie.rb +38 -0
  14. data/lib/geokit-rails3/version.rb +3 -0
  15. data/test/acts_as_mappable_test.rb +420 -0
  16. data/test/boot.rb +32 -0
  17. data/test/database.yml +20 -0
  18. data/test/fixtures/companies.yml +7 -0
  19. data/test/fixtures/custom_locations.yml +54 -0
  20. data/test/fixtures/locations.yml +54 -0
  21. data/test/fixtures/mock_addresses.yml +17 -0
  22. data/test/fixtures/mock_families.yml +2 -0
  23. data/test/fixtures/mock_houses.yml +9 -0
  24. data/test/fixtures/mock_organizations.yml +5 -0
  25. data/test/fixtures/mock_people.yml +5 -0
  26. data/test/fixtures/stores.yml +0 -0
  27. data/test/ip_geocode_lookup_test.disabled.rb +82 -0
  28. data/test/models/company.rb +3 -0
  29. data/test/models/custom_location.rb +12 -0
  30. data/test/models/location.rb +4 -0
  31. data/test/models/mock_address.rb +4 -0
  32. data/test/models/mock_family.rb +3 -0
  33. data/test/models/mock_house.rb +3 -0
  34. data/test/models/mock_organization.rb +4 -0
  35. data/test/models/mock_person.rb +4 -0
  36. data/test/models/store.rb +3 -0
  37. data/test/schema.rb +60 -0
  38. data/test/tasks.rake +38 -0
  39. data/test/test_helper.rb +23 -0
  40. metadata +206 -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 Mysql2 < 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.2.0.beta1"
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