From 70121b3998a94b05b151f07f54ecd1e44d9b36c5 Mon Sep 17 00:00:00 2001
From: Alex Reisner <alex@alexreisner.com>
Date: Sun, 2 Sep 2012 18:46:02 -0400
Subject: [PATCH] Add ability to specify arbitrary URL params

in request to geocoding service.
---
 lib/geocoder/lookups/base.rb           | 10 ++++++++++
 lib/geocoder/lookups/bing.rb           | 16 ++++++++++------
 lib/geocoder/lookups/geocoder_ca.rb    | 12 ++++++++----
 lib/geocoder/lookups/google.rb         | 13 ++++++++-----
 lib/geocoder/lookups/google_premier.rb | 12 ++++++++----
 lib/geocoder/lookups/mapquest.rb       |  3 +--
 lib/geocoder/lookups/nominatim.rb      |  7 +++----
 lib/geocoder/lookups/yahoo.rb          | 11 +++++++----
 lib/geocoder/lookups/yandex.rb         | 11 +++++++----
 test/services_test.rb                  | 12 ++++++++++++
 10 files changed, 74 insertions(+), 33 deletions(-)

diff --git a/lib/geocoder/lookups/base.rb b/lib/geocoder/lookups/base.rb
index a770f97f..7c80494a 100644
--- a/lib/geocoder/lookups/base.rb
+++ b/lib/geocoder/lookups/base.rb
@@ -73,6 +73,16 @@ module Geocoder
         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.
       #
diff --git a/lib/geocoder/lookups/bing.rb b/lib/geocoder/lookups/bing.rb
index a5d254c3..1edb567a 100644
--- a/lib/geocoder/lookups/bing.rb
+++ b/lib/geocoder/lookups/bing.rb
@@ -21,13 +21,17 @@ module Geocoder::Lookup
       end
     end
 
-    def query_url(query)
-      params = {:key => Geocoder::Configuration.api_key}
-      params[:query] = query.sanitized_text unless query.reverse_geocode?
+    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 = query.reverse_geocode? ? "/#{query.sanitized_text}?" : "?"
-      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/geocoder_ca.rb b/lib/geocoder/lookups/geocoder_ca.rb
index 379d0fd4..97ac2721 100644
--- a/lib/geocoder/lookups/geocoder_ca.rb
+++ b/lib/geocoder/lookups/geocoder_ca.rb
@@ -18,13 +18,13 @@ module Geocoder::Lookup
       return []
     end
 
-    def query_url(query)
-      params = {
+    def query_url_params(query)
+      params = super.merge(
         :geoit    => "xml",
         :jsonp    => 1,
         :callback => "test",
         :auth     => Geocoder::Configuration.api_key
-      }
+      )
       if query.reverse_geocode?
         lat,lon = query.coordinates
         params[:latt] = lat
@@ -35,7 +35,11 @@ module Geocoder::Lookup
         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 967294f5..13bb6763 100644
--- a/lib/geocoder/lookups/google.rb
+++ b/lib/geocoder/lookups/google.rb
@@ -27,7 +27,7 @@ module Geocoder::Lookup
       return []
     end
 
-    def query_url_base_params(query)
+    def query_url_google_params(query)
       params = {
         (query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
         :sensor => "false",
@@ -39,11 +39,14 @@ module Geocoder::Lookup
       params
     end
 
-    def query_url(query)
-      params = query_url_base_params(query).merge(
+    def query_url_params(query)
+      super.merge(query_url_google_params(query)).merge(
         :key => Geocoder::Configuration.api_key
-      ).reject{ |key, value| value.nil? }
-      "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + hash_to_query(params)
+      )
+    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 2f1d974c..b725b9fb 100644
--- a/lib/geocoder/lookups/google_premier.rb
+++ b/lib/geocoder/lookups/google_premier.rb
@@ -8,12 +8,16 @@ module Geocoder::Lookup
 
     private # ---------------------------------------------------------------
 
-    def query_url(query)
-      params = query_url_base_params(query).merge(
+    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 0b02807c..404bda22 100644
--- a/lib/geocoder/lookups/mapquest.rb
+++ b/lib/geocoder/lookups/mapquest.rb
@@ -8,9 +8,8 @@ module Geocoder::Lookup
     private # ---------------------------------------------------------------
 
     def query_url(query)
-      params = query_url_params(query)
       method = query.reverse_geocode? ? "reverse" : "search"
-      "http://open.mapquestapi.com/#{method}?" + hash_to_query(params)
+      "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 3a077369..d79f7312 100644
--- a/lib/geocoder/lookups/nominatim.rb
+++ b/lib/geocoder/lookups/nominatim.rb
@@ -16,12 +16,12 @@ module Geocoder::Lookup
     end
 
     def query_url_params(query)
-      params = {
+      params = super.merge(
         :format => "json",
         :polygon => "1",
         :addressdetails => "1",
         :"accept-language" => Geocoder::Configuration.language
-      }
+      )
       if query.reverse_geocode?
         lat,lon = query.coordinates
         params[:lat] = lat
@@ -33,9 +33,8 @@ module Geocoder::Lookup
     end
 
     def query_url(query)
-      params = query_url_params(query)
       method = query.reverse_geocode? ? "reverse" : "search"
-      "http://nominatim.openstreetmap.org/#{method}?" + hash_to_query(params)
+      "http://nominatim.openstreetmap.org/#{method}?" + url_query_string(query)
     end
   end
 end
diff --git a/lib/geocoder/lookups/yahoo.rb b/lib/geocoder/lookups/yahoo.rb
index e240fb4a..9282f2e9 100644
--- a/lib/geocoder/lookups/yahoo.rb
+++ b/lib/geocoder/lookups/yahoo.rb
@@ -20,15 +20,18 @@ module Geocoder::Lookup
       end
     end
 
-    def query_url(query)
-      params = {
+    def query_url_params(query)
+      super.merge(
         :location => query.sanitized_text,
         :flags => "JXTSR",
         :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 11f092d7..9b4f63d6 100644
--- a/lib/geocoder/lookups/yandex.rb
+++ b/lib/geocoder/lookups/yandex.rb
@@ -25,19 +25,22 @@ module Geocoder::Lookup
       end
     end
 
-    def query_url(query)
+    def query_url_params(query)
       if query.reverse_geocode?
         q = query.coordinates.reverse.join(",")
       else
         q = query.sanitized_text
       end
-      params = {
+      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/test/services_test.rb b/test/services_test.rb
index 2864588d..07cb694c 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
-- 
GitLab