From 29f2ca868a945caaf451b918ea004cb7b212ca2e Mon Sep 17 00:00:00 2001
From: Alex Reisner <alex@alexreisner.com>
Date: Fri, 18 Mar 2011 18:14:50 -0400
Subject: [PATCH] Use more sophisticated city detection with Google.

Google results don't return a 'city', so we have to look at several
fields in descending order of preference.
---
 lib/geocoder/results/google.rb        | 20 ++++++++---
 test/fixtures/google_no_locality.json | 51 +++++++++++++++++++++++++++
 test/geocoder_test.rb                 |  5 +++
 test/test_helper.rb                   |  6 +++-
 4 files changed, 77 insertions(+), 5 deletions(-)
 create mode 100644 test/fixtures/google_no_locality.json

diff --git a/lib/geocoder/results/google.rb b/lib/geocoder/results/google.rb
index 5e7f44ae..5455004d 100644
--- a/lib/geocoder/results/google.rb
+++ b/lib/geocoder/results/google.rb
@@ -12,19 +12,31 @@ module Geocoder::Result
     end
 
     def city
-      address_components_of_type(:locality).first['long_name']
+      fields = [:locality, :sublocality, :administrative_area_level_3,
+        :administrative_area_level_2, :administrative_area_level_1]
+      fields.each do |f|
+        if entity = address_components_of_type(f).first
+          return entity['long_name']
+        end
+      end
     end
 
     def country
-      address_components_of_type(:country).first['long_name']
+      if country = address_components_of_type(:country).first
+        country['long_name']
+      end
     end
 
     def country_code
-      address_components_of_type(:country).first['short_name']
+      if country = address_components_of_type(:country).first
+        country['short_name']
+      end
     end
 
     def postal_code
-      address_components_of_type(:postal_code).first['long_name']
+      if postal = address_components_of_type(:postal_code).first
+        postal['long_name']
+      end
     end
 
     def types
diff --git a/test/fixtures/google_no_locality.json b/test/fixtures/google_no_locality.json
new file mode 100644
index 00000000..d012817c
--- /dev/null
+++ b/test/fixtures/google_no_locality.json
@@ -0,0 +1,51 @@
+{
+  "status": "OK",
+  "results": [ {
+    "types": [ "route" ],
+    "formatted_address": "Al Ahram, Haram, Giza, Egypt",
+    "address_components": [ {
+      "long_name": "Al Ahram",
+      "short_name": "Al Ahram",
+      "types": [ "route" ]
+    }, {
+      "long_name": "Haram",
+      "short_name": "Haram",
+      "types": [ "administrative_area_level_2", "political" ]
+    }, {
+      "long_name": "Al Jizah",
+      "short_name": "Al Jizah",
+      "types": [ "administrative_area_level_1", "political" ]
+    }, {
+      "long_name": "Egypt",
+      "short_name": "EG",
+      "types": [ "country", "political" ]
+    } ],
+    "geometry": {
+      "location": {
+        "lat": 29.9803527,
+        "lng": 31.1330307
+      },
+      "location_type": "APPROXIMATE",
+      "viewport": {
+        "southwest": {
+          "lat": 29.9768276,
+          "lng": 31.1302189
+        },
+        "northeast": {
+          "lat": 29.9831228,
+          "lng": 31.1365141
+        }
+      },
+      "bounds": {
+        "southwest": {
+          "lat": 29.9775337,
+          "lng": 31.1327483
+        },
+        "northeast": {
+          "lat": 29.9824167,
+          "lng": 31.1339847
+        }
+      }
+    }
+  } ]
+}
diff --git a/test/geocoder_test.rb b/test/geocoder_test.rb
index 3dda9307..68b8f844 100644
--- a/test/geocoder_test.rb
+++ b/test/geocoder_test.rb
@@ -170,6 +170,11 @@ class GeocoderTest < Test::Unit::TestCase
       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")
+    assert_equal "Haram", result.city
+  end
+
 
   # --- Yahoo ---
 
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 18c7aa74..3cf70f3b 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -62,7 +62,11 @@ module Geocoder
       private #-----------------------------------------------------------------
       def fetch_raw_data(query, reverse = false)
         raise TimeoutError if query == "timeout"
-        file = query == "no results" ? :no_results : :madison_square_garden
+        file = case query
+          when "no results";  :no_results
+          when "no locality"; :no_locality
+          else                :madison_square_garden
+        end
         read_fixture "google_#{file}.json"
       end
     end
-- 
GitLab