Permalink
Browse files

manual merge

  • Loading branch information...
2 parents 1b5f50c + 6571d6f commit c40e2c9659feaf71f04add42972983680ee5774e Andre Lewis committed Feb 22, 2009
Showing with 113 additions and 27 deletions.
  1. +2 −0 lib/geokit.rb
  2. +39 −26 lib/geokit/geocoders.rb
  3. +16 −0 lib/geokit/mappable.rb
  4. +5 −0 test/test_geoloc.rb
  5. +29 −1 test/test_google_geocoder.rb
  6. +22 −0 test/test_inflector.rb
View
@@ -21,6 +21,8 @@ def self.#{sym}=(obj)
end
end
+path = File.expand_path(File.dirname(__FILE__))
+$: << path unless $:.include?(path)
require 'geokit/geocoders'
require 'geokit/mappable'
@@ -220,7 +220,6 @@ def self.add_ampersand(url)
end
end
-
# Geocoder Us geocoder implementation. Requires the Geokit::Geocoders::GEOCODER_US variable to
# contain true or false based upon whether authentication is to occur. Conforms to the
# interface set by the Geocoder class.
@@ -397,30 +396,16 @@ def self.xml2GeoLoc(xml)
doc=REXML::Document.new(xml)
if doc.elements['//kml/Response/Status/code'].text == '200'
- res = GeoLoc.new
- coordinates=doc.elements['//coordinates'].text.to_s.split(',')
-
- #basics
- res.lat=coordinates[1]
- res.lng=coordinates[0]
- res.country_code=doc.elements['//CountryNameCode'].text if doc.elements['//CountryNameCode']
- res.provider='google'
-
- #extended -- false if not not available
- res.city = doc.elements['//LocalityName'].text if doc.elements['//LocalityName']
- res.state = doc.elements['//AdministrativeAreaName'].text if doc.elements['//AdministrativeAreaName']
- res.full_address = doc.elements['//address'].text if doc.elements['//address'] # google provides it
- res.zip = doc.elements['//PostalCodeNumber'].text if doc.elements['//PostalCodeNumber']
- res.street_address = doc.elements['//ThoroughfareName'].text if doc.elements['//ThoroughfareName']
- # Translate accuracy into Yahoo-style token address, street, zip, zip+4, city, state, country
- # For Google, 1=low accuracy, 8=high accuracy
- # old way -- address_details=doc.elements['//AddressDetails','urn:oasis:names:tc:ciq:xsdschema:xAL:2.0']
- address_details=doc.elements['//*[local-name() = "AddressDetails"]']
- accuracy = address_details ? address_details.attributes['Accuracy'].to_i : 0
- res.precision=%w{unknown country state state city zip zip+4 street address}[accuracy]
- res.success=true
-
- return res
+ results = nil
+ doc.each_element('//Placemark') do |e|
+ g = do_placemark(e)
+ if results.nil?
+ results = g
+ else
+ results.push(g)
+ end
+ end
+ return results
else
logger.info "Google was unable to geocode address: "+address
return GeoLoc.new
@@ -430,6 +415,33 @@ def self.xml2GeoLoc(xml)
logger.error "Caught an error during Google geocoding call: "+$!
return GeoLoc.new
end
+
+ def self.do_placemark(doc)
+ res = GeoLoc.new
+ coordinates=doc.elements['.//coordinates'].text.to_s.split(',')
+
+ #basics
+ res.lat=coordinates[1]
+ res.lng=coordinates[0]
+ res.country_code=doc.elements['.//CountryNameCode'].text if doc.elements['.//CountryNameCode']
+ res.provider='google'
+
+ #extended -- false if not not available
+ res.city = doc.elements['.//LocalityName'].text if doc.elements['.//LocalityName']
+ res.state = doc.elements['.//AdministrativeAreaName'].text if doc.elements['.//AdministrativeAreaName']
+ res.full_address = doc.elements['.//address'].text if doc.elements['.//address'] # google provides it
+ res.zip = doc.elements['.//PostalCodeNumber'].text if doc.elements['.//PostalCodeNumber']
+ res.street_address = doc.elements['.//ThoroughfareName'].text if doc.elements['.//ThoroughfareName']
+ # Translate accuracy into Yahoo-style token address, street, zip, zip+4, city, state, country
+ # For Google, 1=low accuracy, 8=high accuracy
+ # old way -- address_details=doc.elements['.//AddressDetails','urn:oasis:names:tc:ciq:xsdschema:xAL:2.0']
+ address_details=doc.elements['.//*[local-name() = "AddressDetails"]']
+ accuracy = address_details ? address_details.attributes['Accuracy'].to_i : 0
+ res.precision=%w{unknown country state state city zip zip+4 street address building}[accuracy]
+ res.success=true
+
+ return res
+ end
end
@@ -475,6 +487,7 @@ class IpGeocoder < Geocoder
# longitude, city, and country code. Sets the success attribute to false if the ip
# parameter does not match an ip address.
def self.do_geocode(ip)
+ return Geoloc.new if '0.0.0.0' == ip
return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
url = "http://api.hostip.info/get_html.php?ip=#{ip}&position=true"
response = self.call_geocoder_service(url)
@@ -505,7 +518,7 @@ def self.parse_body(body) # :nodoc:
res
end
end
-
+
# -------------------------------------------------------------------------------------------
# The Multi Geocoder
# -------------------------------------------------------------------------------------------
@@ -1,3 +1,4 @@
+require 'forwardable'
module Geokit
# Contains class and instance methods providing distance calcuation services. This
@@ -291,6 +292,8 @@ def self.normalize(thing,other=nil)
# the "full address" method for geocoders that do not provide a
# full address in their results (for example, Yahoo), and the "is_us" method.
class GeoLoc < LatLng
+ extend Forwardable
+
# Location attributes. Full address is a concatenation of all values. For example:
# 100 Spear St, San Francisco, CA, 94101, US
attr_accessor :street_address, :city, :state, :zip, :country_code, :full_address
@@ -303,6 +306,8 @@ class GeoLoc < LatLng
# Constructor expects a hash of symbols to correspond with attributes.
def initialize(h={})
+ @results = [self]
+
@street_address=h[:street_address]
@city=h[:city]
@state=h[:state]
@@ -362,6 +367,17 @@ def to_geocodeable_s
a.delete_if { |e| !e || e == '' }
a.join(', ')
end
+
+ def_delegators :@results, :each, :push, :size, :map
+ def_delegator :@results, :[], :pick
+
+ def all
+ @results.dup
+ end
+
+ def to_yaml_properties
+ (instance_variables - ['@results']).sort
+ end
# Returns a string representation of the instance.
def to_s
View
@@ -46,4 +46,9 @@ def test_hash
@another = Geokit::GeoLoc.new @loc.to_hash
assert_equal @loc, @another
end
+
+ def test_all
+ assert_equal [@loc], @loc.all
+ end
+
end
@@ -12,6 +12,8 @@ class GoogleGeocoderTest < BaseGeocoderTest #:nodoc: all
<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://earth.google.com/kml/2.0"><Response><name>San Francisco</name><Status><code>200</code><request>geocode</request></Status><Placemark><address>San Francisco, CA, USA</address><AddressDetails Accuracy="4" xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"><Country><CountryNameCode>US</CountryNameCode><AdministrativeArea><AdministrativeAreaName>CA</AdministrativeAreaName><Locality><LocalityName>San Francisco</LocalityName></Locality></AdministrativeArea></Country></AddressDetails><Point><coordinates>-122.418333,37.775000,0</coordinates></Point></Placemark></Response></kml>
EOF
+ GOOGLE_MULTI="<?xml version='1.0' encoding='UTF-8'?>\n<kml xmlns='http://earth.google.com/kml/2.0'><Response>\n <name>via Sandro Pertini 8, Ossona, MI</name>\n <Status>\n <code>200</code>\n <request>geocode</request>\n </Status>\n <Placemark id='p1'>\n <address>Via Sandro Pertini, 8, 20010 Mesero MI, Italy</address>\n <AddressDetails Accuracy='8' xmlns='urn:oasis:names:tc:ciq:xsdschema:xAL:2.0'><Country><CountryNameCode>IT</CountryNameCode><CountryName>Italy</CountryName><AdministrativeArea><AdministrativeAreaName>Lombardy</AdministrativeAreaName><SubAdministrativeArea><SubAdministrativeAreaName>Milan</SubAdministrativeAreaName><Locality><LocalityName>Mesero</LocalityName><Thoroughfare><ThoroughfareName>8 Via Sandro Pertini</ThoroughfareName></Thoroughfare><PostalCode><PostalCodeNumber>20010</PostalCodeNumber></PostalCode></Locality></SubAdministrativeArea></AdministrativeArea></Country></AddressDetails>\n <Point><coordinates>8.8527131,45.4966243,0</coordinates></Point>\n </Placemark>\n <Placemark id='p2'>\n <address>Via Sandro Pertini, 20010 Ossona MI, Italy</address>\n <AddressDetails Accuracy='6' xmlns='urn:oasis:names:tc:ciq:xsdschema:xAL:2.0'><Country><CountryNameCode>IT</CountryNameCode><CountryName>Italy</CountryName><AdministrativeArea><AdministrativeAreaName>Lombardy</AdministrativeAreaName><SubAdministrativeArea><SubAdministrativeAreaName>Milan</SubAdministrativeAreaName><Locality><LocalityName>Ossona</LocalityName><Thoroughfare><ThoroughfareName>Via Sandro Pertini</ThoroughfareName></Thoroughfare><PostalCode><PostalCodeNumber>20010</PostalCodeNumber></PostalCode></Locality></SubAdministrativeArea></AdministrativeArea></Country></AddressDetails>\n <Point><coordinates>8.9023200,45.5074444,0</coordinates></Point>\n </Placemark>\n</Response></kml>\n"
+
def setup
super
@google_full_hash = {:street_address=>"100 Spear St", :city=>"San Francisco", :state=>"CA", :zip=>"94105", :country_code=>"US"}
@@ -85,4 +87,30 @@ def test_service_unavailable
Geokit::Geocoders::GoogleGeocoder.expects(:call_geocoder_service).with(url).returns(response)
assert !Geokit::Geocoders::GoogleGeocoder.geocode(@google_city_loc).success
end
-end
+
+ def test_multiple_results
+ #Geokit::Geocoders::GoogleGeocoder.do_geocode('via Sandro Pertini 8, Ossona, MI')
+ response = MockSuccess.new
+ response.expects(:body).returns(GOOGLE_MULTI)
+ url = "http://maps.google.com/maps/geo?q=#{Geokit::Inflector.url_escape('via Sandro Pertini 8, Ossona, MI')}&output=xml&key=Google&oe=utf-8"
+ Geokit::Geocoders::GoogleGeocoder.expects(:call_geocoder_service).with(url).returns(response)
+ res=Geokit::Geocoders::GoogleGeocoder.geocode('via Sandro Pertini 8, Ossona, MI')
+ assert_equal "Lombardy", res.state
+ assert_equal "Mesero", res.city
+ assert_equal "45.4966243,8.8527131", res.ll
+ assert !res.is_us?
+ assert_equal "Via Sandro Pertini, 8, 20010 Mesero MI, Italy", res.full_address
+ assert_equal "8 Via Sandro Pertini", res.street_address
+ assert_equal "google", res.provider
+
+ assert_equal 2, res.size
+ res = res.pick(1)
+ assert_equal "Lombardy", res.state
+ assert_equal "Ossona", res.city
+ assert_equal "45.5074444,8.90232", res.ll
+ assert !res.is_us?
+ assert_equal "Via Sandro Pertini, 20010 Ossona MI, Italy", res.full_address
+ assert_equal "Via Sandro Pertini", res.street_address
+ assert_equal "google", res.provider
+ end
+end
@@ -0,0 +1,22 @@
+require 'test/unit'
+require 'lib/geokit'
+
+class InflectorTest < Test::Unit::TestCase #:nodoc: all
+
+ def test_titleize
+ assert_equal 'Sugar Grove', Geokit::Inflector.titleize('Sugar Grove')
+ assert_equal 'Sugar Grove', Geokit::Inflector.titleize('Sugar grove')
+ assert_equal 'Sugar Grove', Geokit::Inflector.titleize('sugar Grove')
+ assert_equal 'Sugar Grove', Geokit::Inflector.titleize('sugar grove')
+ end
+
+ def test_titleize_with_unicode
+ assert_equal 'Borås', Geokit::Inflector.titleize('Borås')
+ assert_equal 'Borås', Geokit::Inflector.titleize('borås')
+ assert_equal 'Borås (Abc)', Geokit::Inflector.titleize('Borås (Abc)')
+ assert_equal 'Borås (Abc)', Geokit::Inflector.titleize('Borås (abc)')
+ assert_equal 'Borås (Abc)', Geokit::Inflector.titleize('borås (Abc)')
+ assert_equal 'Borås (Abc)', Geokit::Inflector.titleize('borås (abc)')
+ end
+
+end

0 comments on commit c40e2c9

Please sign in to comment.