From 46ab278abf8b014edf8e71b3008665c27e962b7f Mon Sep 17 00:00:00 2001
From: Steve Hoeksema <steve@seven.net.nz>
Date: Tue, 13 Sep 2011 09:43:48 +1200
Subject: [PATCH] Add Google Premier geocoder

---
 lib/geocoder.rb                        |  2 +-
 lib/geocoder/configuration.rb          |  6 ++++
 lib/geocoder/lookups/google_premier.rb | 43 ++++++++++++++++++++++++++
 lib/geocoder/results/google_premier.rb |  6 ++++
 test/services_test.rb                  | 18 +++++++++++
 test/test_helper.rb                    |  3 ++
 6 files changed, 77 insertions(+), 1 deletion(-)
 create mode 100644 lib/geocoder/lookups/google_premier.rb
 create mode 100644 lib/geocoder/results/google_premier.rb

diff --git a/lib/geocoder.rb b/lib/geocoder.rb
index 58906daa..c7fb016d 100644
--- a/lib/geocoder.rb
+++ b/lib/geocoder.rb
@@ -56,7 +56,7 @@ module Geocoder
   # All street address lookups, default first.
   #
   def street_lookups
-    [:google, :yahoo, :bing, :geocoder_ca, :yandex]
+    [:google, :google_premier, :yahoo, :bing, :geocoder_ca, :yandex]
   end
 
   ##
diff --git a/lib/geocoder/configuration.rb b/lib/geocoder/configuration.rb
index 3381fb18..5c83adf8 100644
--- a/lib/geocoder/configuration.rb
+++ b/lib/geocoder/configuration.rb
@@ -24,6 +24,12 @@ module Geocoder
         # API key for geocoding service
         [:api_key, nil],
 
+        # API client for geocoding service
+        [:api_client, nil],
+
+        # API channel for geocoding service
+        [:api_channel, nil],
+
         # cache object (must respond to #[], #[]=, and #keys)
         [:cache, nil],
 
diff --git a/lib/geocoder/lookups/google_premier.rb b/lib/geocoder/lookups/google_premier.rb
new file mode 100644
index 00000000..4694d2ec
--- /dev/null
+++ b/lib/geocoder/lookups/google_premier.rb
@@ -0,0 +1,43 @@
+require 'openssl'
+require 'base64'
+require 'geocoder/lookups/google'
+require 'geocoder/results/google_premier'
+
+module Geocoder::Lookup
+  class GooglePremier < Google
+
+    private # ---------------------------------------------------------------
+
+    def query_url(query, reverse = false)
+      params = {
+        (reverse ? :latlng : :address) => query,
+        :sensor => 'false',
+        :language => Geocoder::Configuration.language,
+        :client => Geocoder::Configuration.api_client,
+        :channel => Geocoder::Configuration.api_channel
+      }.reject{ |key, value| value.nil? }
+
+      path = "/maps/api/geocode/json?#{hash_to_query(params)}"
+
+      signature = sign(path)
+
+      "#{protocol}://maps.googleapis.com#{path}&signature=#{signature}"
+    end
+
+    def sign(string)
+      raw_private_key = url_safe_base64_decode(Geocoder::Configuration.api_key)
+      digest = OpenSSL::Digest::Digest.new('sha1')
+      raw_signature = OpenSSL::HMAC.digest(digest, raw_private_key, string)
+      url_safe_base64_encode(raw_signature)
+    end
+
+    def url_safe_base64_decode(base64_string)
+      Base64.decode64(base64_string.tr('-_', '+/'))
+    end
+
+    def url_safe_base64_encode(raw)
+      Base64.encode64(raw).tr('+/', '-_').strip
+    end
+
+  end
+end
diff --git a/lib/geocoder/results/google_premier.rb b/lib/geocoder/results/google_premier.rb
new file mode 100644
index 00000000..7237dc09
--- /dev/null
+++ b/lib/geocoder/results/google_premier.rb
@@ -0,0 +1,6 @@
+require 'geocoder/results/google'
+
+module Geocoder::Result
+  class GooglePremier < Google
+  end
+end
\ No newline at end of file
diff --git a/test/services_test.rb b/test/services_test.rb
index d6ddc852..d1a8218f 100644
--- a/test/services_test.rb
+++ b/test/services_test.rb
@@ -33,6 +33,24 @@ class ServicesTest < Test::Unit::TestCase
   end
 
 
+  # --- Google Premier ---
+
+  def test_google_premier_result_components
+    Geocoder::Configuration.lookup = :google_premier
+    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_premier_query_url
+    Geocoder::Configuration.api_key = "deadbeef"
+    Geocoder::Configuration.api_client = "gme-test"
+    Geocoder::Configuration.api_channel = "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)
+  end
+
+
   # --- Yahoo ---
 
   def test_yahoo_result_components
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 5a417d53..589ebcbe 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -73,6 +73,9 @@ module Geocoder
       end
     end
 
+    class GooglePremier < Google
+    end
+
     class Yahoo < Base
       private #-----------------------------------------------------------------
       def fetch_raw_data(query, reverse = false)
-- 
GitLab