diff --git a/lib/geocoder.rb b/lib/geocoder.rb index df59e222a990b183fe402a6f642a2bb5ee182cd4..3920fa57d57a46647dba62db0599a337338b3be6 100644 --- a/lib/geocoder.rb +++ b/lib/geocoder.rb @@ -10,7 +10,7 @@ module Geocoder # Search for information about an address or a set of coordinates. # def search(*args) - return nil if blank_query?(args[0]) + return [] if blank_query?(args[0]) ip = (args.size == 1 and ip_address?(args.first)) lookup(ip).search(*args) end @@ -19,8 +19,8 @@ module Geocoder # Look up the coordinates of the given street or IP address. # def coordinates(address) - if result = search(address) - result.coordinates + if (results = search(address)).size > 0 + results.first.coordinates end end @@ -28,8 +28,8 @@ module Geocoder # Look up the address of the given coordinates. # def address(latitude, longitude) - if result = search(latitude, longitude) - result.address + if (results = search(latitude, longitude)).size > 0 + results.first.address end end diff --git a/lib/geocoder/lookups/base.rb b/lib/geocoder/lookups/base.rb index 3b449c454f5cb2d5c8cc033a9cc7bc5e36b22a99..2f5674955751812ee17fdc4b04089a2e1a6c0863 100644 --- a/lib/geocoder/lookups/base.rb +++ b/lib/geocoder/lookups/base.rb @@ -17,13 +17,11 @@ module Geocoder # # Takes a search string (eg: "Mississippi Coast Coliseumf, Biloxi, MS", # "205.128.54.202") for geocoding, or coordinates (latitude, longitude) - # for reverse geocoding. + # for reverse geocoding. Returns an array of <tt>Geocoder::Result</tt>s. # def search(*args) reverse = (args.size == 2) || coordinates?(args.first) - if res = result(args.join(","), reverse) - result_class.new(res) - end + results(args.join(","), reverse).map{ |r| result_class.new(r) } end @@ -32,7 +30,7 @@ module Geocoder ## # Geocoder::Result object or nil on timeout or other error. # - def result(query, reverse = false) + def results(query, reverse = false) fail end diff --git a/lib/geocoder/lookups/freegeoip.rb b/lib/geocoder/lookups/freegeoip.rb index 4ae499af6c68b6172c3a350a4f04553e7198f02b..9ff4ac4a2cdf6e4de801474a48564ae861194610 100644 --- a/lib/geocoder/lookups/freegeoip.rb +++ b/lib/geocoder/lookups/freegeoip.rb @@ -6,13 +6,13 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def result(query, reverse = false) + def results(query, reverse = false) # don't look up a loopback address, just return the stored result - return reserved_result(query) if loopback_address?(query) + return [reserved_result(query)] if loopback_address?(query) begin - fetch_data(query, reverse) + return [fetch_data(query, reverse)] rescue StandardError # Freegeoip.net returns HTML on bad request - nil + return [] end end diff --git a/lib/geocoder/lookups/geocoder_ca.rb b/lib/geocoder/lookups/geocoder_ca.rb index 0f11e803b1bc3dda2b17fc13494b42253f7ed30d..f9ad139268a83f8e2f64fb21ef5e35f4fea35d40 100644 --- a/lib/geocoder/lookups/geocoder_ca.rb +++ b/lib/geocoder/lookups/geocoder_ca.rb @@ -6,15 +6,16 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def result(query, reverse = false) - return nil unless doc = fetch_data(query, reverse) + def results(query, reverse = false) + return [] unless doc = fetch_data(query, reverse) if doc['error'].nil? - doc + return [doc] elsif doc['error']['code'] == "005" - nil # "Postal Code is not in the proper Format" => no results, just shut up + # "Postal Code is not in the proper Format" => no results, just shut up else warn "Geocoder.ca service error: #{doc['error']['code']} (#{doc['error']['description']})." end + return [] end def query_url(query, reverse = false) diff --git a/lib/geocoder/lookups/google.rb b/lib/geocoder/lookups/google.rb index 72e54184f21a4dc6260a295c8d1ea5be5913b9d8..711ec67e690d5717d27053b214b4f78a2d0a89ff 100644 --- a/lib/geocoder/lookups/google.rb +++ b/lib/geocoder/lookups/google.rb @@ -6,10 +6,10 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def result(query, reverse = false) - return nil unless doc = fetch_data(query, reverse) + def results(query, reverse = false) + return [] unless doc = fetch_data(query, reverse) case doc['status']; when "OK" # OK status implies >0 results - doc['results'].first + return doc['results'] when "OVER_QUERY_LIMIT" warn "Google Geocoding API error: over query limit." when "REQUEST_DENIED" @@ -17,6 +17,7 @@ module Geocoder::Lookup when "INVALID_REQUEST" warn "Google Geocoding API error: invalid request." end + return [] end def query_url(query, reverse = false) diff --git a/lib/geocoder/lookups/yahoo.rb b/lib/geocoder/lookups/yahoo.rb index 7d4b5494082352d94f96a626544408156d41e207..e95c063559fe266fcb5c1c7836a32cf4c7e4e86d 100644 --- a/lib/geocoder/lookups/yahoo.rb +++ b/lib/geocoder/lookups/yahoo.rb @@ -6,12 +6,13 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def result(query, reverse = false) - return nil unless doc = fetch_data(query, reverse) + def results(query, reverse = false) + return [] unless doc = fetch_data(query, reverse) if doc = doc['ResultSet'] and doc['Error'] == 0 - doc['Results'].first if doc['Found'] > 0 + return doc['Found'] > 0 ? doc['Results'] : [] else warn "Yahoo Geocoding API error: #{doc['Error']} (#{doc['ErrorMessage']})." + return [] end end diff --git a/lib/geocoder/orms/active_record.rb b/lib/geocoder/orms/active_record.rb index 61efacdc80bc2b51c0fc6b7a0ac7d1df90a4f2a1..c93b8e61ee9cd60cccc2b5d941815f5ed986e511 100644 --- a/lib/geocoder/orms/active_record.rb +++ b/lib/geocoder/orms/active_record.rb @@ -151,7 +151,8 @@ module Geocoder::Orm # (or other as specified in +geocoded_by+). Returns coordinates (array). # def geocode - do_lookup(false) do |o,r| + do_lookup(false) do |o,rs| + r = rs.first unless r.latitude.nil? or r.longitude.nil? o.send :write_attribute, self.class.geocoder_options[:latitude], r.latitude o.send :write_attribute, self.class.geocoder_options[:longitude], r.longitude @@ -167,7 +168,8 @@ module Geocoder::Orm # in +reverse_geocoded_by+). Returns address (string). # def reverse_geocode - do_lookup(true) do |o,r| + do_lookup(true) do |o,rs| + r = rs.first unless r.address.nil? o.send :write_attribute, self.class.geocoder_options[:fetched_address], r.address end diff --git a/lib/geocoder/orms/active_record_legacy.rb b/lib/geocoder/orms/active_record_legacy.rb index 0c09248a0197bc28b8750af4bbf33a0602b5a010..e8db8bc72dae59c86e27940b632381a93d5a03f6 100644 --- a/lib/geocoder/orms/active_record_legacy.rb +++ b/lib/geocoder/orms/active_record_legacy.rb @@ -7,7 +7,8 @@ module Geocoder::Orm::ActiveRecord def fetch_coordinates! warn "DEPRECATION WARNING: The 'fetch_coordinates!' method is deprecated and will be removed in geocoder v1.0. " + "Please use 'geocode' instead and then save your objects manually." - do_lookup(false) do |o,r| + do_lookup(false) do |o,rs| + r = rs.first unless r.latitude.nil? or r.longitude.nil? o.send :update_attribute, self.class.geocoder_options[:latitude], r.latitude o.send :update_attribute, self.class.geocoder_options[:longitude], r.longitude @@ -19,7 +20,8 @@ module Geocoder::Orm::ActiveRecord def fetch_coordinates(*args) warn "DEPRECATION WARNING: The 'fetch_coordinates' method will cease taking " + "an argument in geocoder v1.0. Please save your objects manually." if args.size > 0 - do_lookup(false) do |o,r| + do_lookup(false) do |o,rs| + r = rs.first unless r.latitude.nil? or r.longitude.nil? method = ((args.size > 0 && args.first) ? "update" : "write" ) + "_attribute" o.send method, self.class.geocoder_options[:latitude], r.latitude @@ -35,7 +37,8 @@ module Geocoder::Orm::ActiveRecord def fetch_address! warn "DEPRECATION WARNING: The 'fetch_address!' method is deprecated and will be removed in geocoder v1.0. " + "Please use 'reverse_geocode' instead and then save your objects manually." - do_lookup(true) do |o,r| + do_lookup(true) do |o,rs| + r = rs.first unless r.address.nil? o.send :update_attribute, self.class.geocoder_options[:fetched_address], r.address end @@ -46,7 +49,8 @@ module Geocoder::Orm::ActiveRecord def fetch_address(*args) warn "DEPRECATION WARNING: The 'fetch_address' method will cease taking " + "an argument in geocoder v1.0. Please save your objects manually." if args.size > 0 - do_lookup(true) do |o,r| + do_lookup(true) do |o,rs| + r = rs.first unless r.latitude.nil? or r.longitude.nil? method = ((args.size > 0 && args.first) ? "update" : "write" ) + "_attribute" o.send method, self.class.geocoder_options[:fetched_address], r.address diff --git a/lib/geocoder/orms/base.rb b/lib/geocoder/orms/base.rb index 08d16a3bca6728a4579b05823b74841b2495b0ff..90666ae6f3f1c1f3940c29eb082f8e82d64e405b 100644 --- a/lib/geocoder/orms/base.rb +++ b/lib/geocoder/orms/base.rb @@ -60,10 +60,10 @@ module Geocoder ## # Look up geographic data based on object attributes (configured in - # geocoded_by or reverse_geocoded_by) and handle the result with the + # geocoded_by or reverse_geocoded_by) and handle the results with the # block (given to geocoded_by or reverse_geocoded_by). The block is - # given two-arguments: the object being geocoded and a - # Geocoder::Result object with the geocoding results). + # given two-arguments: the object being geocoded and an array of + # Geocoder::Result objects). # def do_lookup(reverse = false) options = self.class.geocoder_options @@ -76,17 +76,17 @@ module Geocoder end args.map!{ |a| send(options[a]) } - if result = Geocoder.search(*args) + if (results = Geocoder.search(*args)).size > 0 # execute custom block, if specified in configuration block_key = reverse ? :reverse_block : :geocode_block if custom_block = options[block_key] - custom_block.call(self, result) + custom_block.call(self, results) # else execute block passed directly to this method, # which generally performs the "auto-assigns" elsif block_given? - yield(self, result) + yield(self, results) end end end diff --git a/lib/geocoder/request.rb b/lib/geocoder/request.rb index cf3e6b3ad5d50ac58b520fcec0845e1f5ce356a3..5f71d46bc86455f9be4b2771b545a16bf5384653 100644 --- a/lib/geocoder/request.rb +++ b/lib/geocoder/request.rb @@ -5,7 +5,7 @@ module Geocoder def location unless defined?(@location) - @location = Geocoder.search(ip) + @location = Geocoder.search(ip).first end @location end diff --git a/test/geocoder_test.rb b/test/geocoder_test.rb index 925efb90c5e6747285a480a090ffc1d4fbe2c9fc..2d29fc109e399f1033ffe5612eccd1f413e32ebf 100644 --- a/test/geocoder_test.rb +++ b/test/geocoder_test.rb @@ -77,11 +77,11 @@ class GeocoderTest < Test::Unit::TestCase end def test_coordinates_method - assert_not_nil Geocoder.coordinates("Madison Square Garden, New York, NY") + assert Geocoder.coordinates("Madison Square Garden, New York, NY").is_a?(Array) end def test_address_method - assert_not_nil Geocoder.address(40.750354, -73.993371) + assert Geocoder.address(40.750354, -73.993371).is_a?(String) end @@ -153,18 +153,18 @@ class GeocoderTest < Test::Unit::TestCase assert_equal address, v.address end - def test_returns_nil_when_no_results + def test_search_returns_empty_array_when_no_results street_lookups.each do |l| Geocoder::Configuration.lookup = l - assert_nil Geocoder.search("no results"), - "Lookup #{l} does not return nil when no results." + assert_equal [], Geocoder.search("no results"), + "Lookup #{l} does not return empty array when no results." end end def test_result_has_required_attributes all_lookups.each do |l| Geocoder::Configuration.lookup = l - result = Geocoder.search(45.423733, -75.676333) + result = Geocoder.search(45.423733, -75.676333).first assert_result_has_required_attributes(result) end end @@ -173,13 +173,13 @@ class GeocoderTest < Test::Unit::TestCase # --- Google --- def test_google_result_components - result = Geocoder.search("Madison Square Garden, New York, NY") + result = Geocoder.search("Madison Square Garden, New York, NY").first assert_equal "Manhattan", result.address_components_of_type(:sublocality).first['long_name'] end def test_google_returns_city_when_no_locality_in_result - result = Geocoder.search("no locality") + result = Geocoder.search("no locality").first assert_equal "Haram", result.city end @@ -188,13 +188,13 @@ class GeocoderTest < Test::Unit::TestCase def test_yahoo_result_components Geocoder::Configuration.lookup = :yahoo - result = Geocoder.search("Madison Square Garden, New York, NY") + result = Geocoder.search("Madison Square Garden, New York, NY").first assert_equal "10001", result.postal_code end def test_yahoo_address_formatting Geocoder::Configuration.lookup = :yahoo - result = Geocoder.search("Madison Square Garden, New York, NY") + result = Geocoder.search("Madison Square Garden, New York, NY").first assert_equal "Madison Square Garden, New York, NY 10001, United States", result.address end @@ -204,7 +204,7 @@ class GeocoderTest < Test::Unit::TestCase def test_geocoder_ca_result_components Geocoder::Configuration.lookup = :geocoder_ca - result = Geocoder.search(45.423733, -75.676333) + result = Geocoder.search(45.423733, -75.676333).first assert_equal "CA", result.country_code assert_equal "289 Somerset ST E, Ottawa, ON K1N6W1, Canada", result.address end @@ -213,12 +213,12 @@ class GeocoderTest < Test::Unit::TestCase # --- FreeGeoIp --- def test_freegeoip_result_on_ip_address_search - result = Geocoder.search("74.200.247.59") + result = Geocoder.search("74.200.247.59").first assert result.is_a?(Geocoder::Result::Freegeoip) end def test_freegeoip_result_components - result = Geocoder.search("74.200.247.59") + result = Geocoder.search("74.200.247.59").first assert_equal "Plano, TX 75093, United States", result.address end @@ -258,7 +258,7 @@ class GeocoderTest < Test::Unit::TestCase def test_detection_of_coordinates_in_search_string Geocoder::Configuration.lookup = :geocoder_ca - result = Geocoder.search("51.178844, -1.826189") + result = Geocoder.search("51.178844, -1.826189").first assert_not_nil result.city # city only present if reverse geocoding search performed end diff --git a/test/test_helper.rb b/test/test_helper.rb index 3cf70f3b538d86eb0fbf438a995c5746c361f0a1..d2a6e51b26f42d4875884b9796ff4c757f5f61bc 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -134,8 +134,8 @@ end # Geocoded model with block. # class Event < ActiveRecord::Base - geocoded_by :address do |obj,result| - if result + geocoded_by :address do |obj,results| + if result = results.first obj.coords_string = "#{result.latitude},#{result.longitude}" end end @@ -151,8 +151,8 @@ end # Reverse geocoded model with block. # class Party < ActiveRecord::Base - reverse_geocoded_by :latitude, :longitude do |obj,result| - if result + reverse_geocoded_by :latitude, :longitude do |obj,results| + if result = results.first obj.country = result.country_code end end