public
Description: A plugin for maps-based apps with 1) ActiveRecord extensions for geo-based finders (find within X miles); 2) geocoding through multiple providers with failover; 3) geo distance calculations; 4) IP-based location lookup; 5) before_filter for IP geocoder.; forked from official SVN repo to fix bugs
Homepage: http://geokit.rubyforge.org/
Clone URL: git://github.com/ptb/geokit.git
Added timeout and proxy support.  Added count support.  Fixed rake-based 
test invocation.  Fixed exclusive range condition bug.  Fixed default ip 
address for localhost

git-svn-id: http://geokit.rubyforge.org/svn/trunk@32 
9265c765-0211-4c68-b2df-6d1bd6e20c4d
bill_eisenhauer (author)
Sun Jun 03 23:28:09 -0700 2007
commit  e495d3dea2e6a8899fdba4620c45dcfade68620d
tree    1ed9a2c82590d24c497bfff0f4a57faaf783a19a
parent  ed6cc61bc37aad4ebb34cecdb2fc94e49d32b4b4
0
...
80
81
82
83
 
84
85
86
87
 
88
89
90
...
97
98
99
100
 
101
102
103
...
108
109
110
111
112
113
114
 
 
 
 
115
116
117
...
123
124
125
 
 
 
 
 
 
 
 
126
127
128
...
80
81
82
 
83
84
85
86
 
87
88
89
90
...
97
98
99
 
100
101
102
103
...
108
109
110
 
 
 
 
111
112
113
114
115
116
117
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
0
@@ -80,11 +80,11 @@ different combinations:
0
 
0
 Origin as a two-element array of latititude/longitude:
0
 
0
- find(:all, :origin=>[37.792,-122.393])
0
+ find(:all, :origin => [37.792,-122.393])
0
 
0
 Origin as a geocodeable string:
0
 
0
- find(:all, :origin=>'100 Spear st, San Francisco, CA')
0
+ find(:all, :origin => '100 Spear st, San Francisco, CA')
0
 
0
 Origin as an object which responds to lat and lng methods,
0
 or latitude and longitude methods, or whatever methods you have
0
@@ -97,7 +97,7 @@ formula for the distance field in the conditions clause. This saves
0
 from having to add complicated SQL in the conditions clause. The result
0
 set returns model instances that are less than 5 units away.
0
 
0
- find(:all, :origin, :conditions => "distance < 5")
0
+ find(:all, :origin => @somewhere, :conditions => "distance < 5")
0
 
0
 NOTE: conditions can also be compound as in
0
 :conditions => "distance < 100 and state ='TX'".
0
@@ -108,10 +108,10 @@ from the :options hash prior to invoking the superclass behavior.
0
 
0
 Other convenience methods work intuitively and are as follows:
0
 
0
- find_within(distance, options={})
0
- find_beyond(distance, options={})
0
- find_closest(options={})
0
- find_farthest(options={})
0
+ find_within(distance, :origin => @somewhere)
0
+ find_beyond(distance, :origin => @somewhere)
0
+ find_closest(:origin => @somewhere)
0
+ find_farthest(:origin => @somewhere)
0
 
0
 where the options respect the defaults, but can be overridden if
0
 desired.
0
@@ -123,6 +123,14 @@ calculations, you can use the following:
0
 
0
 Thereafter, you are free to use it in find_by_sql as you wish.
0
 
0
+There are methods available to enable you to get the count based upon
0
+the find condition that you have provided. These all work similarly to
0
+the finders. So for instance:
0
+
0
+ count(:origin, :conditions => "distance < 5")
0
+ count_within(distance, :origin => @somewhere)
0
+ count_beyond(distance, :origin => @somewhere)
0
+
0
 ## IP GEOCODING
0
 
0
 You can obtain the location for an IP at any time using the geocoder
...
 
 
 
 
 
1
2
3
4
5
6
 
7
8
9
...
1
2
3
4
5
6
 
 
 
 
 
7
8
9
10
0
@@ -1,8 +1,9 @@
0
+author:
0
+ name_1: Bill Eisenhauer
0
+ homepage_1: http://blog.billeisenhauer.com
0
+ name_2: Andre Lewis
0
+ homepage_2: http://www.earthcode.com
0
 summary: Geo distance calculations, distance calculation query support, geocoding for physical and ip addresses.
0
-version: 0.1
0
-author_1: Bill Eisenhauer
0
-homepage_1: http://www.billeisenhauer.com
0
-author_2: Andre Lewis
0
-homepage_andre: http://www.earthcode.com
0
+version: 1.0
0
 rails_version: 1.0+
0
 license: MIT
0
\ No newline at end of file
...
2
3
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
6
7
8
 
9
10
11
12
13
 
14
15
16
17
18
19
20
 
21
22
23
...
25
26
27
28
 
29
30
31
...
33
34
35
36
37
 
38
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
22
23
24
25
26
 
27
28
29
30
31
32
33
 
34
35
36
37
...
39
40
41
 
42
43
44
45
...
47
48
49
 
50
51
52
0
@@ -2,22 +2,36 @@
0
 GeoKit::default_units = :miles
0
 GeoKit::default_formula = :sphere
0
 
0
+# This is the timeout value in seconds to be used for calls to the geocoder web
0
+# services. For no timeout at all, comment out the setting. The timeout unit
0
+# is in seconds.
0
+GeoKit::Geocoders::timeout = 3
0
+
0
+# These settings are used if web service calls must be routed through a proxy.
0
+# These setting can be nil if not needed, otherwise, addr and port must be
0
+# filled in at a minimum. If the proxy requires authentication, the username
0
+# and password can be provided as well.
0
+GeoKit::Geocoders::proxy_addr = nil
0
+GeoKit::Geocoders::proxy_port = nil
0
+GeoKit::Geocoders::proxy_user = nil
0
+GeoKit::Geocoders::proxy_pass = nil
0
+
0
 # This is your yahoo application key for the Yahoo Geocoder.
0
 # See http://developer.yahoo.com/faq/index.html#appid
0
 # and http://developer.yahoo.com/maps/rest/V1/geocode.html
0
-GeoKit::Geocoders::yahoo='REPLACE_WITH_YOUR_YAHOO_KEY'
0
+GeoKit::Geocoders::yahoo = 'REPLACE_WITH_YOUR_YAHOO_KEY'
0
     
0
 # This is your Google Maps geocoder key.
0
 # See http://www.google.com/apis/maps/signup.html
0
 # and http://www.google.com/apis/maps/documentation/#Geocoding_Examples
0
-GeoKit::Geocoders::google='REPLACE_WITH_YOUR_GOOGLE_KEY'
0
+GeoKit::Geocoders::google = 'REPLACE_WITH_YOUR_GOOGLE_KEY'
0
     
0
 # This is your username and password for geocoder.us.
0
 # To use the free service, the value can be set to nil or false. For
0
 # usage tied to an account, the value should be set to username:password.
0
 # See http://geocoder.us
0
 # and http://geocoder.us/user/signup
0
-GeoKit::Geocoders::geocoder_us=false
0
+GeoKit::Geocoders::geocoder_us = false
0
 
0
 # This is your authorization key for geocoder.ca.
0
 # To use the free service, the value can be set to nil or false. For
0
@@ -25,7 +39,7 @@ GeoKit::Geocoders::geocoder_us=false
0
 # Geocoder.ca.
0
 # See http://geocoder.ca
0
 # and http://geocoder.ca/?register=1
0
-GeoKit::Geocoders::geocoder_ca=false
0
+GeoKit::Geocoders::geocoder_ca = false
0
 
0
 # This is the order in which the geocoders are called in a failover scenario
0
 # If you only want to use a single geocoder, put a single symbol in the array.
0
@@ -33,4 +47,4 @@ GeoKit::Geocoders::geocoder_ca=false
0
 # Be aware that there are Terms of Use restrictions on how you can use the
0
 # various geocoders. Make sure you read up on relevant Terms of Use for each
0
 # geocoder you are going to use.
0
-GeoKit::Geocoders::provider_order=[:google,:us]
0
\ No newline at end of file
0
+GeoKit::Geocoders::provider_order = [:google,:us]
0
\ No newline at end of file
...
1
2
3
4
5
 
 
 
 
 
 
 
 
 
6
 
 
7
...
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
0
@@ -1,7 +1,13 @@
0
-require File.dirname(__FILE__) + '/lib/geo_kit/defaults'
0
-require File.dirname(__FILE__) + '/lib/geo_kit/acts_as_mappable'
0
-require File.dirname(__FILE__) + '/lib/geo_kit/ip_geocode_lookup'
0
-require File.dirname(__FILE__) + '/lib/geo_kit/geocoders'
0
-require File.dirname(__FILE__) + '/lib/geo_kit/mappable'
0
+# Load modules and classes needed to automatically mix in ActiveRecord and
0
+# ActionController helpers. All other functionality must be explicitly
0
+# required.
0
+require 'geo_kit/defaults'
0
+require 'geo_kit/mappable'
0
+require 'geo_kit/acts_as_mappable'
0
+require 'geo_kit/ip_geocode_lookup'
0
+
0
+# Automatically mix in distance finder support into ActiveRecord classes.
0
 ActiveRecord::Base.send :include, GeoKit::ActsAsMappable
0
+
0
+# Automatically mix in ip geocoding helpers into ActionController classes.
0
 ActionController::Base.send :include, GeoKit::IpGeocodeLookup
...
 
1
2
3
...
1
2
3
4
0
@@ -1,3 +1,4 @@
0
+# Display to the console the contents of the README file.
0
 puts IO.read(File.join(File.dirname(__FILE__), 'README'))
0
 
0
 # Append the contents of api_keys_template to the application's environment.rb file
...
16
17
18
 
 
19
20
21
...
64
65
66
67
68
69
70
71
72
73
74
75
 
76
77
78
 
 
 
 
 
 
 
 
 
79
80
81
...
107
108
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
111
112
...
121
122
123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
125
126
...
142
143
144
145
 
146
147
148
...
16
17
18
19
20
21
22
23
...
66
67
68
 
 
 
 
 
 
 
 
 
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
185
186
187
 
188
189
190
191
0
@@ -16,6 +16,8 @@ module GeoKit
0
   # * find_closest (alias: find_nearest)
0
   # * find_farthest
0
   #
0
+ # Counter methods are available and work similarly to finders.
0
+ #
0
   # If raw SQL is desired, the distance_sql method can be used to obtain SQL appropriate
0
   # to use in a find_by_sql call.
0
   module ActsAsMappable
0
@@ -64,18 +66,19 @@ module GeoKit
0
         # conditions, substitutes the distance sql for the distance column -- this saves
0
         # having to write the gory SQL.
0
         def find(*args)
0
- options = extract_options_from_args!(args)
0
- origin = extract_origin_from_options(options)
0
- units = extract_units_from_options(options)
0
- formula = extract_formula_from_options(options)
0
- add_distance_to_select(options, origin, units, formula) if origin
0
- apply_find_scope(args, options)
0
- apply_distance_scope(options)
0
- substitute_distance_in_conditions(options, origin, units, formula) if origin && options.has_key?(:conditions)
0
- args.push(options)
0
+ prepare_for_find_or_count(:find, args)
0
           super(*args)
0
         end
0
         
0
+ # Extends the existing count method by:
0
+ # - If a mappable instance exists in the options and the distance column exists in the
0
+ # conditions, substitutes the distance sql for the distance column -- this saves
0
+ # having to write the gory SQL.
0
+ def count(*args)
0
+ prepare_for_find_or_count(:count, args)
0
+ super(*args)
0
+ end
0
+
0
         # Finds within a distance radius.
0
         def find_within(distance, options={})
0
           options[:within] = distance
0
@@ -107,6 +110,26 @@ module GeoKit
0
           find(:farthest, options)
0
         end
0
         
0
+ # counts within a distance radius.
0
+ def count_within(distance, options={})
0
+ options[:within] = distance
0
+ count(options)
0
+ end
0
+ alias count_inside count_within
0
+
0
+ # Counts beyond a distance radius.
0
+ def count_beyond(distance, options={})
0
+ options[:beyond] = distance
0
+ count(options)
0
+ end
0
+ alias count_outside count_beyond
0
+
0
+ # Counts according to a range. Accepts inclusive or exclusive ranges.
0
+ def count_by_range(range, options={})
0
+ options[:range] = range
0
+ count(options)
0
+ end
0
+
0
         # Returns the distance calculation to be used as a display column or a condition. This
0
         # is provide for anyone wanting access to the raw SQL.
0
         def distance_sql(origin, units=default_units, formula=default_formula)
0
@@ -121,6 +144,26 @@ module GeoKit
0
 
0
         private
0
         
0
+ # Prepares either a find or a count action by parsing through the options and
0
+ # conditionally adding to the select clause for finders.
0
+ def prepare_for_find_or_count(action, args)
0
+ options = extract_options_from_args!(args)
0
+ # Obtain items affecting distance condition.
0
+ origin = extract_origin_from_options(options)
0
+ units = extract_units_from_options(options)
0
+ formula = extract_formula_from_options(options)
0
+ # Apply select adjustments based upon action.
0
+ add_distance_to_select(options, origin, units, formula) if origin && action == :find
0
+ # Apply distance scoping and perform substitutions.
0
+ apply_distance_scope(options)
0
+ substitute_distance_in_conditions(options, origin, units, formula) if origin && options.has_key?(:conditions)
0
+ # Order by scoping for find action.
0
+ apply_find_scope(args, options) if action == :find
0
+ # Restore options minus the extra options that we used for the
0
+ # GeoKit API.
0
+ args.push(options)
0
+ end
0
+
0
         # Looks for mapping-specific tokens and makes appropriate translations so that the
0
         # original finder has its expected arguments. Resets the the scope argument to
0
         # :first and ensures the limit is set to one.
0
@@ -142,7 +185,7 @@ module GeoKit
0
         def apply_distance_scope(options)
0
           distance_condition = "#{distance_column_name} <= #{options[:within]}" if options.has_key?(:within)
0
           distance_condition = "#{distance_column_name} > #{options[:beyond]}" if options.has_key?(:beyond)
0
- distance_condition = "#{distance_column_name} >= #{options[:range].first} AND #{distance_column_name} <= #{options[:range].last}" if options.has_key?(:range)
0
+ distance_condition = "#{distance_column_name} >= #{options[:range].first} AND #{distance_column_name} <#{'=' unless options[:range].exclude_end?} #{options[:range].last}" if options.has_key?(:range)
0
           [:within, :beyond, :range].each { |option| options.delete(option) } if distance_condition
0
           if distance_condition && options.has_key?(:conditions)
0
             original_conditions = options[:conditions]
...
1
2
3
 
4
5
6
...
15
16
17
 
 
 
 
 
18
19
20
21
22
23
24
 
 
25
26
27
...
50
51
52
 
 
 
 
 
 
 
 
53
54
55
...
57
58
59
 
 
 
 
 
 
60
61
62
...
88
89
90
91
 
92
93
94
...
130
131
132
133
 
 
134
135
136
...
183
184
185
186
 
 
187
188
189
...
223
224
225
226
 
227
228
229
...
255
256
257
258
 
259
260
261
...
309
310
311
312
 
313
314
315
...
1
2
3
4
5
6
7
...
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 
30
31
32
33
34
...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
...
72
73
74
75
76
77
78
79
80
81
82
83
...
109
110
111
 
112
113
114
115
...
151
152
153
 
154
155
156
157
158
...
205
206
207
 
208
209
210
211
212
...
246
247
248
 
249
250
251
252
...
278
279
280
 
281
282
283
284
...
332
333
334
 
335
336
337
338
0
@@ -1,6 +1,7 @@
0
 require 'net/http'
0
 require 'rexml/document'
0
 require 'yaml'
0
+require 'timeout'
0
 
0
 module GeoKit
0
   # Contains a set of geocoders which can be used independently if desired. The list contains:
0
@@ -15,13 +16,19 @@ module GeoKit
0
   # Some configuration is required for these geocoders and can be located in the environment
0
   # configuration files.
0
   module Geocoders
0
+ @@proxy_addr = nil
0
+ @@proxy_port = nil
0
+ @@proxy_user = nil
0
+ @@proxy_pass = nil
0
+ @@timeout = nil
0
     @@yahoo = 'REPLACE_WITH_YOUR_YAHOO_KEY'
0
     @@google = 'REPLACE_WITH_YOUR_GOOGLE_KEY'
0
     @@geocoder_us = false
0
     @@geocoder_ca = false
0
     @@provider_order = [:google,:us]
0
     
0
- [:yahoo, :google, :geocoder_us, :geocoder_ca, :provider_order].each do |sym|
0
+ [:yahoo, :google, :geocoder_us, :geocoder_ca, :provider_order, :timeout,
0
+ :proxy_addr, :proxy_port, :proxy_user, :proxy_pass].each do |sym|
0
       class_eval <<-EOS, __FILE__, __LINE__
0
         def self.#{sym}
0
           if defined?(#{sym.to_s.upcase})
0
@@ -50,6 +57,14 @@ module GeoKit
0
         res = do_geocode(address)
0
         return res.success ? res : GeoLoc.new
0
       end
0
+
0
+ # Call the geocoder service using the timeout if configured.
0
+ def self.call_geocoder_service(url)
0
+ timeout(GeoKit::Geocoders::timeout) { return self.do_get(url) } if GeoKit::Geocoders::timeout
0
+ return self.do_get(url)
0
+ rescue TimeoutError
0
+ return nil
0
+ end
0
 
0
       protected
0
 
0
@@ -57,6 +72,12 @@ module GeoKit
0
       
0
       private
0
       
0
+ # Wraps the geocoder call around a proxy if necessary.
0
+ def self.do_get(url)
0
+ return Net::HTTP::Proxy(GeoKit::Geocoders::proxy_addr, GeoKit::Geocoders::proxy_port,
0
+ GeoKit::Geocoders::proxy_user, GeoKit::Geocoders::proxy_pass).get_response(URI.parse(url))
0
+ end
0
+
0
       # Adds subclass' geocode method making it conveniently available through
0
       # the base class.
0
       def self.inherited(clazz)
0
@@ -88,7 +109,7 @@ module GeoKit
0
       def self.do_geocode(address)
0
         raise ArgumentError('Geocoder.ca requires a GeoLoc argument') unless address.is_a?(GeoLoc)
0
         url = construct_request(address)
0
- res = Net::HTTP.get_response(URI.parse(url))
0
+ res = self.call_geocoder_service(url)
0
         return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
0
         xml = res.body
0
         logger.debug "Geocoder.ca geocoding. Address: #{address}. Result: #{xml}"
0
@@ -130,7 +151,8 @@ module GeoKit
0
       # Template method which does the geocode lookup.
0
       def self.do_geocode(address)
0
         address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
0
- res = Net::HTTP.get_response(URI.parse("http://maps.google.com/maps/geo?q=#{CGI.escape(address_str)}&output=xml&key=#{GeoKit::Geocoders::google}&oe=utf-8"))
0
+ res = self.call_geocoder_service("http://maps.google.com/maps/geo?q=#{CGI.escape(address_str)}&output=xml&key=#{GeoKit::Geocoders::google}&oe=utf-8")
0
+# res = Net::HTTP.get_response(URI.parse("http://maps.google.com/maps/geo?q=#{CGI.escape(address_str)}&output=xml&key=#{GeoKit::Geocoders::google}&oe=utf-8"))
0
         return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
0
         xml=res.body
0
         logger.debug "Google geocoding. Address: #{address}. Result: #{xml}"
0
@@ -183,7 +205,8 @@ module GeoKit
0
       # parameter does not match an ip address.
0
       def self.do_geocode(ip)
0
         return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
0
- response = Net::HTTP.get_response('api.hostip.info', "/get_html.php?ip=#{ip}&position=true")
0
+ url = "http://api.hostip.info/get_html.php?ip=#{ip}&position=true"
0
+ response = self.call_geocoder_service(url)
0
         response.is_a?(Net::HTTPSuccess) ? parse_body(response.body) : GeoLoc.new
0
       rescue
0
         logger.error "Caught an error during HostIp geocoding call: "+$!
0
@@ -223,7 +246,7 @@ module GeoKit
0
       def self.do_geocode(address)
0
         address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
0
         url = "http://"+(GeoKit::Geocoders::geocoder_us || '')+"geocoder.us/service/csv/geocode?address=#{CGI.escape(address_str)}"
0
- res = Net::HTTP.get_response(URI.parse(url))
0
+ res = self.call_geocoder_service(url)
0
         return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
0
         data = res.body
0
         logger.debug "Geocoder.us geocoding. Address: #{address}. Result: #{data}"
0
@@ -255,7 +278,7 @@ module GeoKit
0
       def self.do_geocode(address)
0
         address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
0
         url="http://api.local.yahoo.com/MapsService/V1/geocode?appid=#{GeoKit::Geocoders::yahoo}&location=#{CGI.escape(address_str)}"
0
- res = Net::HTTP.get_response(URI.parse(url))
0
+ res = self.call_geocoder_service(url)
0
         return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
0
         xml = res.body
0
         doc = REXML::Document.new(xml)
0
@@ -309,7 +332,7 @@ module GeoKit
0
       def self.do_geocode(address)
0
         GeoKit::Geocoders::provider_order.each do |provider|
0
           begin
0
- klass=GeoKit::Geocoders.const_get "#{provider.to_s.capitalize}Geocoder"
0
+ klass = GeoKit::Geocoders.const_get "#{provider.to_s.capitalize}Geocoder"
0
             res = klass.send :geocode, address
0
             return res if res.success
0
           rescue
...
37
38
39
40
41
 
 
42
43
44
45
 
46
47
48
49
...
37
38
39
 
 
40
41
42
 
 
 
43
44
45
46
47
0
@@ -37,12 +37,10 @@ module GeoKit
0
       return location.success ? location : nil
0
     end
0
     
0
- # Either returns the real ip address or a fake one in the case where
0
- # doing live testing via localhost.
0
+ # Returns the real ip address, though this could be the localhost ip
0
+ # address. No special handling here anymore.
0
     def get_ip_address
0
-
0
- address = request.remote_ip
0
- address == '127.0.0.1' ? '12.215.42.19' : address
0
+ request.remote_ip
0
     end
0
   end
0
 end
0
\ No newline at end of file
...
 
 
1
2
3
...
1
2
3
4
5
0
@@ -1,3 +1,5 @@
0
+require 'geo_kit/defaults'
0
+
0
 module GeoKit
0
   # Contains class and instance methods providing distance calcuation services. This
0
   # module is meant to be mixed into classes containing lat and lng attributes where
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
19
20
21
...
30
31
32
 
33
34
35
...
47
48
49
50
 
 
 
 
 
51
52
53
...
70
71
72
 
 
73
74
75
...
111
112
113
 
 
114
115
116
117
118
 
 
119
120
121
122
123
 
 
124
125
126
127
128
 
 
 
129
130
131
132
133
 
 
134
135
136
137
138
 
 
139
140
141
142
143
 
 
144
145
146
147
148
 
 
149
150
151
152
153
 
 
154
155
156
157
158
 
 
159
160
161
162
163
 
 
164
165
166
167
168
 
 
169
170
171
172
173
 
 
 
 
 
 
 
 
 
174
175
176
...
207
208
209
 
 
210
211
212
213
214
 
 
215
216
217
218
219
 
 
220
221
222
223
224
 
 
 
225
226
227
...
244
245
246
 
 
 
247
248
249
250
251
252
 
 
 
253
254
255
256
257
258
 
 
 
259
260
261
262
263
264
 
 
 
265
266
267
268
269
270
 
 
 
271
272
273
...
296
297
298
 
 
299
300
301
302
303
 
 
304
305
306
307
308
 
 
309
310
311
312
313
 
 
314
315
316
317
318
 
 
319
320
321
322
323
 
 
324
325
326
327
328
 
 
 
329
330
331
332
333
 
 
334
335
336
...
352
353
354
 
 
355
356
...
 
 
 
 
 
 
1
2
 
 
 
 
 
 
 
 
 
 
3
4
5
6
...
15
16
17
18
19
20
21
...
33
34
35
 
36
37
38
39
40
41
42
43
...
60
61
62
63
64
65
66
67
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
 
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
 
255
256
257
258
259
260
...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
 
388
389
390
391
392
393
394
395
396
397
398
399
400
...
416
417
418
419
420
421
422
0
@@ -1,21 +1,6 @@
0
-$:.unshift(File.dirname(__FILE__) + '/../lib')
0
-require 'test/unit'
0
-require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
0
-require 'breakpoint'
0
-require 'active_record/fixtures'
0
-require 'action_controller/test_process'
0
 require 'rubygems'
0
 require 'mocha'
0
-
0
-# Config database connection.
0
-config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
0
-ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
0
-ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'mysql'])
0
-#ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'postgresql'])
0
-
0
-
0
-# Establish test tables.
0
-load(File.dirname(__FILE__) + "/schema.rb")
0
+require File.join(File.dirname(__FILE__), 'test_helper')
0
 
0
 GeoKit::Geocoders::provider_order=[:google,:us]
0
 
0
@@ -30,6 +15,7 @@ class Location < ActiveRecord::Base #:nodoc: all
0
   acts_as_mappable
0
 end
0
 
0
+# Uses deviations from conventions.
0
 class CustomLocation < ActiveRecord::Base #:nodoc: all
0
   belongs_to :company
0
   acts_as_mappable :distance_column_name => 'dist',
0
@@ -47,7 +33,11 @@ class ActsAsMappableTest < Test::Unit::TestCase #:nodoc: all
0
     
0
   LOCATION_A_IP = "217.10.83.5"
0
     
0
- self.fixture_path = File.dirname(__FILE__) + '/fixtures'
0
+ #self.fixture_path = File.dirname(__FILE__) + '/fixtures'
0
+ #self.fixture_path = RAILS_ROOT + '/test/fixtures/'
0
+ #puts "Rails Path #{RAILS_ROOT}"
0
+ #puts "Fixture Path: #{self.fixture_path}"
0
+ #self.fixture_path = ' /Users/bill_eisenhauer/Projects/geokit_test/test/fixtures/'
0
   fixtures :companies, :locations, :custom_locations
0
 
0
   def setup
0
@@ -70,6 +60,8 @@ class ActsAsMappableTest < Test::Unit::TestCase #:nodoc: all
0
     Location.default_units = :kms
0
     locations = Location.find(:all, :origin => @loc_a, :conditions => "distance < 3.97")
0
     assert_equal 5, locations.size
0
+ locations = Location.count(:origin => @loc_a, :conditions => "distance < 3.97")
0
+ assert_equal 5, locations
0
     Location.default_units = :miles
0
   end
0
   
0
@@ -111,66 +103,99 @@ class ActsAsMappableTest < Test::Unit::TestCase #:nodoc: all
0
   def test_find_with_distance_condition
0
     locations = Location.find(:all, :origin => @loc_a, :conditions => "distance < 3.97")
0
     assert_equal 5, locations.size
0
+ locations = Location.count(:origin => @loc_a, :conditions => "distance < 3.97")
0
+ assert_equal 5, locations
0
   end
0
   
0
   def test_find_with_distance_condition_with_units_override
0
     locations = Location.find(:all, :origin => @loc_a, :units => :kms, :conditions => "distance < 6.387")
0
     assert_equal 5, locations.size
0
+ locations = Location.count(:origin => @loc_a, :units => :kms, :conditions => "distance < 6.387")
0
+ assert_equal 5, locations
0
   end
0
   
0
   def test_find_with_distance_condition_with_formula_override
0
     locations = Location.find(:all, :origin => @loc_a, :formula => :flat, :conditions => "distance < 6.387")
0
     assert_equal 6, locations.size
0
+ locations = Location.count(:origin => @loc_a, :formula => :flat, :conditions => "distance < 6.387")
0
+ assert_equal 6, locations
0
   end
0
   
0
   def test_find_within
0
     locations = Location.find_within(3.97, :origin => @loc_a)
0
- assert_equal 5, locations.size
0
+ assert_equal 5, locations.size
0
+ locations = Location.count_within(3.97, :origin => @loc_a)
0
+ assert_equal 5, locations
0
   end
0
   
0
   def test_find_within_with_token
0
     locations = Location.find(:all, :within => 3.97, :origin => @loc_a)
0
     assert_equal 5, locations.size
0
+ locations = Location.count(:within => 3.97, :origin => @loc_a)
0
+ assert_equal 5, locations
0
   end
0
   
0
   def test_find_within_with_coordinates
0
     locations = Location.find_within(3.97, :origin =>[@loc_a.lat,@loc_a.lng])
0
     assert_equal 5, locations.size
0
+ locations = Location.count_within(3.97, :origin =>[@loc_a.lat,@loc_a.lng])
0
+ assert_equal 5, locations
0
   end
0
   
0
   def test_find_with_compound_condition
0
     locations = Location.find(:all, :origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
0
     assert_equal 2, locations.size
0
+ locations = Location.count(:origin => @loc_a, :conditions => "distance < 5 and city = 'Coppell'")
0
+ assert_equal 2, locations
0
   end
0
   
0
   def test_find_with_s