geocoder 1.0.5 → 1.1.0

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,9 +2,22 @@
2
2
 
3
3
  Per-release changes to Geocoder.
4
4
 
5
+ == 1.1.0 (2011 Dec 3)
6
+
7
+ * 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.
8
+ * Fix issues with joins and row counts (issues #49, 86, and 108) by not using GROUP BY clause with ActiveRecord scopes.
9
+ * Fix incorrect object ID when join used (fixes issue #140).
10
+ * Fix calculation of bounding box which spans 180th meridian (thanks github.com/hwuethrich).
11
+ * Add within_bounding_box scope for ActiveRecord-based models (thanks github.com/gavinhughes and dbloete).
12
+ * Add option to raise Geocoder::OverQueryLimitError for Google geocoding service.
13
+ * Add support for Nominatim geocoding service (thanks github.com/wranglerdriver).
14
+ * Add support for API key to Geocoder.ca geocoding service (thanks github.com/ryanLonac).
15
+ * Add support for state to Yandex results (thanks github.com/tipugin).
16
+
5
17
  == 1.0.5 (2011 Oct 26)
6
18
 
7
19
  * Fix error with `rake assets:precompile` (thanks github.com/Sush).
20
+ * Fix HTTPS support (thanks github.com/rsanheim).
8
21
  * Improve cache interface.
9
22
 
10
23
  == 1.0.4 (2011 Sep 18)
data/README.rdoc CHANGED
@@ -50,7 +50,7 @@ Next, your model must tell Geocoder which method returns your object's geocodabl
50
50
 
51
51
  For reverse geocoding, tell Geocoder which attributes store latitude and longitude:
52
52
 
53
- reverse_geocoded_by :lat, :lon
53
+ reverse_geocoded_by :latitude, :longitude
54
54
  after_validation :reverse_geocode # auto-fetch address
55
55
 
56
56
  === Mongoid
@@ -190,7 +190,7 @@ If your model has +street+, +city+, +state+, and +country+ attributes you might
190
190
 
191
191
  For reverse geocoding you can also specify an alternate name attribute where the address will be stored, for example:
192
192
 
193
- reverse_geocoded_by :lat, :lon, :address => :location # ActiveRecord
193
+ reverse_geocoded_by :latitude, :longitude, :address => :location # ActiveRecord
194
194
  reverse_geocoded_by :coordinates, :address => :loc # MongoDB
195
195
 
196
196
 
@@ -198,7 +198,7 @@ For reverse geocoding you can also specify an alternate name attribute where the
198
198
 
199
199
  So far we have looked at shortcuts for assigning geocoding results to object attributes. However, if you need to do something fancy you can skip the auto-assignment by providing a block (takes the object to be geocoded and an array of <tt>Geocoder::Result</tt> objects) in which you handle the parsed geocoding result any way you like, for example:
200
200
 
201
- reverse_geocoded_by :lat, :lon do |obj,results|
201
+ reverse_geocoded_by :latitude, :longitude do |obj,results|
202
202
  if geo = results.first
203
203
  obj.city = geo.city
204
204
  obj.zipcode = geo.postal_code
@@ -294,6 +294,17 @@ Documentation:: http://msdn.microsoft.com/en-us/library/ff701715.aspx
294
294
  Terms of Service:: http://www.microsoft.com/maps/product/terms.html
295
295
  Limitations:: No country codes or state names. Must be used on "public-facing, non-password protected web sites," "in conjunction with Bing Maps or an application that integrates Bing Maps."
296
296
 
297
+ ==== Nominatim (<tt>:nominatim</tt>)
298
+
299
+ API key:: none
300
+ Quota:: 1 request/second
301
+ Region:: world
302
+ SSL support:: no
303
+ Languages:: ?
304
+ Documentation:: http://wiki.openstreetmap.org/wiki/Nominatim
305
+ Terms of Service:: http://wiki.openstreetmap.org/wiki/Nominatim_usage_policy
306
+ Limitations:: Please limit request rate to 1 per second and include your contact information in User-Agent headers. Data licensed under CC-BY-SA (you must provide attribution).
307
+
297
308
  ==== Yandex (<tt>:yandex</tt>)
298
309
 
299
310
  API key:: required
data/Rakefile CHANGED
@@ -4,11 +4,17 @@ Bundler::GemHelper.install_tasks
4
4
  require 'rake/testtask'
5
5
  Rake::TestTask.new(:test) do |test|
6
6
  test.libs << 'lib' << 'test'
7
- test.pattern = 'test/**/*_test.rb'
7
+ test.pattern = 'test/*_test.rb'
8
8
  test.verbose = true
9
9
  end
10
10
 
11
- task :default => :test
11
+ Rake::TestTask.new(:integration) do |test|
12
+ test.libs << 'lib' << 'test'
13
+ test.pattern = 'test/integration/*_test.rb'
14
+ test.verbose = true
15
+ end
16
+
17
+ task :default => [:test, :integration]
12
18
 
13
19
  require 'rdoc/task'
14
20
  Rake::RDocTask.new do |rdoc|
data/lib/geocoder.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "geocoder/configuration"
2
2
  require "geocoder/calculations"
3
+ require "geocoder/exceptions"
3
4
  require "geocoder/cache"
4
5
  require "geocoder/request"
5
6
  require "geocoder/models/active_record"
@@ -56,7 +57,7 @@ module Geocoder
56
57
  # All street address lookups, default first.
57
58
  #
58
59
  def street_lookups
59
- [:google, :google_premier, :yahoo, :bing, :geocoder_ca, :yandex]
60
+ [:google, :google_premier, :yahoo, :bing, :geocoder_ca, :yandex, :nominatim]
60
61
  end
61
62
 
62
63
  ##
@@ -67,11 +68,6 @@ module Geocoder
67
68
  end
68
69
 
69
70
 
70
- # exception classes
71
- class Error < StandardError; end
72
- class ConfigurationError < Error; end
73
-
74
-
75
71
  private # -----------------------------------------------------------------
76
72
 
77
73
  ##
data/lib/geocoder/cli.rb CHANGED
@@ -13,8 +13,13 @@ module Geocoder
13
13
  opts.separator "\nOptions: "
14
14
 
15
15
  opts.on("-k <key>", "--key <key>",
16
- "Key for geocoding API (optional for most)") do |key|
17
- Geocoder::Configuration.api_key = key
16
+ "Key for geocoding API (optional for most). For Google Premier use 'key client channel' separated by spaces") do |key|
17
+ premier_key = key.split(' ')
18
+ if premier_key.length == 3
19
+ Geocoder::Configuration.api_key = premier_key
20
+ else
21
+ Geocoder::Configuration.api_key = key
22
+ end
18
23
  end
19
24
 
20
25
  opts.on("-l <language>", "--language <language>",
@@ -0,0 +1,11 @@
1
+ module Geocoder
2
+
3
+ class Error < StandardError
4
+ end
5
+
6
+ class ConfigurationError < Error
7
+ end
8
+
9
+ class OverQueryLimitError < Error
10
+ end
11
+ end
@@ -91,13 +91,17 @@ module Geocoder
91
91
  end
92
92
 
93
93
  ##
94
- # Raise exception instead of warning for specified exceptions.
94
+ # Raise exception if configuration specifies it should be raised.
95
+ # Return false if exception not raised.
95
96
  #
96
- def raise_error(err)
97
- raise err if Geocoder::Configuration.always_raise.include?(err.class)
97
+ def raise_error(error, message = nil)
98
+ if Geocoder::Configuration.always_raise.include?(error.class)
99
+ raise error, message
100
+ else
101
+ false
102
+ end
98
103
  end
99
104
 
100
-
101
105
  ##
102
106
  # Returns a parsed search result (Ruby hash).
103
107
  #
@@ -141,8 +145,11 @@ module Geocoder
141
145
  def fetch_raw_data(query, reverse = false)
142
146
  timeout(Geocoder::Configuration.timeout) do
143
147
  url = query_url(query, reverse)
148
+ uri = URI.parse(url)
144
149
  unless cache and response = cache[url]
145
- response = http_client.get_response(URI.parse(url)).body
150
+ client = http_client.new(uri.host, uri.port)
151
+ client.use_ssl = true if Geocoder::Configuration.use_https
152
+ response = client.get(uri.request_uri).body
146
153
  if cache
147
154
  cache[url] = response
148
155
  end
@@ -22,7 +22,8 @@ module Geocoder::Lookup
22
22
  params = {
23
23
  :geoit => "xml",
24
24
  :jsonp => 1,
25
- :callback => "test"
25
+ :callback => "test",
26
+ :auth => Geocoder::Configuration.api_key
26
27
  }
27
28
  if reverse
28
29
  lat,lon = query.split(',')
@@ -15,7 +15,8 @@ module Geocoder::Lookup
15
15
  case doc['status']; when "OK" # OK status implies >0 results
16
16
  return doc['results']
17
17
  when "OVER_QUERY_LIMIT"
18
- warn "Google Geocoding API error: over query limit."
18
+ raise_error(Geocoder::OverQueryLimitError) ||
19
+ warn("Google Geocoding API error: over query limit.")
19
20
  when "REQUEST_DENIED"
20
21
  warn "Google Geocoding API error: request denied."
21
22
  when "INVALID_REQUEST"
@@ -0,0 +1,37 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/nominatim"
3
+
4
+ module Geocoder::Lookup
5
+ class Nominatim < Base
6
+
7
+ def map_link_url(coordinates)
8
+ "http://www.openstreetmap.org/?lat=#{coordinates[0]}&lon=#{coordinates[1]}&zoom=15&layers=M"
9
+ end
10
+
11
+ private # ---------------------------------------------------------------
12
+
13
+ def results(query, reverse = false)
14
+ return [] unless doc = fetch_data(query, reverse)
15
+ doc.is_a?(Array) ? doc : [doc]
16
+ end
17
+
18
+ def query_url(query, reverse = false)
19
+ params = {
20
+ :format => "json",
21
+ :polygon => "1",
22
+ :addressdetails => "1",
23
+ :"accept-language" => Geocoder::Configuration.language
24
+ }
25
+ if (reverse)
26
+ method = 'reverse'
27
+ parts = query.split(/\s*,\s*/);
28
+ params[:lat] = parts[0]
29
+ params[:lon] = parts[1]
30
+ else
31
+ method = 'search'
32
+ params[:q] = query
33
+ end
34
+ "http://nominatim.openstreetmap.org/#{method}?" + hash_to_query(params)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,67 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Nominatim < Base
5
+
6
+ def house_number
7
+ @data['address']['house_number']
8
+ end
9
+
10
+ def address
11
+ @data['display_name']
12
+ end
13
+
14
+ def street
15
+ @data['address']['road']
16
+ end
17
+
18
+ def city
19
+ @data['address']['city']
20
+ end
21
+
22
+ def village
23
+ @data['address']['villiage']
24
+ end
25
+
26
+ def town
27
+ @data['address']['town']
28
+ end
29
+
30
+ def state
31
+ @data['address']['state']
32
+ end
33
+
34
+ alias_method :state_code, :state
35
+
36
+ def postal_code
37
+ @data['address']['postcode']
38
+ end
39
+
40
+ def county
41
+ @data['address']['county']
42
+ end
43
+
44
+ def country
45
+ @data['address']['country']
46
+ end
47
+
48
+ def country_code
49
+ @data['address']['country_code']
50
+ end
51
+
52
+ def coordinates
53
+ [@data['lat'].to_f, @data['lon'].to_f]
54
+ end
55
+
56
+ def self.response_attributes
57
+ %w[place_id, osm_type, osm_id, boundingbox, license,
58
+ polygonpoints, display_name, class, type, stadium, suburb]
59
+ end
60
+
61
+ response_attributes.each do |a|
62
+ define_method a do
63
+ @data[a]
64
+ end
65
+ end
66
+ end
67
+ end
@@ -12,7 +12,11 @@ module Geocoder::Result
12
12
  end
13
13
 
14
14
  def city
15
- address_details['Locality']['LocalityName']
15
+ if state.empty?
16
+ address_details['Locality']['LocalityName']
17
+ else
18
+ address_details['AdministrativeArea']['Locality']['LocalityName']
19
+ end
16
20
  end
17
21
 
18
22
  def country
@@ -24,7 +28,11 @@ module Geocoder::Result
24
28
  end
25
29
 
26
30
  def state
27
- ""
31
+ if address_details['AdministrativeArea']
32
+ address_details['AdministrativeArea']['AdministrativeAreaName']
33
+ else
34
+ ""
35
+ end
28
36
  end
29
37
 
30
38
  def state_code
@@ -39,6 +39,25 @@ module Geocoder::Store
39
39
  where(:id => false) # no results if no lat/lon given
40
40
  end
41
41
  }
42
+
43
+
44
+ ##
45
+ # Find all objects within the area of a given bounding box.
46
+ # Bounds must be an array of locations specifying the southwest
47
+ # corner followed by the northeast corner of the box
48
+ # (<tt>[[sw_lat, sw_lon], [ne_lat, ne_lon]]</tt>).
49
+ #
50
+ scope :within_bounding_box, lambda{ |bounds|
51
+ sw_lat, sw_lng, ne_lat, ne_lng = bounds.flatten if bounds
52
+ return where(:id => false) unless sw_lat && sw_lng && ne_lat && ne_lng
53
+ spans = "latitude BETWEEN #{sw_lat} AND #{ne_lat} AND "
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}"
56
+ else
57
+ "longitude BETWEEN #{sw_lng} AND #{ne_lng}"
58
+ end
59
+ { :conditions => spans }
60
+ }
42
61
  end
43
62
  end
44
63
 
@@ -114,12 +133,12 @@ module Geocoder::Store
114
133
  "POWER(SIN((#{latitude} - #{lat_attr}) * PI() / 180 / 2), 2) + " +
115
134
  "COS(#{latitude} * PI() / 180) * COS(#{lat_attr} * PI() / 180) * " +
116
135
  "POWER(SIN((#{longitude} - #{lon_attr}) * PI() / 180 / 2), 2) ))"
117
- options[:order] ||= "#{distance} ASC"
136
+ conditions = ["#{distance} <= ?", radius]
118
137
  default_near_scope_options(latitude, longitude, radius, options).merge(
119
- :select => "#{options[:select] || '*'}, " +
138
+ :select => "#{options[:select] || "#{table_name}.*"}, " +
120
139
  "#{distance} AS distance" +
121
140
  (bearing ? ", #{bearing} AS bearing" : ""),
122
- :having => "#{distance} <= #{radius}"
141
+ :conditions => add_exclude_condition(conditions, options[:exclude])
123
142
  )
124
143
  end
125
144
 
@@ -155,11 +174,16 @@ module Geocoder::Store
155
174
 
156
175
  distance = "(#{dy} * ABS(#{lat_attr} - #{latitude}) * #{factor}) + " +
157
176
  "(#{dx} * ABS(#{lon_attr} - #{longitude}) * #{factor})"
177
+ b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
178
+ conditions = [
179
+ "#{lat_attr} BETWEEN ? AND ? AND #{lon_attr} BETWEEN ? AND ?"] +
180
+ [b[0], b[2], b[1], b[3]
181
+ ]
158
182
  default_near_scope_options(latitude, longitude, radius, options).merge(
159
- :select => "#{options[:select] || '*'}, " +
183
+ :select => "#{options[:select] || "#{table_name}.*"}, " +
160
184
  "#{distance} AS distance" +
161
185
  (bearing ? ", #{bearing} AS bearing" : ""),
162
- :order => distance
186
+ :conditions => add_exclude_condition(conditions, options[:exclude])
163
187
  )
164
188
  end
165
189
 
@@ -167,24 +191,24 @@ module Geocoder::Store
167
191
  # Options used for any near-like scope.
168
192
  #
169
193
  def default_near_scope_options(latitude, longitude, radius, options)
170
- lat_attr = geocoder_options[:latitude]
171
- lon_attr = geocoder_options[:longitude]
172
- b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
173
- conditions = \
174
- ["#{lat_attr} BETWEEN ? AND ? AND #{lon_attr} BETWEEN ? AND ?"] +
175
- [b[0], b[2], b[1], b[3]]
176
- if obj = options[:exclude]
177
- conditions[0] << " AND #{table_name}.id != ?"
178
- conditions << obj.id
179
- end
180
194
  {
181
- :group => columns.map{ |c| "#{table_name}.#{c.name}" }.join(','),
182
- :order => options[:order],
195
+ :order => options[:order] || "distance",
183
196
  :limit => options[:limit],
184
- :offset => options[:offset],
185
- :conditions => conditions
197
+ :offset => options[:offset]
186
198
  }
187
199
  end
200
+
201
+ ##
202
+ # Adds a condition to exclude a given object by ID.
203
+ # The given conditions MUST be an array.
204
+ #
205
+ def add_exclude_condition(conditions, exclude)
206
+ if exclude
207
+ conditions[0] << " AND #{table_name}.id != ?"
208
+ conditions << exclude.id
209
+ end
210
+ conditions
211
+ end
188
212
  end
189
213
 
190
214
  ##
@@ -193,12 +217,13 @@ module Geocoder::Store
193
217
  #
194
218
  def geocode
195
219
  do_lookup(false) do |o,rs|
196
- r = rs.first
197
- unless r.latitude.nil? or r.longitude.nil?
198
- o.send :write_attribute, self.class.geocoder_options[:latitude], r.latitude
199
- o.send :write_attribute, self.class.geocoder_options[:longitude], r.longitude
220
+ if r = rs.first
221
+ unless r.latitude.nil? or r.longitude.nil?
222
+ o.send :write_attribute, self.class.geocoder_options[:latitude], r.latitude
223
+ o.send :write_attribute, self.class.geocoder_options[:longitude], r.longitude
224
+ end
225
+ r.coordinates
200
226
  end
201
- r.coordinates
202
227
  end
203
228
  end
204
229
 
@@ -98,18 +98,17 @@ module Geocoder
98
98
  return
99
99
  end
100
100
 
101
- if (results = Geocoder.search(query)).size > 0
101
+ results = Geocoder.search(query)
102
102
 
103
- # execute custom block, if specified in configuration
104
- block_key = reverse ? :reverse_block : :geocode_block
105
- if custom_block = options[block_key]
106
- custom_block.call(self, results)
103
+ # execute custom block, if specified in configuration
104
+ block_key = reverse ? :reverse_block : :geocode_block
105
+ if custom_block = options[block_key]
106
+ custom_block.call(self, results)
107
107
 
108
- # else execute block passed directly to this method,
109
- # which generally performs the "auto-assigns"
110
- elsif block_given?
111
- yield(self, results)
112
- end
108
+ # else execute block passed directly to this method,
109
+ # which generally performs the "auto-assigns"
110
+ elsif block_given?
111
+ yield(self, results)
113
112
  end
114
113
  end
115
114
  end
@@ -56,11 +56,12 @@ module Geocoder::Store
56
56
  #
57
57
  def geocode
58
58
  do_lookup(false) do |o,rs|
59
- r = rs.first
60
- unless r.coordinates.nil?
61
- o.send :write_attribute, self.class.geocoder_options[:coordinates], r.coordinates.reverse
59
+ if r = rs.first
60
+ unless r.coordinates.nil?
61
+ o.send :write_attribute, self.class.geocoder_options[:coordinates], r.coordinates.reverse
62
+ end
63
+ r.coordinates
62
64
  end
63
- r.coordinates
64
65
  end
65
66
  end
66
67
 
@@ -1,3 +1,3 @@
1
1
  module Geocoder
2
- VERSION = "1.0.5"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -3,6 +3,10 @@ require 'test_helper'
3
3
 
4
4
  class ErrorHandlingTest < Test::Unit::TestCase
5
5
 
6
+ def teardown
7
+ Geocoder::Configuration.always_raise = []
8
+ end
9
+
6
10
  def test_does_not_choke_on_timeout
7
11
  # keep test output clean: suppress timeout warning
8
12
  orig = $VERBOSE; $VERBOSE = nil
@@ -21,7 +25,6 @@ class ErrorHandlingTest < Test::Unit::TestCase
21
25
  lookup.send(:results, "timeout")
22
26
  end
23
27
  end
24
- Geocoder::Configuration.always_raise = []
25
28
  end
26
29
 
27
30
  def test_always_raise_socket_error
@@ -32,6 +35,5 @@ class ErrorHandlingTest < Test::Unit::TestCase
32
35
  lookup.send(:results, "socket_error")
33
36
  end
34
37
  end
35
- Geocoder::Configuration.always_raise = []
36
38
  end
37
39
  end
@@ -0,0 +1,150 @@
1
+ [
2
+
3
+ {
4
+ "place_id": "30632629",
5
+ "licence": "Data Copyright OpenStreetMap Contributors, Some Rights Reserved. CC-BY-SA 2.0.",
6
+ "osm_type": "way",
7
+ "osm_id": "24801588",
8
+ "boundingbox": [
9
+ "40.749828338623",
10
+ "40.7511596679688",
11
+ "-73.9943389892578",
12
+ "-73.9926528930664"
13
+ ],
14
+ "polygonpoints": [
15
+ [
16
+ "-73.9943346",
17
+ "40.7503638"
18
+ ],
19
+ [
20
+ "-73.9942745",
21
+ "40.7504158"
22
+ ],
23
+ [
24
+ "-73.9942593",
25
+ "40.750629"
26
+ ],
27
+ [
28
+ "-73.9941343",
29
+ "40.7508432"
30
+ ],
31
+ [
32
+ "-73.9939794",
33
+ "40.7509703"
34
+ ],
35
+ [
36
+ "-73.9938042",
37
+ "40.7510532"
38
+ ],
39
+ [
40
+ "-73.9938025",
41
+ "40.7511311"
42
+ ],
43
+ [
44
+ "-73.9936051",
45
+ "40.7511571"
46
+ ],
47
+ [
48
+ "-73.9935673",
49
+ "40.751105"
50
+ ],
51
+ [
52
+ "-73.9934095",
53
+ "40.7511089"
54
+ ],
55
+ [
56
+ "-73.9931235",
57
+ "40.7510548"
58
+ ],
59
+ [
60
+ "-73.9928863",
61
+ "40.7509311"
62
+ ],
63
+ [
64
+ "-73.9928068",
65
+ "40.750949"
66
+ ],
67
+ [
68
+ "-73.992721",
69
+ "40.7508515"
70
+ ],
71
+ [
72
+ "-73.9927444",
73
+ "40.7507889"
74
+ ],
75
+ [
76
+ "-73.9926693",
77
+ "40.7506457"
78
+ ],
79
+ [
80
+ "-73.9926597",
81
+ "40.7503657"
82
+ ],
83
+ [
84
+ "-73.9928305",
85
+ "40.7500953"
86
+ ],
87
+ [
88
+ "-73.9929757",
89
+ "40.7499911"
90
+ ],
91
+ [
92
+ "-73.9931281",
93
+ "40.7499238"
94
+ ],
95
+ [
96
+ "-73.993133",
97
+ "40.7498631"
98
+ ],
99
+ [
100
+ "-73.9932961",
101
+ "40.7498306"
102
+ ],
103
+ [
104
+ "-73.9933664",
105
+ "40.7498742"
106
+ ],
107
+ [
108
+ "-73.993471",
109
+ "40.7498701"
110
+ ],
111
+ [
112
+ "-73.9938023",
113
+ "40.7499263"
114
+ ],
115
+ [
116
+ "-73.9940703",
117
+ "40.7500756"
118
+ ],
119
+ [
120
+ "-73.9941876",
121
+ "40.7502038"
122
+ ],
123
+ [
124
+ "-73.9942831",
125
+ "40.7502142"
126
+ ],
127
+ [
128
+ "-73.9943346",
129
+ "40.7503638"
130
+ ]
131
+ ],
132
+ "lat": "40.7504928941818",
133
+ "lon": "-73.993466492276",
134
+ "display_name": "Madison Square Garden, West 31st Street, Long Island City, New York City, New York, 10001, United States of America",
135
+ "class": "leisure",
136
+ "type": "stadium",
137
+ "address": {
138
+ "stadium": "Madison Square Garden",
139
+ "road": "West 31st Street",
140
+ "suburb": "Long Island City",
141
+ "city": "New York City",
142
+ "county": "New York",
143
+ "state": "New York",
144
+ "postcode": "10001",
145
+ "country": "United States of America",
146
+ "country_code": "us"
147
+ }
148
+ }
149
+
150
+ ]
@@ -0,0 +1 @@
1
+ [ ]
@@ -32,6 +32,12 @@ class GeocoderTest < Test::Unit::TestCase
32
32
  assert_equal coords, [v.latitude, v.longitude]
33
33
  end
34
34
 
35
+ def test_geocode_block_executed_when_no_results
36
+ v = Event.new("Nowhere", "no results")
37
+ v.geocode
38
+ assert_equal "NOT FOUND", v.coords_string
39
+ end
40
+
35
41
  def test_reverse_geocode_assigns_and_returns_address
36
42
  v = Landmark.new(*landmark_params(:msg))
37
43
  address = "4 Penn Plaza, New York, NY 10001, USA"
@@ -0,0 +1,24 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), *%w[ .. .. lib]))
2
+ require 'pathname'
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'geocoder'
6
+
7
+ class SmokeTest < Test::Unit::TestCase
8
+
9
+ def test_simple_zip_code_search
10
+ result = Geocoder.search "27701"
11
+ assert_equal "Durham", result.first.city
12
+ assert_equal "North Carolina", result.first.state
13
+ end
14
+
15
+ def test_simple_zip_code_search_with_ssl
16
+ Geocoder::Configuration.use_https = true
17
+ result = Geocoder.search "27701"
18
+ assert_equal "Durham", result.first.city
19
+ assert_equal "North Carolina", result.first.state
20
+ ensure
21
+ Geocoder::Configuration.use_https = false
22
+ end
23
+
24
+ end
@@ -110,4 +110,19 @@ class ServicesTest < Test::Unit::TestCase
110
110
  results = Geocoder.search("no results")
111
111
  assert_equal 0, results.length
112
112
  end
113
+
114
+ # --- Nominatim ---
115
+
116
+ def test_nominatim_result_components
117
+ Geocoder::Configuration.lookup = :nominatim
118
+ result = Geocoder.search("Madison Square Garden, New York, NY").first
119
+ assert_equal "10001", result.postal_code
120
+ end
121
+
122
+ def test_nominatim_address_formatting
123
+ Geocoder::Configuration.lookup = :nominatim
124
+ result = Geocoder.search("Madison Square Garden, New York, NY").first
125
+ assert_equal "Madison Square Garden, West 31st Street, Long Island City, New York City, New York, 10001, United States of America",
126
+ result.address
127
+ end
113
128
  end
data/test/test_helper.rb CHANGED
@@ -150,6 +150,19 @@ module Geocoder
150
150
  end
151
151
  end
152
152
 
153
+ class Nominatim < Base
154
+ private #-----------------------------------------------------------------
155
+ def fetch_raw_data(query, reverse = false)
156
+ raise TimeoutError if query == "timeout"
157
+ raise SocketError if query == "socket_error"
158
+ file = case query
159
+ when "no results"; :no_results
160
+ else :madison_square_garden
161
+ end
162
+ read_fixture "nominatim_#{file}.json"
163
+ end
164
+ end
165
+
153
166
  end
154
167
  end
155
168
 
@@ -187,6 +200,8 @@ class Event < ActiveRecord::Base
187
200
  geocoded_by :address do |obj,results|
188
201
  if result = results.first
189
202
  obj.coords_string = "#{result.latitude},#{result.longitude}"
203
+ else
204
+ obj.coords_string = "NOT FOUND"
190
205
  end
191
206
  end
192
207
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: geocoder
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 1.0.5
5
+ version: 1.1.0
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-10-26 00:00:00 -04:00
13
+ date: 2011-12-03 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -35,12 +35,14 @@ files:
35
35
  - lib/geocoder/calculations.rb
36
36
  - lib/geocoder/cli.rb
37
37
  - lib/geocoder/configuration.rb
38
+ - lib/geocoder/exceptions.rb
38
39
  - lib/geocoder/lookups/base.rb
39
40
  - lib/geocoder/lookups/bing.rb
40
41
  - lib/geocoder/lookups/freegeoip.rb
41
42
  - lib/geocoder/lookups/geocoder_ca.rb
42
43
  - lib/geocoder/lookups/google.rb
43
44
  - lib/geocoder/lookups/google_premier.rb
45
+ - lib/geocoder/lookups/nominatim.rb
44
46
  - lib/geocoder/lookups/yahoo.rb
45
47
  - lib/geocoder/lookups/yandex.rb
46
48
  - lib/geocoder/models/active_record.rb
@@ -56,6 +58,7 @@ files:
56
58
  - lib/geocoder/results/geocoder_ca.rb
57
59
  - lib/geocoder/results/google.rb
58
60
  - lib/geocoder/results/google_premier.rb
61
+ - lib/geocoder/results/nominatim.rb
59
62
  - lib/geocoder/results/yahoo.rb
60
63
  - lib/geocoder/results/yandex.rb
61
64
  - lib/geocoder/stores/active_record.rb
@@ -82,6 +85,8 @@ files:
82
85
  - test/fixtures/google_no_city_data.json
83
86
  - test/fixtures/google_no_locality.json
84
87
  - test/fixtures/google_no_results.json
88
+ - test/fixtures/nominatim_madison_square_garden.json
89
+ - test/fixtures/nominatim_no_results.json
85
90
  - test/fixtures/yahoo_garbage.json
86
91
  - test/fixtures/yahoo_madison_square_garden.json
87
92
  - test/fixtures/yahoo_no_results.json
@@ -91,6 +96,7 @@ files:
91
96
  - test/geocoder_test.rb
92
97
  - test/https_test.rb
93
98
  - test/input_handling_test.rb
99
+ - test/integration/smoke_test.rb
94
100
  - test/lookup_test.rb
95
101
  - test/method_aliases_test.rb
96
102
  - test/mongoid_test.rb