diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 0a5300a9547ef5a93f8f9bd4dc7d6a4dba22dc3a..3591852cad61e7f66fbce8f5c0f8703c1d3f2b9a 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -2,6 +2,12 @@ Per-release changes to Geocoder. +== 1.2.0 (???) + +* Add support for setting arbitrary params in geocoding request URL. +* Add support for Google's :bounds parameter (thanks to github.com/rosscooperman and github.com/peterjm for submitting suggestions). +* Code refactoring and cleanup (most notably, added Geocoder::Query class). + == 1.1.3 (2012 Aug 26) * Add support for Mapquest geocoding service (thanks github.com/razorinc). diff --git a/README.rdoc b/README.rdoc index a99a85583196ae5e54f4b9035ec6e2683e170e1b..c1dc8416d69c9a4de23dd7c04d21820c496a23e7 100644 --- a/README.rdoc +++ b/README.rdoc @@ -269,7 +269,10 @@ By default Geocoder uses Google's geocoding API to fetch coordinates and street end -Please see lib/geocoder/configuration.rb for a complete list of configuration options. +Please see lib/geocoder/configuration.rb for a complete list of configuration options. Additionally, some lookups have their own configuration options which are listed in the comparison chart below, and as of version 1.2.0 you can pass arbitrary parameters to any geocoding service. For example, to use Nominatim's <tt>countrycodes</tt> parameter: + + Geocoder::Configuration.lookup = :nominatim + Geocoder.search("Paris", :params => {:countrycodes => "gb,de,fr,es,us"}) === Listing and Comparison @@ -284,6 +287,7 @@ Quota:: 2,500 requests/day, 100,000 with Google Maps API Premier Region:: world SSL support:: yes Languages:: ar, eu, bg, bn, ca, cs, da, de, el, en, en-AU, en-GB, es, eu, fa, fi, fil, fr, gl, gu, hi, hr, hu, id, it, iw, ja, kn, ko, lt, lv, ml, mr, nl, no, pl, pt, pt-BR, pt-PT, ro, ru, sk, sl, sr, sv, tl, ta, te, th, tr, uk, vi, zh-CN, zh-TW (see http://spreadsheets.google.com/pub?key=p9pdwsai2hDMsLkXsoM05KQ&gid=1) +Extra options:: <tt>:bounds</tt> - pass SW and NE coordinates as an array of two arrays to bias results towards a viewport Documentation:: http://code.google.com/apis/maps/documentation/geocoding/#JSON Terms of Service:: http://code.google.com/apis/maps/terms.html#section_10_12 Limitations:: "You must not use or display the Content without a corresponding Google map, unless you are explicitly permitted to do so in the Maps APIs Documentation, or through written permission from Google." "You must not pre-fetch, cache, or store any Content, except that you may store: (i) limited amounts of Content for the purpose of improving the performance of your Maps API Implementation..." @@ -357,7 +361,7 @@ Documentation:: http://www.mapquestapi.com/geocoding/ Terms of Service:: http://info.mapquest.com/terms-of-use/ Limitations:: ? -==== FreeGeoIP +==== FreeGeoIP (<tt>:freegeoip</tt>) API key:: none Quota:: 1000 requests per hour. After reaching the hourly quota, all of your requests will result in HTTP 403 (Forbidden) until it clears up on the next roll over. diff --git a/lib/geocoder.rb b/lib/geocoder.rb index 76f5ec20cc01a26f4ce05ca73516ce786a6ac815..4019e84523f5f00a5ab6e31aebd233804ba5743d 100644 --- a/lib/geocoder.rb +++ b/lib/geocoder.rb @@ -1,8 +1,10 @@ require "geocoder/configuration" +require "geocoder/query" require "geocoder/calculations" require "geocoder/exceptions" require "geocoder/cache" require "geocoder/request" +require "geocoder/lookup" require "geocoder/models/active_record" if defined?(::ActiveRecord) require "geocoder/models/mongoid" if defined?(::Mongoid) require "geocoder/models/mongo_mapper" if defined?(::MongoMapper) @@ -13,15 +15,16 @@ module Geocoder ## # Search for information about an address or a set of coordinates. # - def search(query) - blank_query?(query) ? [] : lookup(query).search(query) + def search(query, options = {}) + query = Geocoder::Query.new(query, options) unless query.is_a?(Geocoder::Query) + query.blank? ? [] : query.execute end ## # Look up the coordinates of the given street or IP address. # - def coordinates(address) - if (results = search(address)).size > 0 + def coordinates(address, options = {}) + if (results = search(address, options)).size > 0 results.first.coordinates end end @@ -30,8 +33,8 @@ module Geocoder # Look up the address of the given coordinates ([lat,lon]) # or IP address (string). # - def address(query) - if (results = search(query)).size > 0 + def address(query, options = {}) + if (results = search(query, options)).size > 0 results.first.address end end @@ -45,85 +48,6 @@ module Geocoder end @cache end - - ## - # Array of valid Lookup names. - # - def valid_lookups - street_lookups + ip_lookups - end - - ## - # All street address lookups, default first. - # - def street_lookups - [:google, :google_premier, :yahoo, :bing, :geocoder_ca, :yandex, :nominatim, :mapquest, :test] - end - - ## - # All IP address lookups, default first. - # - def ip_lookups - [:freegeoip] - end - - - private # ----------------------------------------------------------------- - - ## - # Get a Lookup object (which communicates with the remote geocoding API). - # Takes a search query and returns an IP or street address Lookup - # depending on the query contents. - # - def lookup(query) - if ip_address?(query) - get_lookup(ip_lookups.first) - else - get_lookup(Configuration.lookup || street_lookups.first) - end - end - - ## - # Retrieve a Lookup object from the store. - # - def get_lookup(name) - @lookups = {} unless defined?(@lookups) - @lookups[name] = spawn_lookup(name) unless @lookups.include?(name) - @lookups[name] - end - - ## - # Spawn a Lookup of the given name. - # - def spawn_lookup(name) - if valid_lookups.include?(name) - name = name.to_s - require "geocoder/lookups/#{name}" - klass = name.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join - Geocoder::Lookup.const_get(klass).new - else - valids = valid_lookups.map(&:inspect).join(", ") - raise ConfigurationError, "Please specify a valid lookup for Geocoder " + - "(#{name.inspect} is not one of: #{valids})." - end - end - - ## - # Does the given value look like an IP address? - # - # Does not check for actual validity, just the appearance of four - # dot-delimited numbers. - # - def ip_address?(value) - !!value.to_s.match(/^(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) - end - - ## - # Is the given search query blank? (ie, should we not bother searching?) - # - def blank_query?(value) - !!value.to_s.match(/^\s*$/) - end end # load Railtie if Rails exists diff --git a/lib/geocoder/cli.rb b/lib/geocoder/cli.rb index 8822bf627a664ae6cb48ebddaf63f40a91329544..a5648631b10babc22c8583a8f52257cbcc9c8e0e 100644 --- a/lib/geocoder/cli.rb +++ b/lib/geocoder/cli.rb @@ -32,9 +32,10 @@ module Geocoder Geocoder::Configuration.http_proxy = proxy end - opts.on("-s <service>", Geocoder.street_lookups, "--service <service>", - "Geocoding service: #{Geocoder.street_lookups * ', '}") do |service| + opts.on("-s <service>", Geocoder::Lookup.all_services_except_test, "--service <service>", + "Geocoding service: #{Geocoder::Lookup.all_services_except_test * ', '}") do |service| Geocoder::Configuration.lookup = service.to_sym + Geocoder::Configuration.ip_lookup = service.to_sym end opts.on("-t <seconds>", "--timeout <seconds>", @@ -92,7 +93,7 @@ module Geocoder end if (result = Geocoder.search(query).first) - lookup = Geocoder.send(:get_lookup, :google) + lookup = Geocoder::Lookup.get(:google) lines = [ ["Latitude", result.latitude], ["Longitude", result.longitude], diff --git a/lib/geocoder/configuration.rb b/lib/geocoder/configuration.rb index 7bbe787daa8125d6597d5249962ed64ed6ea4688..c2df6d3eb2817afc7d29eaa7febde5df061e3403 100644 --- a/lib/geocoder/configuration.rb +++ b/lib/geocoder/configuration.rb @@ -40,6 +40,7 @@ module Geocoder OPTIONS = [ :timeout, :lookup, + :ip_lookup, :language, :http_headers, :use_https, @@ -61,7 +62,8 @@ module Geocoder def set_defaults @timeout = 3 # geocoding service timeout (secs) - @lookup = :google # name of geocoding service (symbol) + @lookup = :google # name of street address geocoding service (symbol) + @ip_lookup = :freegeoip # name of IP address geocoding service (symbol) @language = :en # ISO-639 language code @http_headers = {} # HTTP headers for lookup @use_https = false # use HTTPS for lookup requests? (if supported) diff --git a/lib/geocoder/lookup.rb b/lib/geocoder/lookup.rb new file mode 100644 index 0000000000000000000000000000000000000000..11d0a8a20d5fac110f3516c2791479aced6b176b --- /dev/null +++ b/lib/geocoder/lookup.rb @@ -0,0 +1,62 @@ +module Geocoder + module Lookup + + ## + # Array of valid Lookup service names. + # + def self.all_services + street_services + ip_services + end + + ## + # Array of valid Lookup service names, excluding :test. + # + def self.all_services_except_test + all_services - [:test] + end + + ## + # All street address lookup services, default first. + # + def self.street_services + [:google, :google_premier, :yahoo, :bing, :geocoder_ca, :yandex, :nominatim, :mapquest, :test] + end + + ## + # All IP address lookup services, default first. + # + def self.ip_services + [:freegeoip] + end + + ## + # Retrieve a Lookup object from the store. + # Use this instead of Geocoder::Lookup::X.new to get an + # already-configured Lookup object. + # + def self.get(name) + @services = {} unless defined?(@services) + @services[name] = spawn(name) unless @services.include?(name) + @services[name] + end + + + private # ----------------------------------------------------------------- + + ## + # Spawn a Lookup of the given name. + # + def self.spawn(name) + if all_services.include?(name) + name = name.to_s + require "geocoder/lookups/#{name}" + klass = name.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join + Geocoder::Lookup.const_get(klass).new + else + valids = all_services.map(&:inspect).join(", ") + raise ConfigurationError, "Please specify a valid lookup for Geocoder " + + "(#{name.inspect} is not one of: #{valids})." + end + end + end +end diff --git a/lib/geocoder/lookups/base.rb b/lib/geocoder/lookups/base.rb index 3665e954b51dfded0e8576335bf0f4c851a10645..7c80494a07050aaa74061c2681ff778d52a64328 100644 --- a/lib/geocoder/lookups/base.rb +++ b/lib/geocoder/lookups/base.rb @@ -13,6 +13,7 @@ end module Geocoder module Lookup + class Base ## @@ -23,18 +24,9 @@ module Geocoder # "205.128.54.202") for geocoding, or coordinates (latitude, longitude) # for reverse geocoding. Returns an array of <tt>Geocoder::Result</tt>s. # - def search(query) - - # if coordinates given as string, turn into array - query = query.split(/\s*,\s*/) if coordinates?(query) - - if query.is_a?(Array) - reverse = true - query = query.join(',') - else - reverse = false - end - results(query, reverse).map{ |r| + def search(query, options = {}) + query = Geocoder::Query.new(query, options) unless query.is_a?(Geocoder::Query) + results(query).map{ |r| result = result_class.new(r) result.cache_hit = @cache_hit if cache result @@ -77,14 +69,24 @@ module Geocoder ## # Geocoder::Result object or nil on timeout or other error. # - def results(query, reverse = false) + def results(query) fail end + def query_url_params(query) + query.options[:params] || {} + end + + def url_query_string(query) + hash_to_query( + query_url_params(query).reject{ |key,value| value.nil? } + ) + end + ## # URL to use for querying the geocoding engine. # - def query_url(query, reverse = false) + def query_url(query) fail end @@ -111,8 +113,8 @@ module Geocoder ## # Returns a parsed search result (Ruby hash). # - def fetch_data(query, reverse = false) - parse_raw_data fetch_raw_data(query, reverse) + def fetch_data(query) + parse_raw_data fetch_raw_data(query) rescue SocketError => err raise_error(err) or warn "Geocoding API connection cannot be established." rescue TimeoutError => err @@ -144,9 +146,9 @@ module Geocoder ## # Fetches a raw search result (JSON string). # - def fetch_raw_data(query, reverse = false) + def fetch_raw_data(query) timeout(Geocoder::Configuration.timeout) do - url = query_url(query, reverse) + url = query_url(query) uri = URI.parse(url) if cache and body = cache[url] @cache_hit = true @@ -171,20 +173,6 @@ module Geocoder Geocoder.cache end - ## - # Is the given string a loopback IP address? - # - def loopback_address?(ip) - !!(ip == "0.0.0.0" or ip.to_s.match(/^127/)) - end - - ## - # Does the given string look like latitude/longitude coordinates? - # - def coordinates?(value) - value.is_a?(String) and !!value.to_s.match(/^-?[0-9\.]+, *-?[0-9\.]+$/) - end - ## # Simulate ActiveSupport's Object#to_query. # Removes any keys with nil value. diff --git a/lib/geocoder/lookups/bing.rb b/lib/geocoder/lookups/bing.rb index 2bec5a4f1ec09a6443692b8a1fc356fe42dbbdfe..1edb567a8532a4b3ddc8c10b0640e0c1ee2861c9 100644 --- a/lib/geocoder/lookups/bing.rb +++ b/lib/geocoder/lookups/bing.rb @@ -10,8 +10,8 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def results(query, reverse = false) - return [] unless doc = fetch_data(query, reverse) + def results(query) + return [] unless doc = fetch_data(query) if doc['statusDescription'] == "OK" return doc['resourceSets'].first['estimatedTotal'] > 0 ? doc['resourceSets'].first['resources'] : [] @@ -21,13 +21,17 @@ module Geocoder::Lookup end end - def query_url(query, reverse = false) - params = {:key => Geocoder::Configuration.api_key} - params[:query] = query unless reverse + def query_url_params(query) + super.merge( + :key => Geocoder::Configuration.api_key, + :query => query.reverse_geocode? ? nil : query.sanitized_text + ) + end - base_url = "http://dev.virtualearth.net/REST/v1/Locations" - url_tail = reverse ? "/#{query}?" : "?" - base_url + url_tail + hash_to_query(params) + def query_url(query) + "http://dev.virtualearth.net/REST/v1/Locations" + + (query.reverse_geocode? ? "/#{query.sanitized_text}?" : "?") + + url_query_string(query) end end end diff --git a/lib/geocoder/lookups/freegeoip.rb b/lib/geocoder/lookups/freegeoip.rb index a5526667cd343808446934a627d3d8f6c0dee102..a3f6dc91a6662cf40ccc0a37a2461f822975ab0c 100644 --- a/lib/geocoder/lookups/freegeoip.rb +++ b/lib/geocoder/lookups/freegeoip.rb @@ -10,11 +10,11 @@ module Geocoder::Lookup raw_data.match(/^<html><title>404/) ? nil : super(raw_data) end - def results(query, reverse = false) + def results(query) # 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 query.loopback_ip_address? begin - return (doc = fetch_data(query, reverse)) ? [doc] : [] + return (doc = fetch_data(query)) ? [doc] : [] rescue StandardError => err # Freegeoip.net returns HTML on bad request raise_error(err) return [] @@ -36,8 +36,8 @@ module Geocoder::Lookup } end - def query_url(query, reverse = false) - "http://freegeoip.net/json/#{query}" + def query_url(query) + "http://freegeoip.net/json/#{query.sanitized_text}" end end end diff --git a/lib/geocoder/lookups/geocoder_ca.rb b/lib/geocoder/lookups/geocoder_ca.rb index 32ea293ab6af7388b0484fd1676ee3af9f57f6ab..97ac2721c756fe0e158f7ac51b3106f7bb9af1bb 100644 --- a/lib/geocoder/lookups/geocoder_ca.rb +++ b/lib/geocoder/lookups/geocoder_ca.rb @@ -6,8 +6,8 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def results(query, reverse = false) - return [] unless doc = fetch_data(query, reverse) + def results(query) + return [] unless doc = fetch_data(query) if doc['error'].nil? return [doc] elsif doc['error']['code'] == "005" @@ -18,24 +18,28 @@ module Geocoder::Lookup return [] end - def query_url(query, reverse = false) - params = { + def query_url_params(query) + params = super.merge( :geoit => "xml", :jsonp => 1, :callback => "test", :auth => Geocoder::Configuration.api_key - } - if reverse - lat,lon = query.split(',') + ) + if query.reverse_geocode? + lat,lon = query.coordinates params[:latt] = lat params[:longt] = lon params[:corner] = 1 params[:reverse] = 1 else - params[:locate] = query + params[:locate] = query.sanitized_text params[:showpostal] = 1 end - "http://geocoder.ca/?" + hash_to_query(params) + params + end + + def query_url(query) + "http://geocoder.ca/?" + url_query_string(query) end def parse_raw_data(raw_data) diff --git a/lib/geocoder/lookups/google.rb b/lib/geocoder/lookups/google.rb index 6898c267551bc056834cf7969fda1bb7fa46f4a3..13bb676351260674d6a7dbc47f469586fac895f3 100644 --- a/lib/geocoder/lookups/google.rb +++ b/lib/geocoder/lookups/google.rb @@ -10,8 +10,8 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def results(query, reverse = false) - return [] unless doc = fetch_data(query, reverse) + def results(query) + return [] unless doc = fetch_data(query) case doc['status']; when "OK" # OK status implies >0 results return doc['results'] when "OVER_QUERY_LIMIT" @@ -27,14 +27,26 @@ module Geocoder::Lookup return [] end - def query_url(query, reverse = false) + def query_url_google_params(query) params = { - (reverse ? :latlng : :address) => query, + (query.reverse_geocode? ? :latlng : :address) => query.sanitized_text, :sensor => "false", - :language => Geocoder::Configuration.language, - :key => Geocoder::Configuration.api_key + :language => Geocoder::Configuration.language } - "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + hash_to_query(params) + unless (bounds = query.options[:bounds]).nil? + params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join('|') + end + params + end + + def query_url_params(query) + super.merge(query_url_google_params(query)).merge( + :key => Geocoder::Configuration.api_key + ) + end + + def query_url(query) + "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query) end end end diff --git a/lib/geocoder/lookups/google_premier.rb b/lib/geocoder/lookups/google_premier.rb index 6befdddf585167868fcdbb58a042f0ea8175ea6d..b725b9fb4543aacd07206a7746a92d54f1bcdbf3 100644 --- a/lib/geocoder/lookups/google_premier.rb +++ b/lib/geocoder/lookups/google_premier.rb @@ -8,15 +8,16 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def query_url(query, reverse = false) - params = { - (reverse ? :latlng : :address) => query, - :sensor => 'false', - :language => Geocoder::Configuration.language, + def query_url_params(query) + super.merge(query_url_google_params(query)).merge( + :key => nil, # don't use param inherited from Google lookup :client => Geocoder::Configuration.api_key[1], :channel => Geocoder::Configuration.api_key[2] - }.reject{ |key, value| value.nil? } - path = "/maps/api/geocode/json?#{hash_to_query(params)}" + ) + end + + def query_url(query) + path = "/maps/api/geocode/json?" + url_query_string(query) "#{protocol}://maps.googleapis.com#{path}&signature=#{sign(path)}" end diff --git a/lib/geocoder/lookups/mapquest.rb b/lib/geocoder/lookups/mapquest.rb index 08cd31d8de0d33d19d985188ddff854311fd17f3..404bda22eef80bfc0e79593a39df3345f6ef5717 100644 --- a/lib/geocoder/lookups/mapquest.rb +++ b/lib/geocoder/lookups/mapquest.rb @@ -1,33 +1,15 @@ require 'geocoder/lookups/base' +require "geocoder/lookups/nominatim" require "geocoder/results/mapquest" module Geocoder::Lookup - class Mapquest < Base + class Mapquest < Nominatim private # --------------------------------------------------------------- - def results(query, reverse = false) - return [] unless doc = fetch_data(query, reverse) - doc.is_a?(Array) ? doc : [doc] - end - - def query_url(query, reverse = false) - params = { - :format => "json", - :polygon => "1", - :addressdetails => "1", - :"accept-language" => Geocoder::Configuration.language - } - if (reverse) - method = 'reverse' - parts = query.split(/\s*,\s*/); - params[:lat] = parts[0] - params[:lon] = parts[1] - else - method = 'search' - params[:q] = query - end - "http://open.mapquestapi.com/#{method}?" + hash_to_query(params) + def query_url(query) + method = query.reverse_geocode? ? "reverse" : "search" + "http://open.mapquestapi.com/#{method}?" + url_query_string(query) end end end diff --git a/lib/geocoder/lookups/nominatim.rb b/lib/geocoder/lookups/nominatim.rb index 12f2c1513879cb87346341c96b2aa92f30cab9bf..d79f7312650c2d6d3d7df63285c0b6cea5b4bb19 100644 --- a/lib/geocoder/lookups/nominatim.rb +++ b/lib/geocoder/lookups/nominatim.rb @@ -10,28 +10,31 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def results(query, reverse = false) - return [] unless doc = fetch_data(query, reverse) + def results(query) + return [] unless doc = fetch_data(query) doc.is_a?(Array) ? doc : [doc] end - def query_url(query, reverse = false) - params = { + def query_url_params(query) + params = super.merge( :format => "json", :polygon => "1", :addressdetails => "1", :"accept-language" => Geocoder::Configuration.language - } - if (reverse) - method = 'reverse' - parts = query.split(/\s*,\s*/); - params[:lat] = parts[0] - params[:lon] = parts[1] + ) + if query.reverse_geocode? + lat,lon = query.coordinates + params[:lat] = lat + params[:lon] = lon else - method = 'search' - params[:q] = query + params[:q] = query.sanitized_text end - "http://nominatim.openstreetmap.org/#{method}?" + hash_to_query(params) + params + end + + def query_url(query) + method = query.reverse_geocode? ? "reverse" : "search" + "http://nominatim.openstreetmap.org/#{method}?" + url_query_string(query) end end end diff --git a/lib/geocoder/lookups/test.rb b/lib/geocoder/lookups/test.rb index e06171c9dbc96a4ce03a54b2832c7262efa95b33..89aa97f4445d7d65c75caea6b0fe6d67c3d75dbe 100644 --- a/lib/geocoder/lookups/test.rb +++ b/lib/geocoder/lookups/test.rb @@ -5,12 +5,14 @@ module Geocoder module Lookup class Test < Base - def self.add_stub(query, results) - stubs[query] = results + def self.add_stub(query_text, results) + stubs[query_text] = results end - def self.read_stub(query) - stubs.fetch(query) { raise ArgumentError, "unknown stub request #{query}" } + def self.read_stub(query_text) + stubs.fetch(query_text) { + raise ArgumentError, "unknown stub request #{query_text}" + } end def self.stubs @@ -23,8 +25,8 @@ module Geocoder private - def results(query, reverse = false) - Geocoder::Lookup::Test.read_stub(query) + def results(query) + Geocoder::Lookup::Test.read_stub(query.text) end end diff --git a/lib/geocoder/lookups/yahoo.rb b/lib/geocoder/lookups/yahoo.rb index 1ce523ecc304a7973f5062e275cfc78473972a43..9282f2e970deedc170889f1d5d2043673cf38251 100644 --- a/lib/geocoder/lookups/yahoo.rb +++ b/lib/geocoder/lookups/yahoo.rb @@ -10,8 +10,8 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def results(query, reverse = false) - return [] unless doc = fetch_data(query, reverse) + def results(query) + return [] unless doc = fetch_data(query) if doc = doc['ResultSet'] and doc['Error'] == 0 return doc['Found'] > 0 ? doc['Results'] : [] else @@ -20,15 +20,18 @@ module Geocoder::Lookup end end - def query_url(query, reverse = false) - params = { - :location => query, + def query_url_params(query) + super.merge( + :location => query.sanitized_text, :flags => "JXTSR", - :gflags => "AC#{'R' if reverse}", + :gflags => "AC#{'R' if query.reverse_geocode?}", :locale => "#{Geocoder::Configuration.language}_US", :appid => Geocoder::Configuration.api_key - } - "http://where.yahooapis.com/geocode?" + hash_to_query(params) + ) + end + + def query_url(query) + "http://where.yahooapis.com/geocode?" + url_query_string(query) end end end diff --git a/lib/geocoder/lookups/yandex.rb b/lib/geocoder/lookups/yandex.rb index 452d27694eea2728450e6cb05877b909ee441f7f..9b4f63d6e8104fe422f7d48474e51fba30973bf6 100644 --- a/lib/geocoder/lookups/yandex.rb +++ b/lib/geocoder/lookups/yandex.rb @@ -10,8 +10,8 @@ module Geocoder::Lookup private # --------------------------------------------------------------- - def results(query, reverse = false) - return [] unless doc = fetch_data(query, reverse) + def results(query) + return [] unless doc = fetch_data(query) if err = doc['error'] warn "Yandex Geocoding API error: #{err['status']} (#{err['message']})." return [] @@ -25,15 +25,22 @@ module Geocoder::Lookup end end - def query_url(query, reverse = false) - query = query.split(",").reverse.join(",") if reverse - params = { - :geocode => query, + def query_url_params(query) + if query.reverse_geocode? + q = query.coordinates.reverse.join(",") + else + q = query.sanitized_text + end + super.merge( + :geocode => q, :format => "json", :plng => "#{Geocoder::Configuration.language}", # supports ru, uk, be :key => Geocoder::Configuration.api_key - } - "http://geocode-maps.yandex.ru/1.x/?" + hash_to_query(params) + ) + end + + def query_url(query) + "http://geocode-maps.yandex.ru/1.x/?" + url_query_string(query) end end end diff --git a/lib/geocoder/query.rb b/lib/geocoder/query.rb new file mode 100644 index 0000000000000000000000000000000000000000..3da86ef17430b0227dcc9a8cf285a97835197551 --- /dev/null +++ b/lib/geocoder/query.rb @@ -0,0 +1,88 @@ +module Geocoder + class Query + attr_accessor :text, :options + + def initialize(text, options = {}) + self.text = text + self.options = options + end + + def execute + lookup.search(text, options) + end + + def to_s + text + end + + def sanitized_text + if coordinates? + text.split(/\s*,\s*/).join(',') + else + text + end + end + + ## + # Get a Lookup object (which communicates with the remote geocoding API) + # appropriate to the Query text. + # + def lookup + if ip_address? + name = Configuration.ip_lookup || Geocoder::Lookup.ip_services.first + else + name = Configuration.lookup || Geocoder::Lookup.street_services.first + end + Lookup.get(name) + end + + ## + # Is the Query text blank? (ie, should we not bother searching?) + # + def blank? + !!text.to_s.match(/^\s*$/) + end + + ## + # Does the Query text look like an IP address? + # + # Does not check for actual validity, just the appearance of four + # dot-delimited numbers. + # + def ip_address? + !!text.to_s.match(/^(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) + end + + ## + # Is the Query text a loopback IP address? + # + def loopback_ip_address? + !!(text == "0.0.0.0" or text.to_s.match(/^127/)) + end + + ## + # Does the given string look like latitude/longitude coordinates? + # + def coordinates? + text.is_a?(Array) or ( + text.is_a?(String) and + !!text.to_s.match(/^-?[0-9\.]+, *-?[0-9\.]+$/) + ) + end + + ## + # Return the latitude/longitude coordinates specified in the query, + # or nil if none. + # + def coordinates + sanitized_text.split(',') if coordinates? + end + + ## + # Should reverse geocoding be performed for this query? + # + def reverse_geocode? + coordinates? + end + end +end diff --git a/lib/geocoder/results/mapquest.rb b/lib/geocoder/results/mapquest.rb index 8d2b6022f704e68122f1c56c1639349c2f225ee1..f977a6b5f5afb5e26aa8303e29723140daaae04b 100644 --- a/lib/geocoder/results/mapquest.rb +++ b/lib/geocoder/results/mapquest.rb @@ -1,66 +1,7 @@ require 'geocoder/results/base' +require 'geocoder/results/nominatim' module Geocoder::Result - class Mapquest < Base - - def house_number - @data['address']['house_number'] - end - - def address - @data['display_name'] - end - - def street - @data['address']['road'] - end - - def city - @data['address']['city'] - end - - def village - @data['address']['villiage'] - end - - def town - @data['address']['town'] - end - - def state - @data['address']['state'] - end - - alias_method :state_code, :state - - def postal_code - @data['address']['postcode'] - end - - def county - @data['address']['county'] - end - - def country - @data['address']['country'] - end - - def country_code - @data['address']['country_code'] - end - - def coordinates - [@data['lat'].to_f, @data['lon'].to_f] - end - - def self.response_attributes - %w[place_id boundingbox license polygonpoints display_name class type stadium suburb] - end - - response_attributes.each do |a| - define_method a do - @data[a] - end - end + class Mapquest < Nominatim end end diff --git a/lib/geocoder/results/nominatim.rb b/lib/geocoder/results/nominatim.rb index 59ef04678bef6d94da01c2f9e86c808d86556302..afd9af6f1008ab8c7ca544fcddadc6b850f6ab5d 100644 --- a/lib/geocoder/results/nominatim.rb +++ b/lib/geocoder/results/nominatim.rb @@ -5,8 +5,9 @@ module Geocoder::Result def poi %w[stadium bus_stop tram_stop].each do |key| - @data['address'][key] if @data['address'].key?(key) + return @data['address'][key] if @data['address'].key?(key) end + return nil end def house_number diff --git a/lib/geocoder/stores/active_record.rb b/lib/geocoder/stores/active_record.rb index 96b11e0701a2c3a3873e0930b295e1822303fc14..426622e8b5644b73d225b3f554dbec7521c247a5 100644 --- a/lib/geocoder/stores/active_record.rb +++ b/lib/geocoder/stores/active_record.rb @@ -148,9 +148,7 @@ module Geocoder::Store distance = full_distance_from_sql(latitude, longitude, options) conditions = ["#{distance} <= ?", radius] default_near_scope_options(latitude, longitude, radius, options).merge( - :select => select_addon(options) + - "#{distance} AS distance" + - (bearing ? ", #{bearing} AS bearing" : ""), + :select => select_clause(options[:select], distance, bearing), :conditions => add_exclude_condition(conditions, options[:exclude]) ) end @@ -222,18 +220,22 @@ module Geocoder::Store [b[0], b[2], b[1], b[3] ] default_near_scope_options(latitude, longitude, radius, options).merge( - :select => select_addon(options) + - "#{distance} AS distance" + - (bearing ? ", #{bearing} AS bearing" : ""), + :select => select_clause(options[:select], distance, bearing), :conditions => add_exclude_condition(conditions, options[:exclude]) ) end ## - # Select string to add + # Generate the SELECT clause. # - def select_addon(options) - options[:select] == :ignore ? "" : "#{options[:select] || full_column_name("*")}, " + def select_clause(columns, distance, bearing) + if columns == :geo_only + clause = "" + else + clause = (columns || full_column_name("*")) + ", " + end + clause + "#{distance} AS distance" + + (bearing ? ", #{bearing} AS bearing" : "") end ## diff --git a/lib/geocoder/version.rb b/lib/geocoder/version.rb index 0eb5a04215f806f4d4b75facf7c6e9b2335e31bb..3416c7e7efeb7a1f91029a9b3913b328fda8d0af 100644 --- a/lib/geocoder/version.rb +++ b/lib/geocoder/version.rb @@ -1,3 +1,3 @@ module Geocoder - VERSION = "1.1.3" + VERSION = "1.2.0" end diff --git a/test/calculations_test.rb b/test/calculations_test.rb index 4f9fef0df46df8131fb82d67bd7f9b93e61f68d8..902d8d680f8926bb89115b383b89acf72f07bbe3 100644 --- a/test/calculations_test.rb +++ b/test/calculations_test.rb @@ -185,4 +185,11 @@ class CalculationsTest < Test::Unit::TestCase assert !Geocoder::Calculations.coordinates_present?(Geocoder::Calculations::NAN) assert !Geocoder::Calculations.coordinates_present?(3.23, nil) end + + def test_extract_coordinates + coords = [-23,47] + l = Landmark.new("Madagascar", coords[0], coords[1]) + assert_equal coords, Geocoder::Calculations.extract_coordinates(l) + assert_equal coords, Geocoder::Calculations.extract_coordinates(coords) + end end diff --git a/test/error_handling_test.rb b/test/error_handling_test.rb index 9d84bdfdc008fe2d25671d36d052e3dd8fadaa40..369613e69540d3c33a039fd8ccf35800ee2445a3 100644 --- a/test/error_handling_test.rb +++ b/test/error_handling_test.rb @@ -10,7 +10,7 @@ class ErrorHandlingTest < Test::Unit::TestCase def test_does_not_choke_on_timeout # keep test output clean: suppress timeout warning orig = $VERBOSE; $VERBOSE = nil - all_lookups_except_test.each do |l| + Geocoder::Lookup.all_services_except_test.each do |l| Geocoder::Configuration.lookup = l assert_nothing_raised { Geocoder.search("timeout") } end @@ -19,20 +19,20 @@ class ErrorHandlingTest < Test::Unit::TestCase def test_always_raise_timeout_error Geocoder::Configuration.always_raise = [TimeoutError] - all_lookups_except_test.each do |l| - lookup = Geocoder.send(:get_lookup, l) + Geocoder::Lookup.all_services_except_test.each do |l| + lookup = Geocoder::Lookup.get(l) assert_raises TimeoutError do - lookup.send(:results, "timeout") + lookup.send(:results, Geocoder::Query.new("timeout")) end end end def test_always_raise_socket_error Geocoder::Configuration.always_raise = [SocketError] - all_lookups_except_test.each do |l| - lookup = Geocoder.send(:get_lookup, l) + Geocoder::Lookup.all_services_except_test.each do |l| + lookup = Geocoder::Lookup.get(l) assert_raises SocketError do - lookup.send(:results, "socket_error") + lookup.send(:results, Geocoder::Query.new("socket_error")) end end end diff --git a/test/https_test.rb b/test/https_test.rb index 58219d33cc8f013746583b0d20a699e93b534ad8..aba96acf7e53aea456c91ba503659a5f23160c2a 100644 --- a/test/https_test.rb +++ b/test/https_test.rb @@ -6,11 +6,11 @@ class HttpsTest < Test::Unit::TestCase def test_uses_https_for_secure_query Geocoder::Configuration.use_https = true g = Geocoder::Lookup::Google.new - assert_match /^https:/, g.send(:query_url, {:a => 1, :b => 2}) + assert_match /^https:/, g.send(:query_url, Geocoder::Query.new("test")) end def test_uses_http_by_default g = Geocoder::Lookup::Google.new - assert_match /^http:/, g.send(:query_url, {:a => 1, :b => 2}) + assert_match /^http:/, g.send(:query_url, Geocoder::Query.new("test")) end end diff --git a/test/input_handling_test.rb b/test/input_handling_test.rb deleted file mode 100644 index f5da1f13c9df941fdbf08a157464a0dbb0738d7c..0000000000000000000000000000000000000000 --- a/test/input_handling_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -# encoding: utf-8 -require 'test_helper' - -class InputHandlingTest < Test::Unit::TestCase - - def test_ip_address_detection - assert Geocoder.send(:ip_address?, "232.65.123.94") - assert Geocoder.send(:ip_address?, "666.65.123.94") # technically invalid - assert Geocoder.send(:ip_address?, "::ffff:12.34.56.78") - assert !Geocoder.send(:ip_address?, "232.65.123.94.43") - assert !Geocoder.send(:ip_address?, "232.65.123") - assert !Geocoder.send(:ip_address?, "::ffff:123.456.789") - end - - def test_blank_query_detection - assert Geocoder.send(:blank_query?, nil) - assert Geocoder.send(:blank_query?, "") - assert Geocoder.send(:blank_query?, "\t ") - assert !Geocoder.send(:blank_query?, "a") - assert !Geocoder.send(:blank_query?, "МоÑква") # no ASCII characters - end - - def test_coordinates_detection - lookup = Geocoder::Lookup::Google.new - assert lookup.send(:coordinates?, "51.178844,5") - assert lookup.send(:coordinates?, "51.178844, -1.826189") - assert !lookup.send(:coordinates?, "232.65.123") - end - - def test_does_not_choke_on_nil_address - all_lookups.each do |l| - Geocoder::Configuration.lookup = l - assert_nothing_raised { Venue.new("Venue", nil).geocode } - end - end - - def test_extract_coordinates - coords = [-23,47] - l = Landmark.new("Madagascar", coords[0], coords[1]) - assert_equal coords, Geocoder::Calculations.extract_coordinates(l) - assert_equal coords, Geocoder::Calculations.extract_coordinates(coords) - end -end diff --git a/test/integration/smoke_test.rb b/test/integration/smoke_test.rb index 8d80e1e14730cd9ad53072ef2ff9c07c5f4cf373..b0c805e61759fc9695c14bde1c0c8eca8d0d1802 100644 --- a/test/integration/smoke_test.rb +++ b/test/integration/smoke_test.rb @@ -8,15 +8,17 @@ class SmokeTest < Test::Unit::TestCase def test_simple_zip_code_search result = Geocoder.search "27701" - assert_equal "Durham", result.first.city - assert_equal "North Carolina", result.first.state + assert_not_nil (r = result.first) + assert_equal "Durham", r.city + assert_equal "North Carolina", r.state end def test_simple_zip_code_search_with_ssl Geocoder::Configuration.use_https = true result = Geocoder.search "27701" - assert_equal "Durham", result.first.city - assert_equal "North Carolina", result.first.state + assert_not_nil (r = result.first) + assert_equal "Durham", r.city + assert_equal "North Carolina", r.state ensure Geocoder::Configuration.use_https = false end diff --git a/test/lookup_test.rb b/test/lookup_test.rb index 9cce80b7751c06470161fa5062c5399808abf08f..5b4550c6c5045705395fb7bc687a6eda16bb7803 100644 --- a/test/lookup_test.rb +++ b/test/lookup_test.rb @@ -4,13 +4,20 @@ require 'test_helper' class LookupTest < Test::Unit::TestCase def test_search_returns_empty_array_when_no_results - all_lookups_except_test.each do |l| - lookup = Geocoder.send(:get_lookup, l) - assert_equal [], lookup.send(:results, "no results"), + Geocoder::Lookup.all_services_except_test.each do |l| + lookup = Geocoder::Lookup.get(l) + assert_equal [], lookup.send(:results, Geocoder::Query.new("no results")), "Lookup #{l} does not return empty array when no results." end end + def test_does_not_choke_on_nil_address + Geocoder::Lookup.all_services.each do |l| + Geocoder::Configuration.lookup = l + assert_nothing_raised { Venue.new("Venue", nil).geocode } + end + end + def test_hash_to_query g = Geocoder::Lookup::Google.new assert_equal "a=1&b=2", g.send(:hash_to_query, {:a => 1, :b => 2}) @@ -19,19 +26,19 @@ class LookupTest < Test::Unit::TestCase def test_google_api_key Geocoder::Configuration.api_key = "MY_KEY" g = Geocoder::Lookup::Google.new - assert_match "key=MY_KEY", g.send(:query_url, "Madison Square Garden, New York, NY 10001, United States") + assert_match "key=MY_KEY", g.send(:query_url, Geocoder::Query.new("Madison Square Garden, New York, NY 10001, United States")) end def test_yahoo_app_id Geocoder::Configuration.api_key = "MY_KEY" g = Geocoder::Lookup::Yahoo.new - assert_match "appid=MY_KEY", g.send(:query_url, "Madison Square Garden, New York, NY 10001, United States") + assert_match "appid=MY_KEY", g.send(:query_url, Geocoder::Query.new("Madison Square Garden, New York, NY 10001, United States")) end def test_geocoder_ca_showpostal Geocoder::Configuration.api_key = "MY_KEY" g = Geocoder::Lookup::GeocoderCa.new - assert_match "showpostal=1", g.send(:query_url, "Madison Square Garden, New York, NY 10001, United States") + assert_match "showpostal=1", g.send(:query_url, Geocoder::Query.new("Madison Square Garden, New York, NY 10001, United States")) end end diff --git a/test/query_test.rb b/test/query_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..22a90b5c674d181f7815b19e6949c4ea87d66c80 --- /dev/null +++ b/test/query_test.rb @@ -0,0 +1,34 @@ +# encoding: utf-8 +require 'test_helper' + +class QueryTest < Test::Unit::TestCase + + def test_ip_address_detection + assert Geocoder::Query.new("232.65.123.94").ip_address? + assert Geocoder::Query.new("666.65.123.94").ip_address? # technically invalid + assert Geocoder::Query.new("::ffff:12.34.56.78").ip_address? + assert !Geocoder::Query.new("232.65.123.94.43").ip_address? + assert !Geocoder::Query.new("232.65.123").ip_address? + assert !Geocoder::Query.new("::ffff:123.456.789").ip_address? + end + + def test_blank_query_detection + assert Geocoder::Query.new(nil).blank? + assert Geocoder::Query.new("").blank? + assert Geocoder::Query.new("\t ").blank? + assert !Geocoder::Query.new("a").blank? + assert !Geocoder::Query.new("МоÑква").blank? # no ASCII characters + end + + def test_coordinates_detection + assert Geocoder::Query.new("51.178844,5").coordinates? + assert Geocoder::Query.new("51.178844, -1.826189").coordinates? + assert !Geocoder::Query.new("232.65.123").coordinates? + end + + def test_loopback_ip_address + assert Geocoder::Query.new("0.0.0.0").loopback_ip_address? + assert Geocoder::Query.new("127.0.0.1").loopback_ip_address? + assert !Geocoder::Query.new("232.65.123.234").loopback_ip_address? + end +end diff --git a/test/result_test.rb b/test/result_test.rb index 85bb0f4f7ee26bf2534a3cc3ce8562c7eecd58b3..ab207c5fb6f0bd4834cf88b3764708d2db91ebee 100644 --- a/test/result_test.rb +++ b/test/result_test.rb @@ -4,7 +4,7 @@ require 'test_helper' class ResultTest < Test::Unit::TestCase def test_result_has_required_attributes - all_lookups_except_test.each do |l| + Geocoder::Lookup.all_services_except_test.each do |l| Geocoder::Configuration.lookup = l result = Geocoder.search([45.423733, -75.676333]).first assert_result_has_required_attributes(result) diff --git a/test/services_test.rb b/test/services_test.rb index 83fe571a0eaaa21a066339da4857ddf9cfedc32b..07cb694c728458b88f1ac04ab7654aa11bcf05ac 100644 --- a/test/services_test.rb +++ b/test/services_test.rb @@ -4,6 +4,18 @@ require 'test_helper' class ServicesTest < Test::Unit::TestCase + def test_query_url_contains_values_in_params_hash + Geocoder::Lookup.all_services_except_test.each do |l| + next if l == :google_premier # TODO: need to set keys to test + next if l == :freegeoip # does not use query string + url = Geocoder::Lookup.get(l).send(:query_url, Geocoder::Query.new( + "test", :params => {:one_in_the_hand => "two in the bush"} + )) + assert_match /one_in_the_hand=two\+in\+the\+bush/, url, + "Lookup #{l} does not appear to support arbitrary params in URL" + end + end + # --- Google --- def test_google_result_components @@ -28,6 +40,14 @@ class ServicesTest < Test::Unit::TestCase result.precision end + def test_google_query_url_contains_bounds + lookup = Geocoder::Lookup::Google.new + url = lookup.send(:query_url, Geocoder::Query.new( + "Some Intersection", + :bounds => [[40.0, -120.0], [39.0, -121.0]] + )) + assert_match /bounds=40.0+%2C-120.0+%7C39.0+%2C-121.0+/, url + end # --- Google Premier --- @@ -41,7 +61,7 @@ class ServicesTest < Test::Unit::TestCase def test_google_premier_query_url Geocoder::Configuration.api_key = ["deadbeef", "gme-test", "test-dev"] assert_equal "http://maps.googleapis.com/maps/api/geocode/json?address=Madison+Square+Garden%2C+New+York%2C+NY&channel=test-dev&client=gme-test&language=en&sensor=false&signature=doJvJqX7YJzgV9rJ0DnVkTGZqTg=", - Geocoder::Lookup::GooglePremier.new.send(:query_url, "Madison Square Garden, New York, NY", false) + Geocoder::Lookup::GooglePremier.new.send(:query_url, Geocoder::Query.new("Madison Square Garden, New York, NY")) end diff --git a/test/test_helper.rb b/test/test_helper.rb index 8ac6b3e0a6a939e7635eca5e6f63479a532c4a4c..fcdd13381f4def69fef9b672ba261aaee3238ee9 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -60,10 +60,10 @@ module Geocoder class Google < Base private #----------------------------------------------------------------- - def fetch_raw_data(query, reverse = false) - raise TimeoutError if query == "timeout" - raise SocketError if query == "socket_error" - file = case query + def fetch_raw_data(query) + raise TimeoutError if query.text == "timeout" + raise SocketError if query.text == "socket_error" + file = case query.text when "no results"; :no_results when "no locality"; :no_locality when "no city data"; :no_city_data @@ -78,10 +78,10 @@ module Geocoder class Yahoo < Base private #----------------------------------------------------------------- - def fetch_raw_data(query, reverse = false) - raise TimeoutError if query == "timeout" - raise SocketError if query == "socket_error" - file = case query + def fetch_raw_data(query) + raise TimeoutError if query.text == "timeout" + raise SocketError if query.text == "socket_error" + file = case query.text when "no results"; :no_results else :madison_square_garden end @@ -91,10 +91,10 @@ module Geocoder class Yandex < Base private #----------------------------------------------------------------- - def fetch_raw_data(query, reverse = false) - raise TimeoutError if query == "timeout" - raise SocketError if query == "socket_error" - file = case query + def fetch_raw_data(query) + raise TimeoutError if query.text == "timeout" + raise SocketError if query.text == "socket_error" + file = case query.text when "no results"; :no_results when "invalid key"; :invalid_key else :kremlin @@ -105,13 +105,13 @@ module Geocoder class GeocoderCa < Base private #----------------------------------------------------------------- - def fetch_raw_data(query, reverse = false) - raise TimeoutError if query == "timeout" - raise SocketError if query == "socket_error" - if reverse + def fetch_raw_data(query) + raise TimeoutError if query.text == "timeout" + raise SocketError if query.text == "socket_error" + if query.reverse_geocode? read_fixture "geocoder_ca_reverse.json" else - file = case query + file = case query.text when "no results"; :no_results else :madison_square_garden end @@ -122,10 +122,10 @@ module Geocoder class Freegeoip < Base private #----------------------------------------------------------------- - def fetch_raw_data(query, reverse = false) - raise TimeoutError if query == "timeout" - raise SocketError if query == "socket_error" - file = case query + def fetch_raw_data(query) + raise TimeoutError if query.text == "timeout" + raise SocketError if query.text == "socket_error" + file = case query.text when "no results"; :no_results else "74_200_247_59" end @@ -135,13 +135,13 @@ module Geocoder class Bing < Base private #----------------------------------------------------------------- - def fetch_raw_data(query, reverse = false) - raise TimeoutError if query == "timeout" - raise SocketError if query == "socket_error" - if reverse + def fetch_raw_data(query) + raise TimeoutError if query.text == "timeout" + raise SocketError if query.text == "socket_error" + if query.reverse_geocode? read_fixture "bing_reverse.json" else - file = case query + file = case query.text when "no results"; :no_results else :madison_square_garden end @@ -152,10 +152,10 @@ module Geocoder class Nominatim < Base private #----------------------------------------------------------------- - def fetch_raw_data(query, reverse = false) - raise TimeoutError if query == "timeout" - raise SocketError if query == "socket_error" - file = case query + def fetch_raw_data(query) + raise TimeoutError if query.text == "timeout" + raise SocketError if query.text == "socket_error" + file = case query.text when "no results"; :no_results else :madison_square_garden end @@ -163,12 +163,12 @@ module Geocoder end end - class Mapquest < Base + class Mapquest < Nominatim private #----------------------------------------------------------------- - def fetch_raw_data(query, reverse = false) - raise TimeoutError if query == "timeout" - raise SocketError if query == "socket_error" - file = case query + def fetch_raw_data(query) + raise TimeoutError if query.text == "timeout" + raise SocketError if query.text == "socket_error" + file = case query.text when "no results"; :no_results else :madison_square_garden end @@ -277,18 +277,6 @@ class Test::Unit::TestCase }[abbrev] end - def all_lookups - Geocoder.valid_lookups - end - - def all_lookups_except_test - Geocoder.valid_lookups - [:test] - end - - def street_lookups - all_lookups - [:freegeoip] - end - def is_nan_coordinates?(coordinates) return false unless coordinates.respond_to? :size # Should be an array return false unless coordinates.size == 2 # Should have dimension 2