geocoder 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of geocoder might be problematic. Click here for more details.

data/CHANGELOG.rdoc CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  Per-release changes to Geocoder.
4
4
 
5
+ == 1.1.1 (2012 Feb 16)
6
+
7
+ * Add distance_from_sql class method to geocoded class (thanks github.com/dwilkie).
8
+ * Add OverQueryLimitError and raise when relevant for Google lookup.
9
+ * Fix: don't cache API data if response indicates an error.
10
+ * Fix: within_bounding_box now uses correct lat/lon DB columns (thanks github.com/kongo).
11
+ * Fix: error accessing city in some cases with Yandex result (thanks github.com/kor6n and sld).
12
+
5
13
  == 1.1.0 (2011 Dec 3)
6
14
 
7
15
  * A block passed to geocoded_by is now always executed, even if the geocoding service returns no results. This means you need to make sure you have results before trying to assign data to your object.
@@ -120,14 +120,14 @@ module Geocoder
120
120
  # Parses a raw search result (returns hash or array).
121
121
  #
122
122
  def parse_raw_data(raw_data)
123
- if defined?(ActiveSupport::JSON)
124
- ActiveSupport::JSON.decode(raw_data)
125
- else
126
- begin
123
+ begin
124
+ if defined?(ActiveSupport::JSON)
125
+ ActiveSupport::JSON.decode(raw_data)
126
+ else
127
127
  JSON.parse(raw_data)
128
- rescue
129
- warn "Geocoding API's response was not valid JSON."
130
128
  end
129
+ rescue
130
+ warn "Geocoding API's response was not valid JSON."
131
131
  end
132
132
  end
133
133
 
@@ -146,15 +146,16 @@ module Geocoder
146
146
  timeout(Geocoder::Configuration.timeout) do
147
147
  url = query_url(query, reverse)
148
148
  uri = URI.parse(url)
149
- unless cache and response = cache[url]
149
+ unless cache and body = cache[url]
150
150
  client = http_client.new(uri.host, uri.port)
151
151
  client.use_ssl = true if Geocoder::Configuration.use_https
152
- response = client.get(uri.request_uri).body
153
- if cache
154
- cache[url] = response
152
+ response = client.get(uri.request_uri)
153
+ body = response.body
154
+ if cache and (200..399).include?(response.code.to_i)
155
+ cache[url] = body
155
156
  end
156
157
  end
157
- response
158
+ body
158
159
  end
159
160
  end
160
161
 
@@ -14,8 +14,10 @@ module Geocoder::Result
14
14
  def city
15
15
  if state.empty?
16
16
  address_details['Locality']['LocalityName']
17
- else
17
+ elsif sub_state.empty?
18
18
  address_details['AdministrativeArea']['Locality']['LocalityName']
19
+ else
20
+ address_details['AdministrativeArea']['SubAdministrativeArea']['Locality']['LocalityName']
19
21
  end
20
22
  end
21
23
 
@@ -35,6 +37,14 @@ module Geocoder::Result
35
37
  end
36
38
  end
37
39
 
40
+ def sub_state
41
+ if !state.empty? and address_details['AdministrativeArea']['SubAdministrativeArea']
42
+ address_details['AdministrativeArea']['SubAdministrativeArea']['SubAdministrativeAreaName']
43
+ else
44
+ ""
45
+ end
46
+ end
47
+
38
48
  def state_code
39
49
  ""
40
50
  end
@@ -50,11 +50,11 @@ module Geocoder::Store
50
50
  scope :within_bounding_box, lambda{ |bounds|
51
51
  sw_lat, sw_lng, ne_lat, ne_lng = bounds.flatten if bounds
52
52
  return where(:id => false) unless sw_lat && sw_lng && ne_lat && ne_lng
53
- spans = "latitude BETWEEN #{sw_lat} AND #{ne_lat} AND "
53
+ spans = "#{geocoder_options[:latitude]} BETWEEN #{sw_lat} AND #{ne_lat} AND "
54
54
  spans << if sw_lng > ne_lng # Handle a box that spans 180
55
- "longitude BETWEEN #{sw_lng} AND 180 OR longitude BETWEEN -180 AND #{ne_lng}"
55
+ "#{geocoder_options[:longitude]} BETWEEN #{sw_lng} AND 180 OR #{geocoder_options[:longitude]} BETWEEN -180 AND #{ne_lng}"
56
56
  else
57
- "longitude BETWEEN #{sw_lng} AND #{ne_lng}"
57
+ "#{geocoder_options[:longitude]} BETWEEN #{sw_lng} AND #{ne_lng}"
58
58
  end
59
59
  { :conditions => spans }
60
60
  }
@@ -66,6 +66,11 @@ module Geocoder::Store
66
66
  #
67
67
  module ClassMethods
68
68
 
69
+ def distance_from_sql(location, *args)
70
+ latitude, longitude = Geocoder::Calculations.extract_coordinates(location)
71
+ distance_from_sql_options(latitude, longitude, *args) if latitude and longitude
72
+ end
73
+
69
74
  private # ----------------------------------------------------------------
70
75
 
71
76
  ##
@@ -92,14 +97,19 @@ module Geocoder::Store
92
97
  end
93
98
  end
94
99
 
100
+ def distance_from_sql_options(latitude, longitude, options = {})
101
+ if connection.adapter_name.match /sqlite/i
102
+ approx_distance_from_sql(latitude, longitude, options)
103
+ else
104
+ full_distance_from_sql(latitude, longitude, options)
105
+ end
106
+ end
107
+
95
108
  ##
96
109
  # Scope options hash for use with a database that supports POWER(),
97
110
  # SQRT(), PI(), and trigonometric functions SIN(), COS(), ASIN(),
98
111
  # ATAN2(), DEGREES(), and RADIANS().
99
112
  #
100
- # Distance calculations based on the excellent tutorial at:
101
- # http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
102
- #
103
113
  # Bearing calculation based on:
104
114
  # http://www.beginningspatial.com/calculating_bearing_one_point_another
105
115
  #
@@ -128,11 +138,8 @@ module Geocoder::Store
128
138
  ")) + 360 " +
129
139
  "AS decimal) % 360"
130
140
  end
131
- earth = Geocoder::Calculations.earth_radius(options[:units] || :mi)
132
- distance = "#{earth} * 2 * ASIN(SQRT(" +
133
- "POWER(SIN((#{latitude} - #{lat_attr}) * PI() / 180 / 2), 2) + " +
134
- "COS(#{latitude} * PI() / 180) * COS(#{lat_attr} * PI() / 180) * " +
135
- "POWER(SIN((#{longitude} - #{lon_attr}) * PI() / 180 / 2), 2) ))"
141
+
142
+ distance = full_distance_from_sql(latitude, longitude, options)
136
143
  conditions = ["#{distance} <= ?", radius]
137
144
  default_near_scope_options(latitude, longitude, radius, options).merge(
138
145
  :select => "#{options[:select] || "#{table_name}.*"}, " +
@@ -142,6 +149,36 @@ module Geocoder::Store
142
149
  )
143
150
  end
144
151
 
152
+
153
+ # Distance calculations based on the excellent tutorial at:
154
+ # http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
155
+
156
+ def full_distance_from_sql(latitude, longitude, options)
157
+ lat_attr = geocoder_options[:latitude]
158
+ lon_attr = geocoder_options[:longitude]
159
+
160
+ earth = Geocoder::Calculations.earth_radius(options[:units] || :mi)
161
+
162
+ "#{earth} * 2 * ASIN(SQRT(" +
163
+ "POWER(SIN((#{latitude} - #{table_name}.#{lat_attr}) * PI() / 180 / 2), 2) + " +
164
+ "COS(#{latitude} * PI() / 180) * COS(#{table_name}.#{lat_attr} * PI() / 180) * " +
165
+ "POWER(SIN((#{longitude} - #{table_name}.#{lon_attr}) * PI() / 180 / 2), 2) ))"
166
+ end
167
+
168
+ def approx_distance_from_sql(latitude, longitude, options)
169
+ lat_attr = geocoder_options[:latitude]
170
+ lon_attr = geocoder_options[:longitude]
171
+
172
+ dx = Geocoder::Calculations.longitude_degree_distance(30, options[:units] || :mi)
173
+ dy = Geocoder::Calculations.latitude_degree_distance(options[:units] || :mi)
174
+
175
+ # sin of 45 degrees = average x or y component of vector
176
+ factor = Math.sin(Math::PI / 4)
177
+
178
+ "(#{dy} * ABS(#{table_name}.#{lat_attr} - #{latitude}) * #{factor}) + " +
179
+ "(#{dx} * ABS(#{table_name}.#{lon_attr} - #{longitude}) * #{factor})"
180
+ end
181
+
145
182
  ##
146
183
  # Scope options hash for use with a database without trigonometric
147
184
  # functions, like SQLite. Approach is to find objects within a square
@@ -166,14 +203,8 @@ module Geocoder::Store
166
203
  bearing = false
167
204
  end
168
205
 
169
- dx = Geocoder::Calculations.longitude_degree_distance(30, options[:units] || :mi)
170
- dy = Geocoder::Calculations.latitude_degree_distance(options[:units] || :mi)
171
-
172
- # sin of 45 degrees = average x or y component of vector
173
- factor = Math.sin(Math::PI / 4)
206
+ distance = approx_distance_from_sql(latitude, longitude, options)
174
207
 
175
- distance = "(#{dy} * ABS(#{lat_attr} - #{latitude}) * #{factor}) + " +
176
- "(#{dx} * ABS(#{lon_attr} - #{longitude}) * #{factor})"
177
208
  b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
178
209
  conditions = [
179
210
  "#{lat_attr} BETWEEN ? AND ? AND #{lon_attr} BETWEEN ? AND ?"] +
@@ -235,11 +266,12 @@ module Geocoder::Store
235
266
  #
236
267
  def reverse_geocode
237
268
  do_lookup(true) do |o,rs|
238
- r = rs.first
239
- unless r.address.nil?
240
- o.send :write_attribute, self.class.geocoder_options[:fetched_address], r.address
269
+ if r = rs.first
270
+ unless r.address.nil?
271
+ o.send :write_attribute, self.class.geocoder_options[:fetched_address], r.address
272
+ end
273
+ r.address
241
274
  end
242
- r.address
243
275
  end
244
276
  end
245
277
 
@@ -71,11 +71,12 @@ module Geocoder::Store
71
71
  #
72
72
  def reverse_geocode
73
73
  do_lookup(true) do |o,rs|
74
- r = rs.first
75
- unless r.address.nil?
76
- o.send :write_attribute, self.class.geocoder_options[:fetched_address], r.address
74
+ if r = rs.first
75
+ unless r.address.nil?
76
+ o.send :write_attribute, self.class.geocoder_options[:fetched_address], r.address
77
+ end
78
+ r.address
77
79
  end
78
- r.address
79
80
  end
80
81
  end
81
82
  end
@@ -1,3 +1,3 @@
1
1
  module Geocoder
2
- VERSION = "1.1.0"
2
+ VERSION = "1.1.1"
3
3
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: geocoder
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.1.0
5
+ version: 1.1.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Alex Reisner
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-12-03 00:00:00 -05:00
13
+ date: 2012-02-16 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies: []
16
16