From 2b473b45872dd101a7ad48ab618cd9b39406ea91 Mon Sep 17 00:00:00 2001
From: Alex Reisner <alex@alexreisner.com>
Date: Tue, 15 Mar 2011 01:02:03 -0400
Subject: [PATCH] Add Geocoder.ca support.

---
 lib/geocoder.rb                               |  2 +-
 lib/geocoder/lookups/geocoder_ca.rb           | 43 ++++++++++++++
 lib/geocoder/results/geocoder_ca.rb           | 58 +++++++++++++++++++
 .../geocoder_ca_madison_square_garden.json    |  1 +
 test/fixtures/geocoder_ca_no_results.json     |  1 +
 test/fixtures/geocoder_ca_reverse.json        | 34 +++++++++++
 test/geocoder_test.rb                         | 10 ++++
 test/test_helper.rb                           | 13 +++++
 8 files changed, 161 insertions(+), 1 deletion(-)
 create mode 100644 lib/geocoder/lookups/geocoder_ca.rb
 create mode 100644 lib/geocoder/results/geocoder_ca.rb
 create mode 100644 test/fixtures/geocoder_ca_madison_square_garden.json
 create mode 100644 test/fixtures/geocoder_ca_no_results.json
 create mode 100644 test/fixtures/geocoder_ca_reverse.json

diff --git a/lib/geocoder.rb b/lib/geocoder.rb
index 120cffbf..23f67ab0 100644
--- a/lib/geocoder.rb
+++ b/lib/geocoder.rb
@@ -77,7 +77,7 @@ module Geocoder
   end
 
   def valid_lookups
-    [:google, :yahoo, :freegeoip]
+    [:google, :yahoo, :geocoder_ca, :freegeoip]
   end
 
   ##
diff --git a/lib/geocoder/lookups/geocoder_ca.rb b/lib/geocoder/lookups/geocoder_ca.rb
new file mode 100644
index 00000000..93a1aa03
--- /dev/null
+++ b/lib/geocoder/lookups/geocoder_ca.rb
@@ -0,0 +1,43 @@
+require 'geocoder/lookups/base'
+require "geocoder/results/geocoder_ca"
+
+module Geocoder::Lookup
+  class GeocoderCa < Base
+
+    private # ---------------------------------------------------------------
+
+    def result(query, reverse = false)
+      return nil unless doc = fetch_data(query, reverse)
+      if doc['error'].nil?
+        doc
+      elsif doc['error']['code'] == "005"
+        nil # "Postal Code is not in the proper Format" => no results, just shut up
+      else
+        warn "Geocoder.ca service error: #{doc['error']['code']} (#{doc['error']['description']})."
+      end
+    end
+
+    def query_url(query, reverse = false)
+      params = {
+        :geoit    => "xml",
+        :reverse  => reverse ? "Reverse+GeoCode+it!" : nil,
+        :jsonp    => 1,
+        :callback => "test"
+      }
+      if reverse
+        lat,lon = query.split(',')
+        params[:latt] = lat
+        params[:longt] = lon
+        params[:corner] = 1
+      else
+        params[:locate] = query
+      end
+      "http://geocoder.ca/?" + hash_to_query(params)
+    end
+
+    def parse_raw_data(raw_data)
+      super raw_data[/^test\((.*)\)\;\s*$/, 1]
+    end
+  end
+end
+
diff --git a/lib/geocoder/results/geocoder_ca.rb b/lib/geocoder/results/geocoder_ca.rb
new file mode 100644
index 00000000..f5f9e14b
--- /dev/null
+++ b/lib/geocoder/results/geocoder_ca.rb
@@ -0,0 +1,58 @@
+require 'geocoder/results/base'
+
+module Geocoder::Result
+  class GeocoderCa < Base
+
+    def coordinates
+      [@data['latt'].to_f, @data['longt'].to_f]
+    end
+
+    def address(format = :full)
+      "#{street_address}, #{city}, #{state} #{postal_code}, #{country}"
+    end
+
+    def street_address
+      "#{@data['stnumber']} #{@data['staddress']}"
+    end
+
+    def city
+      @data['city']
+    end
+
+    def state
+      @data['prov']
+    end
+
+    alias_method :province, :state
+
+    def postal_code
+      @data['postal']
+    end
+
+    def country
+      country_code == 'CA' ? 'Canada' : 'United States'
+    end
+
+    def country_code
+      prov = @data['prov']
+      return nil if prov.nil? || prov == ""
+      canadian_province_abbreviations.include?(@data['prov']) ? "CA" : "US"
+    end
+
+    def canadian_province_abbreviations
+      %w[ON QC NS NB MB BC PE SK AB NL]
+    end
+
+    def self.response_attributes
+      %w[latt longt inlatt inlongt betweenRoad1 betweenRoad2 distance
+        stnumber staddress city prov postal
+        NearRoad NearRoadDistance intersection major_intersection]
+    end
+
+    response_attributes.each do |a|
+      define_method a do
+        @data[a]
+      end
+    end
+  end
+end
diff --git a/test/fixtures/geocoder_ca_madison_square_garden.json b/test/fixtures/geocoder_ca_madison_square_garden.json
new file mode 100644
index 00000000..7592108f
--- /dev/null
+++ b/test/fixtures/geocoder_ca_madison_square_garden.json
@@ -0,0 +1 @@
+test({"longt":"-73.992006","latt":"40.749101"});
diff --git a/test/fixtures/geocoder_ca_no_results.json b/test/fixtures/geocoder_ca_no_results.json
new file mode 100644
index 00000000..e30a039f
--- /dev/null
+++ b/test/fixtures/geocoder_ca_no_results.json
@@ -0,0 +1 @@
+test({"longt":"-0.000000","error":{"description":"Postal Code is not in the proper Format.","code":"005"},"latt":"176946676.000000"});
diff --git a/test/fixtures/geocoder_ca_reverse.json b/test/fixtures/geocoder_ca_reverse.json
new file mode 100644
index 00000000..85001ff7
--- /dev/null
+++ b/test/fixtures/geocoder_ca_reverse.json
@@ -0,0 +1,34 @@
+test({
+  "latt":"45.423733",
+  "longt":"-75.676333",
+  "inlatt":"45.424035",
+  "inlongt":"-75.675941",
+  "betweenRoad1":"Chapel",
+  "betweenRoad2":"Russell",
+  "distance":"0.034",
+  "stnumber":"289",
+  "staddress":"Somerset ST E",
+  "city":"Ottawa",
+  "prov":"ON",
+  "postal":"K1N6W1",
+  "NearRoad":"Somerset ST E",
+  "NearRoadDistance":"0.013",
+  "intersection":{
+    "lattx":"45.423733",
+    "longtx":"-75.676333",
+    "distance":"0.045",
+    "street1":"Somerset St E",
+    "street2":"Russell Ave",
+    "city":"OTTAWA",
+    "prov":"ON"
+  },
+  "major_intersection":{
+    "lattx":"45.4241623853",
+    "longtx":"-75.6753026518",
+    "distance":"0.052",
+    "street1":"Chapel St",
+    "street2":"Somerset St E",
+    "city":"OTTAWA",
+    "prov":"ON"
+  }
+});
diff --git a/test/geocoder_test.rb b/test/geocoder_test.rb
index 4c62ec1f..3b45bd1b 100644
--- a/test/geocoder_test.rb
+++ b/test/geocoder_test.rb
@@ -170,6 +170,16 @@ class GeocoderTest < Test::Unit::TestCase
   end
 
 
+  # --- Geocoder.ca ---
+
+  def test_geocoder_ca_result_components
+    Geocoder::Configuration.lookup = :geocoder_ca
+    result = Geocoder.search(45.423733, -75.676333)
+    assert_equal "CA", result.country_code
+    assert_equal "289 Somerset ST E, Ottawa, ON K1N6W1, Canada", result.address
+  end
+
+
   # --- FreeGeoIp ---
 
   def test_freegeoip_result_on_ip_address_search
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 38de15d0..92c0681b 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -72,6 +72,19 @@ module Geocoder
       end
     end
 
+    class GeocoderCa < Base
+      private #-----------------------------------------------------------------
+      def fetch_raw_data(query, reverse = false)
+        raise TimeoutError if query == "timeout"
+        if reverse
+          read_fixture "geocoder_ca_reverse.json"
+        else
+          file = query == "no results" ? :no_results : :madison_square_garden
+          read_fixture "geocoder_ca_#{file}.json"
+        end
+      end
+    end
+
     class Freegeoip < Base
       private #-----------------------------------------------------------------
       def fetch_raw_data(query, reverse = false)
-- 
GitLab