From 76f6f93494c8b1b0543ea0a0886e8bd4da448ceb Mon Sep 17 00:00:00 2001
From: Alex Reisner <alex@alexreisner.com>
Date: Thu, 6 Dec 2012 16:51:28 -0500
Subject: [PATCH] Raise error when required API key is missing.

---
 lib/geocoder/lookups/base.rb           | 26 ++++++++++++++++++++++++++
 lib/geocoder/lookups/bing.rb           |  8 ++++++++
 lib/geocoder/lookups/freegeoip.rb      |  4 ++++
 lib/geocoder/lookups/geocoder_ca.rb    |  8 ++++++++
 lib/geocoder/lookups/google.rb         |  4 ++++
 lib/geocoder/lookups/google_premier.rb |  8 ++++++++
 lib/geocoder/lookups/mapquest.rb       |  8 ++++++++
 lib/geocoder/lookups/nominatim.rb      |  4 ++++
 lib/geocoder/lookups/test.rb           |  4 ++++
 lib/geocoder/lookups/yahoo.rb          |  8 ++++++++
 lib/geocoder/lookups/yandex.rb         |  8 ++++++++
 test/lookup_test.rb                    |  7 +++++++
 test/services_test.rb                  | 14 +++++++++++++-
 test/test_helper.rb                    | 19 +++++++------------
 14 files changed, 117 insertions(+), 13 deletions(-)

diff --git a/lib/geocoder/lookups/base.rb b/lib/geocoder/lookups/base.rb
index 33fc8b64..c19a61da 100644
--- a/lib/geocoder/lookups/base.rb
+++ b/lib/geocoder/lookups/base.rb
@@ -16,6 +16,13 @@ module Geocoder
 
     class Base
 
+      ##
+      # Human-readable name of the geocoding API.
+      #
+      def name
+        fail
+      end
+
       ##
       # Query the geocoding API and return a Geocoder::Result object.
       # Returns +nil+ on timeout or error.
@@ -43,6 +50,14 @@ module Geocoder
         nil
       end
 
+      ##
+      # Array containing string descriptions of keys required by the API.
+      # Empty array if keys are optional or not required.
+      #
+      def required_api_key_parts
+        []
+      end
+
 
       private # -------------------------------------------------------------
 
@@ -162,6 +177,7 @@ module Geocoder
         if cache and body = cache[key]
           @cache_hit = true
         else
+          check_api_key_configuration!(query)
           response = make_api_request(query)
           body = response.body
           if cache and (200..399).include?(response.code.to_i)
@@ -185,6 +201,16 @@ module Geocoder
         end
       end
 
+      def check_api_key_configuration!(query)
+        key_parts = query.lookup.required_api_key_parts
+        if key_parts.size > Array(Geocoder::Configuration.api_key).size
+          parts_string = key_parts.size == 1 ? key_parts.first : key_parts
+          raise Geocoder::ConfigurationError,
+            "The #{query.lookup.name} API requires a key to be configured: " +
+            parts_string.inspect
+        end
+      end
+
       ##
       # The working Cache object.
       #
diff --git a/lib/geocoder/lookups/bing.rb b/lib/geocoder/lookups/bing.rb
index 1f8f4c20..54dfa13d 100644
--- a/lib/geocoder/lookups/bing.rb
+++ b/lib/geocoder/lookups/bing.rb
@@ -4,10 +4,18 @@ require "geocoder/results/bing"
 module Geocoder::Lookup
   class Bing < Base
 
+    def name
+      "Bing"
+    end
+
     def map_link_url(coordinates)
       "http://www.bing.com/maps/default.aspx?cp=#{coordinates.join('~')}"
     end
 
+    def required_api_key_parts
+      ["key"]
+    end
+
     private # ---------------------------------------------------------------
 
     def results(query)
diff --git a/lib/geocoder/lookups/freegeoip.rb b/lib/geocoder/lookups/freegeoip.rb
index e6f8f231..b94946a6 100644
--- a/lib/geocoder/lookups/freegeoip.rb
+++ b/lib/geocoder/lookups/freegeoip.rb
@@ -4,6 +4,10 @@ require 'geocoder/results/freegeoip'
 module Geocoder::Lookup
   class Freegeoip < Base
 
+    def name
+      "FreeGeoIP"
+    end
+
     private # ---------------------------------------------------------------
 
     def parse_raw_data(raw_data)
diff --git a/lib/geocoder/lookups/geocoder_ca.rb b/lib/geocoder/lookups/geocoder_ca.rb
index 9c62d954..44b256c0 100644
--- a/lib/geocoder/lookups/geocoder_ca.rb
+++ b/lib/geocoder/lookups/geocoder_ca.rb
@@ -4,6 +4,14 @@ require "geocoder/results/geocoder_ca"
 module Geocoder::Lookup
   class GeocoderCa < Base
 
+    def name
+      "Geocoder.ca"
+    end
+
+    def required_api_key_parts
+      ["key"]
+    end
+
     private # ---------------------------------------------------------------
 
     def results(query)
diff --git a/lib/geocoder/lookups/google.rb b/lib/geocoder/lookups/google.rb
index 13bb6763..b6b9302a 100644
--- a/lib/geocoder/lookups/google.rb
+++ b/lib/geocoder/lookups/google.rb
@@ -4,6 +4,10 @@ require "geocoder/results/google"
 module Geocoder::Lookup
   class Google < Base
 
+    def name
+      "Google"
+    end
+
     def map_link_url(coordinates)
       "http://maps.google.com/maps?q=#{coordinates.join(',')}"
     end
diff --git a/lib/geocoder/lookups/google_premier.rb b/lib/geocoder/lookups/google_premier.rb
index b725b9fb..a61cc56d 100644
--- a/lib/geocoder/lookups/google_premier.rb
+++ b/lib/geocoder/lookups/google_premier.rb
@@ -6,6 +6,14 @@ require 'geocoder/results/google_premier'
 module Geocoder::Lookup
   class GooglePremier < Google
 
+    def name
+      "Google Premier"
+    end
+
+    def required_api_key_parts
+      ["private key", "client", "channel"]
+    end
+
     private # ---------------------------------------------------------------
 
     def query_url_params(query)
diff --git a/lib/geocoder/lookups/mapquest.rb b/lib/geocoder/lookups/mapquest.rb
index 6a852933..fd5ae8c6 100644
--- a/lib/geocoder/lookups/mapquest.rb
+++ b/lib/geocoder/lookups/mapquest.rb
@@ -5,6 +5,14 @@ require "geocoder/results/mapquest"
 module Geocoder::Lookup
   class Mapquest < Base
 
+    def name
+      "Mapquest"
+    end
+
+    def required_api_key_parts
+      ["key"]
+    end
+
     private # ---------------------------------------------------------------
 
     def query_url(query)
diff --git a/lib/geocoder/lookups/nominatim.rb b/lib/geocoder/lookups/nominatim.rb
index 0391d1bb..f7ed5638 100644
--- a/lib/geocoder/lookups/nominatim.rb
+++ b/lib/geocoder/lookups/nominatim.rb
@@ -4,6 +4,10 @@ require "geocoder/results/nominatim"
 module Geocoder::Lookup
   class Nominatim < Base
 
+    def name
+      "Nominatim"
+    end
+
     def map_link_url(coordinates)
       "http://www.openstreetmap.org/?lat=#{coordinates[0]}&lon=#{coordinates[1]}&zoom=15&layers=M"
     end
diff --git a/lib/geocoder/lookups/test.rb b/lib/geocoder/lookups/test.rb
index 89aa97f4..ebf7b5d7 100644
--- a/lib/geocoder/lookups/test.rb
+++ b/lib/geocoder/lookups/test.rb
@@ -5,6 +5,10 @@ module Geocoder
   module Lookup
     class Test < Base
 
+      def name
+        "Test"
+      end
+
       def self.add_stub(query_text, results)
         stubs[query_text] = results
       end
diff --git a/lib/geocoder/lookups/yahoo.rb b/lib/geocoder/lookups/yahoo.rb
index b4381782..be1925df 100644
--- a/lib/geocoder/lookups/yahoo.rb
+++ b/lib/geocoder/lookups/yahoo.rb
@@ -5,10 +5,18 @@ require 'oauth_util'
 module Geocoder::Lookup
   class Yahoo < Base
 
+    def name
+      "Yahoo BOSS"
+    end
+
     def map_link_url(coordinates)
       "http://maps.yahoo.com/#lat=#{coordinates[0]}&lon=#{coordinates[1]}"
     end
 
+    def required_api_key_parts
+      ["consumer key", "consumer secret"]
+    end
+
     private # ---------------------------------------------------------------
 
     def results(query)
diff --git a/lib/geocoder/lookups/yandex.rb b/lib/geocoder/lookups/yandex.rb
index 70dbaa7d..7470eb0f 100644
--- a/lib/geocoder/lookups/yandex.rb
+++ b/lib/geocoder/lookups/yandex.rb
@@ -4,10 +4,18 @@ require "geocoder/results/yandex"
 module Geocoder::Lookup
   class Yandex < Base
 
+    def name
+      "Yandex"
+    end
+
     def map_link_url(coordinates)
       "http://maps.yandex.ru/?ll=#{coordinates.reverse.join(',')}"
     end
 
+    def required_api_key_parts
+      ["key"]
+    end
+
     private # ---------------------------------------------------------------
 
     def results(query)
diff --git a/test/lookup_test.rb b/test/lookup_test.rb
index b721e4a1..4c9a0047 100644
--- a/test/lookup_test.rb
+++ b/test/lookup_test.rb
@@ -36,4 +36,11 @@ class LookupTest < Test::Unit::TestCase
     assert_match "showpostal=1", g.send(:query_url, Geocoder::Query.new("Madison Square Garden, New York, NY  10001, United States"))
   end
 
+  def test_raises_configuration_error_on_missing_key
+    assert_raises Geocoder::ConfigurationError do
+      Geocoder::Configuration.lookup = :bing
+      Geocoder::Configuration.api_key = nil
+      Geocoder.search("Madison Square Garden, New York, NY  10001, United States")
+    end
+  end
 end
diff --git a/test/services_test.rb b/test/services_test.rb
index 0000b57b..d33a648f 100644
--- a/test/services_test.rb
+++ b/test/services_test.rb
@@ -77,11 +77,13 @@ class ServicesTest < Test::Unit::TestCase
 
   def test_yahoo_no_results
     Geocoder::Configuration.lookup = :yahoo
+    set_api_key!(:yahoo)
     assert_equal [], Geocoder.search("no results")
   end
 
   def test_yahoo_error
     Geocoder::Configuration.lookup = :yahoo
+    set_api_key!(:yahoo)
     # keep test output clean: suppress timeout warning
     orig = $VERBOSE; $VERBOSE = nil
     assert_equal [], Geocoder.search("error")
@@ -91,12 +93,14 @@ class ServicesTest < Test::Unit::TestCase
 
   def test_yahoo_result_components
     Geocoder::Configuration.lookup = :yahoo
+    set_api_key!(:yahoo)
     result = Geocoder.search("madison square garden").first
     assert_equal "10001", result.postal_code
   end
 
   def test_yahoo_address_formatting
     Geocoder::Configuration.lookup = :yahoo
+    set_api_key!(:yahoo)
     result = Geocoder.search("madison square garden").first
     assert_equal "Madison Square Garden, New York, NY 10001, United States", result.address
   end
@@ -108,6 +112,7 @@ class ServicesTest < Test::Unit::TestCase
     # keep test output clean: suppress timeout warning
     orig = $VERBOSE; $VERBOSE = nil
     Geocoder::Configuration.lookup = :yandex
+    set_api_key!(:yandex)
     assert_equal [], Geocoder.search("invalid key")
   ensure
     $VERBOSE = orig
@@ -118,6 +123,7 @@ class ServicesTest < Test::Unit::TestCase
 
   def test_geocoder_ca_result_components
     Geocoder::Configuration.lookup = :geocoder_ca
+    set_api_key!(:geocoder_ca)
     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
@@ -141,6 +147,7 @@ class ServicesTest < Test::Unit::TestCase
 
   def test_bing_result_components
     Geocoder::Configuration.lookup = :bing
+    set_api_key!(:bing)
     result = Geocoder.search("Madison Square Garden, New York, NY").first
     assert_equal "Madison Square Garden, NY", result.address
     assert_equal "NY", result.state
@@ -149,6 +156,7 @@ class ServicesTest < Test::Unit::TestCase
 
   def test_bing_no_results
     Geocoder::Configuration.lookup = :bing
+    set_api_key!(:bing)
     results = Geocoder.search("no results")
     assert_equal 0, results.length
   end
@@ -157,22 +165,24 @@ class ServicesTest < Test::Unit::TestCase
 
   def test_nominatim_result_components
     Geocoder::Configuration.lookup = :nominatim
+    set_api_key!(:nominatim)
     result = Geocoder.search("Madison Square Garden, New York, NY").first
     assert_equal "10001", result.postal_code
   end
 
   def test_nominatim_address_formatting
     Geocoder::Configuration.lookup = :nominatim
+    set_api_key!(:nominatim)
     result = Geocoder.search("Madison Square Garden, New York, NY").first
     assert_equal "Madison Square Garden, West 31st Street, Long Island City, New York City, New York, 10001, United States of America",
       result.address
   end
+
   # --- MapQuest ---
 
   def test_api_route
     Geocoder::Configuration.lookup = :mapquest
     Geocoder::Configuration.api_key = "abc123"
-
     lookup = Geocoder::Lookup::Mapquest.new
     query = Geocoder::Query.new("Bluffton, SC")
     res = lookup.send(:query_url, query)
@@ -182,12 +192,14 @@ class ServicesTest < Test::Unit::TestCase
 
   def test_mapquest_result_components
     Geocoder::Configuration.lookup = :mapquest
+    set_api_key!(:mapquest)
     result = Geocoder.search("Madison Square Garden, New York, NY").first
     assert_equal "10001", result.postal_code
   end
 
   def test_mapquest_address_formatting
     Geocoder::Configuration.lookup = :mapquest
+    set_api_key!(:mapquest)
     result = Geocoder.search("Madison Square Garden, New York, NY").first
     assert_equal "46 West 31st Street, New York, NY, 10001, US",
       result.address
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 81deb6f3..bff12199 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -326,19 +326,14 @@ class Test::Unit::TestCase
   end
 
   def set_api_key!(lookup_name)
-    if lookup_name == :google_premier
-      Geocoder::Configuration.api_key = [
-        'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
-        'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
-        'cccccccccccccccccccccccccccccc'
-      ]
-    elsif lookup_name == :yahoo
-      Geocoder::Configuration.api_key = [
-        'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
-        'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
-      ]
+    lookup = Geocoder::Lookup.get(lookup_name)
+    if lookup.required_api_key_parts.size == 1
+      key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+    elsif lookup.required_api_key_parts.size > 1
+      key = lookup.required_api_key_parts
     else
-      Geocoder::Configuration.api_key = nil
+      key = nil
     end
+    Geocoder::Configuration.api_key = key
   end
 end
-- 
GitLab