geokit 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -54,7 +54,7 @@ If you're using this gem by itself, here are the configuration options:
54
54
  # This is the timeout value in seconds to be used for calls to the geocoder web
55
55
  # services. For no timeout at all, comment out the setting. The timeout unit
56
56
  # is in seconds.
57
- Geokit::Geocoders::timeout = 3
57
+ Geokit::Geocoders::request_timeout = 3
58
58
 
59
59
  # These settings are used if web service calls must be routed through a proxy.
60
60
  # These setting can be nil if not needed, otherwise, addr and port must be
@@ -142,26 +142,26 @@ The Google Geocoder sports a number of useful tricks that elevate it a little bi
142
142
 
143
143
  In addition, you can use viewport or country code biasing to make sure the geocoders prefers results within a specific area. Say we wanted to geocode the city of Syracuse in Italy. A normal geocoding query would look like this:
144
144
 
145
- irb> res = Geokit::Geocoder::GoogleGeocoder.geocode('Syracuse')
145
+ irb> res = Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse')
146
146
  irb> res.full_address
147
147
  => "Syracuse, NY, USA"
148
148
 
149
149
  Not exactly what we were looking for. We know that Syracuse is in Italy, so we can tell the Google Geocoder to prefer results from Italy first, and then wander the Syracuses of the world. To do that, we have to pass Italy's ccTLD (country code top-level domain) to the `:bias` option of the `geocode` method. You can find a comprehensive list of all ccTLDs here: http://en.wikipedia.org/wiki/CcTLD.
150
150
 
151
- irb> res = Geokit::Geocoder::GoogleGeocoder.geocode('Syracuse', :bias => 'it')
151
+ irb> res = Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse', :bias => 'it')
152
152
  irb> res.full_address
153
153
  => "Syracuse, Italy"
154
154
 
155
155
  Alternatively, we can speficy the geocoding bias as a bounding box object. Say we wanted to geocode the Winnetka district in Los Angeles.
156
156
 
157
- irb> res = Geokit::Geocoder::GoogleGeocoder.geocode('Winnetka')
157
+ irb> res = Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka')
158
158
  irb> res.full_address
159
159
  => "Winnetka, IL, USA"
160
160
 
161
161
  Not it. What we can do is tell the geocoder to return results only from in and around LA.
162
162
 
163
- irb> la_bounds = Geokit::Geocoder::GoogleGeocoder.geocode('Los Angeles').suggested_bounds
164
- irb> res = Geokit::Geocoder::GoogleGeocoder.geocode('Winnetka', :bias => la_bounds)
163
+ irb> la_bounds = Geokit::Geocoders::GoogleGeocoder.geocode('Los Angeles').suggested_bounds
164
+ irb> res = Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka', :bias => la_bounds)
165
165
  irb> res.full_address
166
166
  => "Winnetka, California, USA"
167
167
 
data/Rakefile CHANGED
@@ -1,9 +1,11 @@
1
1
  # -*- ruby -*-
2
2
 
3
+ require "rake/gempackagetask"
3
4
  require 'rubygems'
4
5
  require 'hoe'
5
6
  require './lib/geokit.rb'
6
7
 
8
+
7
9
  # undefined method `empty?' for nil:NilClass
8
10
  # /Library/Ruby/Site/1.8/rubygems/specification.rb:886:in `validate'
9
11
  class NilClass
data/geokit.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{geokit}
5
- s.version = "1.5.0"
5
+ s.version = "1.6.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Andre Lewis and Bill Eisenhauer"]
@@ -10,7 +10,12 @@ Gem::Specification.new do |s|
10
10
  s.description = %q{Geokit Gem}
11
11
  s.email = ["andre@earthcode.com / bill_eisenhauer@yahoo.com"]
12
12
  s.extra_rdoc_files = ["Manifest.txt", "README.markdown"]
13
- s.files = ["Manifest.txt", "README.markdown", "Rakefile", "lib/geokit/geocoders.rb", "lib/geokit.rb", "lib/geokit/mappable.rb", "test/test_base_geocoder.rb", "test/test_bounds.rb", "test/test_ca_geocoder.rb", "test/test_geoloc.rb", "test/test_google_geocoder.rb", "test/test_latlng.rb", "test/test_multi_geocoder.rb", "test/test_us_geocoder.rb", "test/test_yahoo_geocoder.rb"]
13
+ s.files = ["Manifest.txt", "README.markdown", "Rakefile", "lib/geokit/geocoders.rb", "lib/geokit.rb",
14
+ "lib/geokit/mappable.rb", "test/test_base_geocoder.rb", "test/test_bounds.rb",
15
+ "test/test_ca_geocoder.rb", "test/test_geoloc.rb", "test/test_google_geocoder3.rb",
16
+ "test/test_google_geocoder.rb", "test/test_latlng.rb", "test/test_multi_geocoder.rb",
17
+ "test/test_us_geocoder.rb", "test/test_yahoo_geocoder.rb"
18
+ ]
14
19
  s.has_rdoc = true
15
20
  s.homepage = %q{http://geokit.rubyforge.org}
16
21
  s.rdoc_options = ["--main", "README.markdown"]
@@ -18,15 +23,16 @@ Gem::Specification.new do |s|
18
23
  s.rubyforge_project = %q{geokit}
19
24
  s.rubygems_version = %q{1.3.5}
20
25
  s.summary = %q{none}
21
- s.test_files = ["test/test_base_geocoder.rb", "test/test_bounds.rb", "test/test_ca_geocoder.rb", "test/test_geoloc.rb",
22
- "test/test_geoplugin_geocoder.rb", "test/test_google_geocoder.rb", "test/test_google_reverse_geocoder.rb",
23
- "test/test_inflector.rb", "test/test_ipgeocoder.rb", "test/test_latlng.rb", "test/test_multi_geocoder.rb",
24
- "test/test_multi_ip_geocoder.rb", "test/test_us_geocoder.rb", "test/test_yahoo_geocoder.rb"]
25
-
26
+ s.test_files = [
27
+ "test/test_base_geocoder.rb", "test/test_bounds.rb", "test/test_ca_geocoder.rb",
28
+ "test/test_geoloc.rb", "test/test_geoplugin_geocoder.rb", "test/test_google_geocoder3.rb",
29
+ "test/test_google_geocoder.rb", "test/test_google_reverse_geocoder.rb", "test/test_inflector.rb",
30
+ "test/test_ipgeocoder.rb", "test/test_latlng.rb", "test/test_multi_geocoder.rb",
31
+ "test/test_multi_ip_geocoder.rb", "test/test_us_geocoder.rb", "test/test_yahoo_geocoder.rb"
32
+ ]
26
33
  if s.respond_to? :specification_version then
27
34
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
28
35
  s.specification_version = 2
29
36
  end
37
+ s.add_dependency(%q{json_pure})
30
38
  end
31
-
32
-
data/lib/geokit.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Geokit
2
- VERSION = '1.5.0'
2
+ VERSION = '1.6.0'
3
3
  # These defaults are used in Geokit::Mappable.distance_to and in acts_as_mappable
4
4
  @@default_units = :miles
5
5
  @@default_formula = :sphere
@@ -1,9 +1,17 @@
1
1
  require 'net/http'
2
+ require 'ipaddr'
2
3
  require 'rexml/document'
3
4
  require 'yaml'
4
5
  require 'timeout'
5
6
  require 'logger'
6
7
 
8
+ # do this just in case
9
+ begin
10
+ ActiveSupport.nil?
11
+ rescue NameError
12
+ require 'json/pure'
13
+ end
14
+
7
15
  module Geokit
8
16
 
9
17
  class TooManyQueriesError < StandardError; end
@@ -519,7 +527,220 @@ module Geokit
519
527
  end
520
528
  end
521
529
 
530
+ class GoogleGeocoder3 < Geocoder
531
+
532
+ private
533
+ # Template method which does the reverse-geocode lookup.
534
+ def self.do_reverse_geocode(latlng)
535
+ latlng=LatLng.normalize(latlng)
536
+ res = self.call_geocoder_service("http://maps.google.com/maps/api/geocode/json?sensor=false&latlng=#{Geokit::Inflector::url_escape(latlng.ll)}")
537
+ return GeoLoc.new unless (res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPOK))
538
+ json = res.body
539
+ logger.debug "Google reverse-geocoding. LL: #{latlng}. Result: #{json}"
540
+ return self.json2GeoLoc(json)
541
+ end
522
542
 
543
+ # Template method which does the geocode lookup.
544
+ #
545
+ # Supports viewport/country code biasing
546
+ #
547
+ # ==== OPTIONS
548
+ # * :bias - This option makes the Google Geocoder return results biased to a particular
549
+ # country or viewport. Country code biasing is achieved by passing the ccTLD
550
+ # ('uk' for .co.uk, for example) as a :bias value. For a list of ccTLD's,
551
+ # look here: http://en.wikipedia.org/wiki/CcTLD. By default, the geocoder
552
+ # will be biased to results within the US (ccTLD .com).
553
+ #
554
+ # If you'd like the Google Geocoder to prefer results within a given viewport,
555
+ # you can pass a Geokit::Bounds object as the :bias value.
556
+ #
557
+ # ==== EXAMPLES
558
+ # # By default, the geocoder will return Syracuse, NY
559
+ # Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse').country_code # => 'US'
560
+ # # With country code biasing, it returns Syracuse in Sicily, Italy
561
+ # Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse', :bias => :it).country_code # => 'IT'
562
+ #
563
+ # # By default, the geocoder will return Winnetka, IL
564
+ # Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka').state # => 'IL'
565
+ # # When biased to an bounding box around California, it will now return the Winnetka neighbourhood, CA
566
+ # bounds = Geokit::Bounds.normalize([34.074081, -118.694401], [34.321129, -118.399487])
567
+ # Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka', :bias => bounds).state # => 'CA'
568
+ def self.do_geocode(address, options = {})
569
+ bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ''
570
+ address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
571
+ res = self.call_geocoder_service("http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(address_str)}#{bias_str}")
572
+ return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
573
+ json = res.body
574
+ logger.debug "Google geocoding. Address: #{address}. Result: #{json}"
575
+ return self.json2GeoLoc(json, address)
576
+ end
577
+
578
+ def self.construct_bias_string_from_options(bias)
579
+ if bias.is_a?(String) or bias.is_a?(Symbol)
580
+ # country code biasing
581
+ "&region=#{bias.to_s.downcase}"
582
+ elsif bias.is_a?(Bounds)
583
+ # viewport biasing
584
+ Geokit::Inflector::url_escape("&bounds=#{bias.sw.to_s}|#{bias.ne.to_s}")
585
+ end
586
+ end
587
+
588
+ def self.json2GeoLoc(json, address="")
589
+ ret=nil
590
+ begin
591
+ results=::ActiveSupport::JSON.decode(json)
592
+ rescue NameError => e
593
+ results=JSON.parse(json)
594
+ end
595
+
596
+
597
+ if results['status'] == 'OVER_QUERY_LIMIT'
598
+ raise Geokit::TooManyQueriesError
599
+ end
600
+ if results['status'] == 'ZERO_RESULTS'
601
+ return GeoLoc.new
602
+ end
603
+ # this should probably be smarter.
604
+ if !results['status'] == 'OK'
605
+ raise Geokit::Geocoders::GeocodeError
606
+ end
607
+ # location_type stores additional data about the specified location.
608
+ # The following values are currently supported:
609
+ # "ROOFTOP" indicates that the returned result is a precise geocode
610
+ # for which we have location information accurate down to street
611
+ # address precision.
612
+ # "RANGE_INTERPOLATED" indicates that the returned result reflects an
613
+ # approximation (usually on a road) interpolated between two precise
614
+ # points (such as intersections). Interpolated results are generally
615
+ # returned when rooftop geocodes are unavailable for a street address.
616
+ # "GEOMETRIC_CENTER" indicates that the returned result is the
617
+ # geometric center of a result such as a polyline (for example, a
618
+ # street) or polygon (region).
619
+ # "APPROXIMATE" indicates that the returned result is approximate
620
+
621
+ # these do not map well. Perhaps we should guess better based on size
622
+ # of bounding box where it exists? Does it really matter?
623
+ accuracy = {
624
+ "ROOFTOP" => 9,
625
+ "RANGE_INTERPOLATED" => 8,
626
+ "GEOMETRIC_CENTER" => 5,
627
+ "APPROXIMATE" => 4
628
+ }
629
+ results['results'].sort_by{|a|accuracy[a['geometry']['location_type']]}.reverse.each do |addr|
630
+ res=GeoLoc.new
631
+ res.provider = 'google3'
632
+ res.success = true
633
+ res.full_address = addr['formatted_address']
634
+ addr['address_components'].each do |comp|
635
+ case
636
+ when comp['types'].include?("street_number")
637
+ res.street_number = comp['short_name']
638
+ when comp['types'].include?("route")
639
+ res.street_name = comp['long_name']
640
+ when comp['types'].include?("locality")
641
+ res.city = comp['long_name']
642
+ when comp['types'].include?("administrative_area_level_1")
643
+ res.state = comp['short_name']
644
+ res.province = comp['short_name']
645
+ when comp['types'].include?("postal_code")
646
+ res.zip = comp['long_name']
647
+ when comp['types'].include?("country")
648
+ res.country_code = comp['short_name']
649
+ res.country = comp['long_name']
650
+ when comp['types'].include?("administrative_area_level_2")
651
+ res.district = comp['long_name']
652
+ end
653
+ end
654
+ if res.street_name
655
+ res.street_address=[res.street_number,res.street_name].join(' ').strip
656
+ end
657
+ res.accuracy = accuracy[addr['geometry']['location_type']]
658
+ res.precision=%w{unknown country state state city zip zip+4 street address building}[res.accuracy]
659
+ # try a few overrides where we can
660
+ if res.street_name && res.precision=='city'
661
+ res.precision = 'street'
662
+ res.accuracy = 7
663
+ end
664
+
665
+ res.lat=addr['geometry']['location']['lat'].to_f
666
+ res.lng=addr['geometry']['location']['lng'].to_f
667
+
668
+ ne=Geokit::LatLng.new(
669
+ addr['geometry']['viewport']['northeast']['lat'].to_f,
670
+ addr['geometry']['viewport']['northeast']['lng'].to_f
671
+ )
672
+ sw=Geokit::LatLng.new(
673
+ addr['geometry']['viewport']['southwest']['lat'].to_f,
674
+ addr['geometry']['viewport']['southwest']['lng'].to_f
675
+ )
676
+ res.suggested_bounds = Geokit::Bounds.new(sw,ne)
677
+
678
+ if ret
679
+ ret.all.push(res)
680
+ else
681
+ ret=res
682
+ end
683
+ end
684
+ return ret
685
+ end
686
+ end
687
+
688
+ class FCCGeocoder < Geocoder
689
+
690
+ private
691
+ # Template method which does the reverse-geocode lookup.
692
+ def self.do_reverse_geocode(latlng)
693
+ latlng=LatLng.normalize(latlng)
694
+ res = self.call_geocoder_service("http://data.fcc.gov/api/block/find?format=json&latitude=#{Geokit::Inflector::url_escape(latlng.lat.to_s)}&longitude=#{Geokit::Inflector::url_escape(latlng.lng.to_s)}")
695
+ return GeoLoc.new unless (res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPOK))
696
+ json = res.body
697
+ logger.debug "FCC reverse-geocoding. LL: #{latlng}. Result: #{json}"
698
+ return self.json2GeoLoc(json)
699
+ end
700
+
701
+ # Template method which does the geocode lookup.
702
+ #
703
+ # ==== EXAMPLES
704
+ # ll=GeoKit::LatLng.new(40, -85)
705
+ # Geokit::Geocoders::FCCGeocoder.geocode(ll) #
706
+
707
+ # JSON result looks like this
708
+ # => {"County"=>{"name"=>"Wayne", "FIPS"=>"18177"},
709
+ # "Block"=>{"FIPS"=>"181770103002004"},
710
+ # "executionTime"=>"0.099",
711
+ # "State"=>{"name"=>"Indiana", "code"=>"IN", "FIPS"=>"18"},
712
+ # "status"=>"OK"}
713
+
714
+ def self.json2GeoLoc(json, address="")
715
+ ret=nil
716
+ begin
717
+ results=::ActiveSupport::JSON.decode(json)
718
+ rescue NameError => e
719
+ results=JSON.parse(json)
720
+ end
721
+
722
+ if results.has_key?('Err') and results['Err']["msg"] == 'There are no results for this location'
723
+ return GeoLoc.new
724
+ end
725
+ # this should probably be smarter.
726
+ if !results['status'] == 'OK'
727
+ raise Geokit::Geocoders::GeocodeError
728
+ end
729
+
730
+ res = GeoLoc.new
731
+ res.provider = 'fcc'
732
+ res.success = true
733
+ res.precision = 'block'
734
+ res.country_code = 'US'
735
+ res.district = results['County']['name']
736
+ res.district_fips = results['County']['FIPS']
737
+ res.state = results['State']['code']
738
+ res.state_fips = results['State']['FIPS']
739
+ res.block_fips = results['Block']['FIPS']
740
+
741
+ res
742
+ end
743
+ end
523
744
  # -------------------------------------------------------------------------------------------
524
745
  # IP Geocoders
525
746
  # -------------------------------------------------------------------------------------------
@@ -556,14 +777,35 @@ module Geokit
556
777
  # as community contributions.
557
778
  class IpGeocoder < Geocoder
558
779
 
780
+ # A number of non-routable IP ranges.
781
+ #
782
+ # --
783
+ # Sources for these:
784
+ # RFC 3330: Special-Use IPv4 Addresses
785
+ # The bogon list: http://www.cymru.com/Documents/bogon-list.html
786
+
787
+ NON_ROUTABLE_IP_RANGES = [
788
+ IPAddr.new('0.0.0.0/8'), # "This" Network
789
+ IPAddr.new('10.0.0.0/8'), # Private-Use Networks
790
+ IPAddr.new('14.0.0.0/8'), # Public-Data Networks
791
+ IPAddr.new('127.0.0.0/8'), # Loopback
792
+ IPAddr.new('169.254.0.0/16'), # Link local
793
+ IPAddr.new('172.16.0.0/12'), # Private-Use Networks
794
+ IPAddr.new('192.0.2.0/24'), # Test-Net
795
+ IPAddr.new('192.168.0.0/16'), # Private-Use Networks
796
+ IPAddr.new('198.18.0.0/15'), # Network Interconnect Device Benchmark Testing
797
+ IPAddr.new('224.0.0.0/4'), # Multicast
798
+ IPAddr.new('240.0.0.0/4') # Reserved for future use
799
+ ].freeze
800
+
559
801
  private
560
802
 
561
803
  # Given an IP address, returns a GeoLoc instance which contains latitude,
562
804
  # longitude, city, and country code. Sets the success attribute to false if the ip
563
805
  # parameter does not match an ip address.
564
806
  def self.do_geocode(ip, options = {})
565
- return GeoLoc.new if '0.0.0.0' == ip
566
807
  return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
808
+ return GeoLoc.new if self.private_ip_address?(ip)
567
809
  url = "http://api.hostip.info/get_html.php?ip=#{ip}&position=true"
568
810
  response = self.call_geocoder_service(url)
569
811
  response.is_a?(Net::HTTPSuccess) ? parse_body(response.body) : GeoLoc.new
@@ -592,6 +834,15 @@ module Geokit
592
834
  res.success = !(res.city =~ /\(.+\)/)
593
835
  res
594
836
  end
837
+
838
+ # Checks whether the IP address belongs to a private address range.
839
+ #
840
+ # This function is used to reduce the number of useless queries made to
841
+ # the geocoding service. Such queries can occur frequently during
842
+ # integration tests.
843
+ def self.private_ip_address?(ip)
844
+ return NON_ROUTABLE_IP_RANGES.any? { |range| range.include?(ip) }
845
+ end
595
846
  end
596
847
 
597
848
  # -------------------------------------------------------------------------------------------
@@ -287,6 +287,8 @@ module Geokit
287
287
  return thing
288
288
  elsif thing.class.respond_to?(:acts_as_mappable) && thing.class.respond_to?(:distance_column_name)
289
289
  return thing.to_lat_lng
290
+ elsif thing.respond_to? :to_lat_lng
291
+ return thing.to_lat_lng
290
292
  end
291
293
 
292
294
  raise ArgumentError.new("#{thing} (#{thing.class}) cannot be normalized to a LatLng. We tried interpreting it as an array, string, Mappable, etc., but no dice.")
@@ -342,22 +344,26 @@ module Geokit
342
344
 
343
345
  # Location attributes. Full address is a concatenation of all values. For example:
344
346
  # 100 Spear St, San Francisco, CA, 94101, US
345
- attr_accessor :street_address, :city, :state, :zip, :country_code, :country, :full_address, :all, :district, :province
347
+ # Street number and street name are extracted from the street address attribute if they don't exist
348
+ attr_accessor :street_number,:street_name,:street_address, :city, :state, :zip, :country_code, :country, :full_address, :all, :district, :province
346
349
  # Attributes set upon return from geocoding. Success will be true for successful
347
350
  # geocode lookups. The provider will be set to the name of the providing geocoder.
348
351
  # Finally, precision is an indicator of the accuracy of the geocoding.
349
352
  attr_accessor :success, :provider, :precision, :suggested_bounds
350
- # Street number and street name are extracted from the street address attribute.
351
- attr_reader :street_number, :street_name
352
353
  # accuracy is set for Yahoo and Google geocoders, it is a numeric value of the
353
354
  # precision. see http://code.google.com/apis/maps/documentation/geocoding/#GeocodingAccuracy
354
355
  attr_accessor :accuracy
356
+ # FCC Attributes
357
+ attr_accessor :district_fips, :state_fips, :block_fips
358
+
355
359
 
356
360
  # Constructor expects a hash of symbols to correspond with attributes.
357
361
  def initialize(h={})
358
362
  @all = [self]
359
363
 
360
364
  @street_address=h[:street_address]
365
+ @street_number=nil
366
+ @street_name=nil
361
367
  @city=h[:city]
362
368
  @state=h[:state]
363
369
  @zip=h[:zip]
@@ -385,21 +391,22 @@ module Geokit
385
391
  @full_address ? @full_address : to_geocodeable_s
386
392
  end
387
393
 
388
- # Extracts the street number from the street address if the street address
389
- # has a value.
394
+ # Extracts the street number from the street address where possible.
390
395
  def street_number
391
- street_address[/(\d*)/] if street_address
396
+ @street_number ||= street_address[/(\d*)/] if street_address
397
+ @street_number
392
398
  end
393
399
 
394
- # Returns the street name portion of the street address.
400
+ # Returns the street name portion of the street address where possible
395
401
  def street_name
396
- street_address[street_number.length, street_address.length].strip if street_address
402
+ @street_name||=street_address[street_number.length, street_address.length].strip if street_address
403
+ @street_name
397
404
  end
398
405
 
399
406
  # gives you all the important fields as key-value pairs
400
407
  def hash
401
408
  res={}
402
- [:success,:lat,:lng,:country_code,:city,:state,:zip,:street_address,:province,:district,:provider,:full_address,:is_us?,:ll,:precision].each { |s| res[s] = self.send(s.to_s) }
409
+ [:success,:lat,:lng,:country_code,:city,:state,:zip,:street_address,:province,:district,:provider,:full_address,:is_us?,:ll,:precision,:district_fips,:state_fips,:block_fips].each { |s| res[s] = self.send(s.to_s) }
403
410
  res
404
411
  end
405
412
  alias to_hash hash
@@ -411,8 +418,12 @@ module Geokit
411
418
 
412
419
  # Sets the street address after capitalizing each word within the street address.
413
420
  def street_address=(address)
414
- @street_address = Geokit::Inflector::titleize(address) if address
415
- end
421
+ if address and not ['google','google3'].include?(self.provider)
422
+ @street_address = Geokit::Inflector::titleize(address)
423
+ else
424
+ @street_address = address
425
+ end
426
+ end
416
427
 
417
428
  # Returns a comma-delimited string consisting of the street address, city, state,
418
429
  # zip, and country code. Only includes those attributes that are non-blank.
data/test/test_geoloc.rb CHANGED
@@ -65,7 +65,7 @@ class GeoLocTest < Test::Unit::TestCase #:nodoc: all
65
65
  @loc.zip = '94105'
66
66
  @loc.country_code = 'US'
67
67
  assert_equal(
68
- "--- !ruby/object:Geokit::GeoLoc \ncity: San Francisco\ncountry_code: US\nfull_address: \nlat: \nlng: \nprecision: unknown\nprovince: \nstate: CA\nstreet_address: \nsuccess: false\nzip: \"94105\"\n",
68
+ "--- !ruby/object:Geokit::GeoLoc \ncity: San Francisco\ncountry_code: US\nfull_address: \nlat: \nlng: \nprecision: unknown\nprovince: \nstate: CA\nstreet_address: \nstreet_name: \nstreet_number: \nsuccess: false\nzip: \"94105\"\n",
69
69
  @loc.to_yaml)
70
70
  end
71
71
 
@@ -33,8 +33,8 @@ class IpGeocoderTest < BaseGeocoderTest #:nodoc: all
33
33
  GeoKit::Geocoders::GeoPluginGeocoder.expects(:call_geocoder_service).with(url).returns(success)
34
34
  location = GeoKit::Geocoders::GeoPluginGeocoder.geocode('200.150.38.66')
35
35
  assert_not_nil location
36
- assert_equal -19.916700, location.lat
37
- assert_equal -43.933300, location.lng
36
+ assert_equal(-19.916700, location.lat)
37
+ assert_equal(-43.933300, location.lng)
38
38
  assert_equal "Belo Horizonte", location.city
39
39
  assert_equal "Minas Gerais", location.state
40
40
  assert_equal "BR", location.country_code
@@ -186,7 +186,7 @@ class GoogleGeocoderTest < BaseGeocoderTest #:nodoc: all
186
186
 
187
187
  assert_equal "Plaza de la Puerta del Sol, 28013, Madrid, Spain", res.full_address
188
188
  assert_equal "28013", res.zip
189
- assert_equal "Plaza De La Puerta Del Sol", res.street_address
189
+ assert_equal "Plaza de la Puerta del Sol", res.street_address
190
190
  end
191
191
 
192
192
  def test_country_code_biasing
@@ -0,0 +1,536 @@
1
+ require File.join(File.dirname(__FILE__), 'test_base_geocoder')
2
+
3
+ Geokit::Geocoders::google = 'Google'
4
+
5
+ class GoogleGeocoder3Test < BaseGeocoderTest #:nodoc: all
6
+
7
+ GOOGLE3_FULL=%q/
8
+ {
9
+ "status": "OK",
10
+ "results": [ {
11
+ "types": [ "street_address" ],
12
+ "formatted_address": "100 Spear St, San Francisco, CA 94105, USA",
13
+ "address_components": [ {
14
+ "long_name": "100",
15
+ "short_name": "100",
16
+ "types": [ "street_number" ]
17
+ }, {
18
+ "long_name": "Spear St",
19
+ "short_name": "Spear St",
20
+ "types": [ "route" ]
21
+ }, {
22
+ "long_name": "San Francisco",
23
+ "short_name": "San Francisco",
24
+ "types": [ "locality", "political" ]
25
+ }, {
26
+ "long_name": "San Francisco",
27
+ "short_name": "San Francisco",
28
+ "types": [ "administrative_area_level_3", "political" ]
29
+ }, {
30
+ "long_name": "San Francisco",
31
+ "short_name": "San Francisco",
32
+ "types": [ "administrative_area_level_2", "political" ]
33
+ }, {
34
+ "long_name": "California",
35
+ "short_name": "CA",
36
+ "types": [ "administrative_area_level_1", "political" ]
37
+ }, {
38
+ "long_name": "United States",
39
+ "short_name": "US",
40
+ "types": [ "country", "political" ]
41
+ }, {
42
+ "long_name": "94105",
43
+ "short_name": "94105",
44
+ "types": [ "postal_code" ]
45
+ } ],
46
+ "geometry": {
47
+ "location": {
48
+ "lat": 37.7921509,
49
+ "lng": -122.3940000
50
+ },
51
+ "location_type": "ROOFTOP",
52
+ "viewport": {
53
+ "southwest": {
54
+ "lat": 37.7890033,
55
+ "lng": -122.3971476
56
+ },
57
+ "northeast": {
58
+ "lat": 37.7952985,
59
+ "lng": -122.3908524
60
+ }
61
+ }
62
+ }
63
+ } ]
64
+ }
65
+ /.strip
66
+
67
+ GOOGLE3_CITY=%q/
68
+ {
69
+ "status": "OK",
70
+ "results": [ {
71
+ "types": [ "locality", "political" ],
72
+ "formatted_address": "San Francisco, CA, USA",
73
+ "address_components": [ {
74
+ "long_name": "San Francisco",
75
+ "short_name": "San Francisco",
76
+ "types": [ "locality", "political" ]
77
+ }, {
78
+ "long_name": "San Francisco",
79
+ "short_name": "San Francisco",
80
+ "types": [ "administrative_area_level_2", "political" ]
81
+ }, {
82
+ "long_name": "California",
83
+ "short_name": "CA",
84
+ "types": [ "administrative_area_level_1", "political" ]
85
+ }, {
86
+ "long_name": "United States",
87
+ "short_name": "US",
88
+ "types": [ "country", "political" ]
89
+ } ],
90
+ "geometry": {
91
+ "location": {
92
+ "lat": 37.7749295,
93
+ "lng": -122.4194155
94
+ },
95
+ "location_type": "APPROXIMATE",
96
+ "viewport": {
97
+ "southwest": {
98
+ "lat": 37.7043396,
99
+ "lng": -122.5474749
100
+ },
101
+ "northeast": {
102
+ "lat": 37.8454521,
103
+ "lng": -122.2913561
104
+ }
105
+ },
106
+ "bounds": {
107
+ "southwest": {
108
+ "lat": 37.7034000,
109
+ "lng": -122.5270000
110
+ },
111
+ "northeast": {
112
+ "lat": 37.8120000,
113
+ "lng": -122.3482000
114
+ }
115
+ }
116
+ }
117
+ } ]
118
+ }
119
+ /.strip
120
+ GOOGLE3_MULTI=%q/
121
+ {
122
+ "status": "OK",
123
+ "results": [ {
124
+ "types": [ "street_address" ],
125
+ "formatted_address": "Via Sandro Pertini, 8, 20010 Mesero MI, Italy",
126
+ "address_components": [ {
127
+ "long_name": "8",
128
+ "short_name": "8",
129
+ "types": [ "street_number" ]
130
+ }, {
131
+ "long_name": "Via Sandro Pertini",
132
+ "short_name": "Via Sandro Pertini",
133
+ "types": [ "route" ]
134
+ }, {
135
+ "long_name": "Mesero",
136
+ "short_name": "Mesero",
137
+ "types": [ "locality", "political" ]
138
+ }, {
139
+ "long_name": "Milan",
140
+ "short_name": "MI",
141
+ "types": [ "administrative_area_level_2", "political" ]
142
+ }, {
143
+ "long_name": "Lombardy",
144
+ "short_name": "Lombardy",
145
+ "types": [ "administrative_area_level_1", "political" ]
146
+ }, {
147
+ "long_name": "Italy",
148
+ "short_name": "IT",
149
+ "types": [ "country", "political" ]
150
+ }, {
151
+ "long_name": "20010",
152
+ "short_name": "20010",
153
+ "types": [ "postal_code" ]
154
+ } ],
155
+ "geometry": {
156
+ "location": {
157
+ "lat": 45.4966218,
158
+ "lng": 8.8526940
159
+ },
160
+ "location_type": "RANGE_INTERPOLATED",
161
+ "viewport": {
162
+ "southwest": {
163
+ "lat": 45.4934754,
164
+ "lng": 8.8495559
165
+ },
166
+ "northeast": {
167
+ "lat": 45.4997707,
168
+ "lng": 8.8558512
169
+ }
170
+ },
171
+ "bounds": {
172
+ "southwest": {
173
+ "lat": 45.4966218,
174
+ "lng": 8.8526940
175
+ },
176
+ "northeast": {
177
+ "lat": 45.4966243,
178
+ "lng": 8.8527131
179
+ }
180
+ }
181
+ },
182
+ "partial_match": true
183
+ },
184
+ {
185
+ "types": [ "route" ],
186
+ "formatted_address": "Via Sandro Pertini, 20010 Ossona MI, Italy",
187
+ "address_components": [ {
188
+ "long_name": "Via Sandro Pertini",
189
+ "short_name": "Via Sandro Pertini",
190
+ "types": [ "route" ]
191
+ }, {
192
+ "long_name": "Ossona",
193
+ "short_name": "Ossona",
194
+ "types": [ "locality", "political" ]
195
+ }, {
196
+ "long_name": "Milan",
197
+ "short_name": "MI",
198
+ "types": [ "administrative_area_level_2", "political" ]
199
+ }, {
200
+ "long_name": "Lombardy",
201
+ "short_name": "Lombardy",
202
+ "types": [ "administrative_area_level_1", "political" ]
203
+ }, {
204
+ "long_name": "Italy",
205
+ "short_name": "IT",
206
+ "types": [ "country", "political" ]
207
+ }, {
208
+ "long_name": "20010",
209
+ "short_name": "20010",
210
+ "types": [ "postal_code" ]
211
+ } ],
212
+ "geometry": {
213
+ "location": {
214
+ "lat": 45.5074444,
215
+ "lng": 8.9023200
216
+ },
217
+ "location_type": "GEOMETRIC_CENTER",
218
+ "viewport": {
219
+ "southwest": {
220
+ "lat": 45.5043320,
221
+ "lng": 8.8990670
222
+ },
223
+ "northeast": {
224
+ "lat": 45.5106273,
225
+ "lng": 8.9053622
226
+ }
227
+ },
228
+ "bounds": {
229
+ "southwest": {
230
+ "lat": 45.5064427,
231
+ "lng": 8.9020024
232
+ },
233
+ "northeast": {
234
+ "lat": 45.5085166,
235
+ "lng": 8.9024268
236
+ }
237
+ }
238
+ }
239
+ }
240
+ ]
241
+ }
242
+ /.strip
243
+ GOOGLE3_REVERSE_MADRID=%q/
244
+ {
245
+ "status": "OK",
246
+ "results": [ {
247
+ "types": [ ],
248
+ "formatted_address": "Calle de las Carretas, 28013 Madrid, Spain",
249
+ "address_components": [ {
250
+ "long_name": "Calle de las Carretas",
251
+ "short_name": "Calle de las Carretas",
252
+ "types": [ "route" ]
253
+ }, {
254
+ "long_name": "Madrid",
255
+ "short_name": "Madrid",
256
+ "types": [ "locality", "political" ]
257
+ }, {
258
+ "long_name": "Madrid",
259
+ "short_name": "M",
260
+ "types": [ "administrative_area_level_2", "political" ]
261
+ }, {
262
+ "long_name": "Madrid",
263
+ "short_name": "Madrid",
264
+ "types": [ "administrative_area_level_1", "political" ]
265
+ }, {
266
+ "long_name": "Spain",
267
+ "short_name": "ES",
268
+ "types": [ "country", "political" ]
269
+ }, {
270
+ "long_name": "28013",
271
+ "short_name": "28013",
272
+ "types": [ "postal_code" ]
273
+ } ],
274
+ "geometry": {
275
+ "location": {
276
+ "lat": 40.4166824,
277
+ "lng": -3.7033411
278
+ },
279
+ "location_type": "APPROXIMATE",
280
+ "viewport": {
281
+ "southwest": {
282
+ "lat": 40.4135351,
283
+ "lng": -3.7064880
284
+ },
285
+ "northeast": {
286
+ "lat": 40.4198303,
287
+ "lng": -3.7001927
288
+ }
289
+ },
290
+ "bounds": {
291
+ "southwest": {
292
+ "lat": 40.4166419,
293
+ "lng": -3.7033685
294
+ },
295
+ "northeast": {
296
+ "lat": 40.4167235,
297
+ "lng": -3.7033122
298
+ }
299
+ }
300
+ }
301
+ } ]
302
+ }
303
+ /
304
+ GOOGLE3_COUNTRY_CODE_BIASED_RESULT=%q/
305
+ {
306
+ "status": "OK",
307
+ "results": [ {
308
+ "types": [ "administrative_area_level_2", "political" ],
309
+ "formatted_address": "Syracuse, Italy",
310
+ "address_components": [ {
311
+ "long_name": "Syracuse",
312
+ "short_name": "SR",
313
+ "types": [ "administrative_area_level_2", "political" ]
314
+ }, {
315
+ "long_name": "Sicily",
316
+ "short_name": "Sicily",
317
+ "types": [ "administrative_area_level_1", "political" ]
318
+ }, {
319
+ "long_name": "Italy",
320
+ "short_name": "IT",
321
+ "types": [ "country", "political" ]
322
+ } ],
323
+ "geometry": {
324
+ "location": {
325
+ "lat": 37.0630218,
326
+ "lng": 14.9856176
327
+ },
328
+ "location_type": "APPROXIMATE",
329
+ "viewport": {
330
+ "southwest": {
331
+ "lat": 36.7775664,
332
+ "lng": 14.4733800
333
+ },
334
+ "northeast": {
335
+ "lat": 37.3474070,
336
+ "lng": 15.4978552
337
+ }
338
+ },
339
+ "bounds": {
340
+ "southwest": {
341
+ "lat": 36.6441736,
342
+ "lng": 14.7724913
343
+ },
344
+ "northeast": {
345
+ "lat": 37.4125978,
346
+ "lng": 15.3367367
347
+ }
348
+ }
349
+ }
350
+ } ]
351
+ }
352
+ /
353
+ GOOGLE3_TOO_MANY=%q/
354
+ {
355
+ "status": "OVER_QUERY_LIMIT"
356
+ }
357
+ /
358
+ def setup
359
+ super
360
+ @google_full_hash = {:street_address=>"100 Spear St", :city=>"San Francisco", :state=>"CA", :zip=>"94105", :country_code=>"US"}
361
+ @google_city_hash = {:city=>"San Francisco", :state=>"CA"}
362
+
363
+ @google_full_loc = Geokit::GeoLoc.new(@google_full_hash)
364
+ @google_city_loc = Geokit::GeoLoc.new(@google_city_hash)
365
+ end
366
+
367
+ def test_google3_full_address
368
+ response = MockSuccess.new
369
+ response.expects(:body).returns(GOOGLE3_FULL)
370
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(@address)}"
371
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
372
+ res=Geokit::Geocoders::GoogleGeocoder3.geocode(@address)
373
+ assert_equal "CA", res.state
374
+ assert_equal "San Francisco", res.city
375
+ assert_equal "37.7921509,-122.394", res.ll # slightly dif from yahoo
376
+ assert res.is_us?
377
+ assert_equal "100 Spear St, San Francisco, CA 94105, USA", res.full_address #slightly different from yahoo
378
+ assert_equal "google3", res.provider
379
+ end
380
+
381
+ def test_google3_full_address_with_geo_loc
382
+ response = MockSuccess.new
383
+ response.expects(:body).returns(GOOGLE3_FULL)
384
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(@full_address_short_zip)}"
385
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
386
+ res=Geokit::Geocoders::GoogleGeocoder3.geocode(@google_full_loc)
387
+ assert_equal "CA", res.state
388
+ assert_equal "San Francisco", res.city
389
+ assert_equal "37.7921509,-122.394", res.ll # slightly dif from yahoo
390
+ assert res.is_us?
391
+ assert_equal "100 Spear St, San Francisco, CA 94105, USA", res.full_address #slightly different from yahoo
392
+ assert_equal "google3", res.provider
393
+ end
394
+
395
+ def test_google3_full_address_accuracy
396
+ response = MockSuccess.new
397
+ response.expects(:body).returns(GOOGLE3_FULL)
398
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(@full_address_short_zip)}"
399
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
400
+ res=Geokit::Geocoders::GoogleGeocoder3.geocode(@google_full_loc)
401
+ assert_equal 9, res.accuracy
402
+ end
403
+
404
+ def test_google3_city
405
+ response = MockSuccess.new
406
+ response.expects(:body).returns(GOOGLE3_CITY)
407
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(@address)}"
408
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
409
+ res=Geokit::Geocoders::GoogleGeocoder3.do_geocode(@address)
410
+ assert_nil res.street_address
411
+ assert_equal "CA", res.state
412
+ assert_equal "San Francisco", res.city
413
+ assert_equal "37.7749295,-122.4194155", res.ll
414
+ assert res.is_us?
415
+ assert_equal "San Francisco, CA, USA", res.full_address
416
+ assert_equal "google3", res.provider
417
+ end
418
+
419
+ def test_google3_city_accuracy
420
+ response = MockSuccess.new
421
+ response.expects(:body).returns(GOOGLE3_CITY)
422
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(@address)}"
423
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
424
+ res=Geokit::Geocoders::GoogleGeocoder3.geocode(@address)
425
+ assert_equal 4, res.accuracy
426
+ end
427
+
428
+ def test_google3_city_with_geo_loc
429
+ response = MockSuccess.new
430
+ response.expects(:body).returns(GOOGLE3_CITY)
431
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(@address)}"
432
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
433
+ res=Geokit::Geocoders::GoogleGeocoder3.geocode(@google_city_loc)
434
+ assert_equal "CA", res.state
435
+ assert_equal "San Francisco", res.city
436
+ assert_equal "37.7749295,-122.4194155", res.ll
437
+ assert res.is_us?
438
+ assert_equal "San Francisco, CA, USA", res.full_address
439
+ assert_nil res.street_address
440
+ assert_equal "google3", res.provider
441
+ end
442
+
443
+ def test_google3_suggested_bounds
444
+ response = MockSuccess.new
445
+ response.expects(:body).returns(GOOGLE3_FULL)
446
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(@full_address_short_zip)}"
447
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
448
+ res = Geokit::Geocoders::GoogleGeocoder3.geocode(@google_full_loc)
449
+
450
+ assert_instance_of Geokit::Bounds, res.suggested_bounds
451
+ assert_equal Geokit::Bounds.new(Geokit::LatLng.new(37.7890033, -122.3971476), Geokit::LatLng.new(37.7952985, -122.3908524)), res.suggested_bounds
452
+ end
453
+
454
+ def test_service_unavailable
455
+ response = MockFailure.new
456
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(@address)}"
457
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
458
+ assert !Geokit::Geocoders::GoogleGeocoder3.geocode(@google_city_loc).success
459
+ end
460
+
461
+ def test_multiple_results
462
+ #Geokit::Geocoders::GoogleGeocoder3.do_geocode('via Sandro Pertini 8, Ossona, MI')
463
+ response = MockSuccess.new
464
+ response.expects(:body).returns(GOOGLE3_MULTI)
465
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector.url_escape('via Sandro Pertini 8, Ossona, MI')}"
466
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
467
+ res=Geokit::Geocoders::GoogleGeocoder3.geocode('via Sandro Pertini 8, Ossona, MI')
468
+ assert_equal "Lombardy", res.state
469
+ assert_equal "Mesero", res.city
470
+ assert_equal "45.4966218,8.852694", res.ll
471
+ assert !res.is_us?
472
+ assert_equal "Via Sandro Pertini, 8, 20010 Mesero MI, Italy", res.full_address
473
+ assert_equal "8 Via Sandro Pertini", res.street_address
474
+ assert_equal "google3", res.provider
475
+
476
+ assert_equal 2, res.all.size
477
+ res = res.all[1]
478
+ assert_equal "Lombardy", res.state
479
+ assert_equal "Ossona", res.city
480
+ assert_equal "45.5074444,8.90232", res.ll
481
+ assert !res.is_us?
482
+ assert_equal "Via Sandro Pertini, 20010 Ossona MI, Italy", res.full_address
483
+ assert_equal "Via Sandro Pertini", res.street_address
484
+ assert_equal "google3", res.provider
485
+ end
486
+ #
487
+ def test_reverse_geocode
488
+ #Geokit::Geocoders::GoogleGeocoder3.do_reverse_geocode("40.4167413, -3.7032498")
489
+ madrid = Geokit::GeoLoc.new
490
+ madrid.lat, madrid.lng = "40.4167413", "-3.7032498"
491
+ response = MockSuccess.new
492
+ response.expects(:body).returns(GOOGLE3_REVERSE_MADRID)
493
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&latlng=#{Geokit::Inflector::url_escape(madrid.ll)}"
494
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).
495
+ returns(response)
496
+ res=Geokit::Geocoders::GoogleGeocoder3.do_reverse_geocode(madrid.ll)
497
+
498
+ assert_equal madrid.lat.to_s.slice(1..5), res.lat.to_s.slice(1..5)
499
+ assert_equal madrid.lng.to_s.slice(1..5), res.lng.to_s.slice(1..5)
500
+ assert_equal "ES", res.country_code
501
+ assert_equal "google3", res.provider
502
+
503
+ assert_equal "Madrid", res.city
504
+ assert_equal "Madrid", res.state
505
+
506
+ assert_equal "Spain", res.country
507
+ assert_equal "street", res.precision
508
+ assert_equal true, res.success
509
+
510
+ assert_equal "Calle de las Carretas, 28013 Madrid, Spain", res.full_address
511
+ assert_equal "28013", res.zip
512
+ assert_equal "Calle de las Carretas", res.street_address
513
+ end
514
+
515
+ def test_country_code_biasing
516
+ response = MockSuccess.new
517
+ response.expects(:body).returns(GOOGLE3_COUNTRY_CODE_BIASED_RESULT)
518
+
519
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=Syracuse&region=it"
520
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
521
+ biased_result = Geokit::Geocoders::GoogleGeocoder3.geocode('Syracuse', :bias => 'it')
522
+
523
+ assert_equal 'IT', biased_result.country_code
524
+ assert_equal 'Sicily', biased_result.state
525
+ end
526
+
527
+ def test_too_many_queries
528
+ response = MockSuccess.new
529
+ response.expects(:body).returns(GOOGLE3_TOO_MANY)
530
+ url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector.url_escape(@address)}"
531
+ Geokit::Geocoders::GoogleGeocoder3.expects(:call_geocoder_service).with(url).returns(response)
532
+ assert_raise Geokit::TooManyQueriesError do
533
+ res=Geokit::Geocoders::GoogleGeocoder3.geocode(@address)
534
+ end
535
+ end
536
+ end
@@ -4,8 +4,8 @@ require File.join(File.dirname(__FILE__), 'test_base_geocoder')
4
4
  class IpGeocoderTest < BaseGeocoderTest #:nodoc: all
5
5
 
6
6
  IP_FAILURE=<<-EOF
7
- Country: (Private Address) (XX)
8
- City: (Private Address)
7
+ Country: SWITZERLAND (CH)
8
+ City: (Unknown City)
9
9
  Latitude:
10
10
  Longitude:
11
11
  EOF
@@ -24,10 +24,22 @@ class IpGeocoderTest < BaseGeocoderTest #:nodoc: all
24
24
  Longitude: 12.9167
25
25
  EOF
26
26
 
27
- def setup
28
- super
29
- @success.provider = "hostip"
30
- end
27
+ PRIVATE_IPS_TO_TEST = [
28
+ '10.10.10.10',
29
+ '172.16.1.3',
30
+ '172.22.3.42',
31
+ '172.30.254.164',
32
+ '192.168.1.1',
33
+ '0.0.0.0',
34
+ '127.0.0.1',
35
+ '240.3.4.5',
36
+ '225.1.6.55'
37
+ ].freeze
38
+
39
+ def setup
40
+ super
41
+ @success.provider = "hostip"
42
+ end
31
43
 
32
44
  def test_successful_lookup
33
45
  success = MockSuccess.new
@@ -64,14 +76,24 @@ class IpGeocoderTest < BaseGeocoderTest #:nodoc: all
64
76
  def test_failed_lookup
65
77
  failure = MockSuccess.new
66
78
  failure.expects(:body).returns(IP_FAILURE)
67
- url = 'http://api.hostip.info/get_html.php?ip=10.10.10.10&position=true'
79
+ url = 'http://api.hostip.info/get_html.php?ip=128.178.0.0&position=true'
68
80
  GeoKit::Geocoders::IpGeocoder.expects(:call_geocoder_service).with(url).returns(failure)
69
- location = GeoKit::Geocoders::IpGeocoder.geocode("10.10.10.10")
81
+ location = GeoKit::Geocoders::IpGeocoder.geocode("128.178.0.0")
70
82
  assert_not_nil location
71
83
  assert !location.success?
72
84
  end
73
85
 
86
+ def test_private_ips
87
+ GeoKit::Geocoders::IpGeocoder.expects(:call_geocoder_service).never
88
+ PRIVATE_IPS_TO_TEST.each do |ip|
89
+ location = GeoKit::Geocoders::IpGeocoder.geocode(ip)
90
+ assert_not_nil location
91
+ assert !location.success?
92
+ end
93
+ end
94
+
74
95
  def test_invalid_ip
96
+ GeoKit::Geocoders::IpGeocoder.expects(:call_geocoder_service).never
75
97
  location = GeoKit::Geocoders::IpGeocoder.geocode("blah")
76
98
  assert_not_nil location
77
99
  assert !location.success?
@@ -79,9 +101,9 @@ class IpGeocoderTest < BaseGeocoderTest #:nodoc: all
79
101
 
80
102
  def test_service_unavailable
81
103
  failure = MockFailure.new
82
- url = 'http://api.hostip.info/get_html.php?ip=10.10.10.10&position=true'
104
+ url = 'http://api.hostip.info/get_html.php?ip=12.215.42.19&position=true'
83
105
  GeoKit::Geocoders::IpGeocoder.expects(:call_geocoder_service).with(url).returns(failure)
84
- location = GeoKit::Geocoders::IpGeocoder.geocode("10.10.10.10")
106
+ location = GeoKit::Geocoders::IpGeocoder.geocode("12.215.42.19")
85
107
  assert_not_nil location
86
108
  assert !location.success?
87
109
  end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geokit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 6
9
+ - 0
10
+ version: 1.6.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Andre Lewis
@@ -9,19 +15,41 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-09-21 00:00:00 -07:00
18
+ date: 2011-05-27 00:00:00 -07:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
- name: hoe
22
+ name: rubyforge
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 2
32
+ - 0
33
+ - 4
34
+ version: 2.0.4
17
35
  type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: hoe
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
20
42
  requirements:
21
43
  - - ">="
22
44
  - !ruby/object:Gem::Version
23
- version: 1.12.2
24
- version:
45
+ hash: 21
46
+ segments:
47
+ - 2
48
+ - 6
49
+ - 1
50
+ version: 2.6.1
51
+ type: :development
52
+ version_requirements: *id002
25
53
  description: ""
26
54
  email:
27
55
  - andre@earthcode.com
@@ -54,6 +82,8 @@ files:
54
82
  - test/test_multi_geocoder.rb
55
83
  - test/test_us_geocoder.rb
56
84
  - test/test_yahoo_geocoder.rb
85
+ - test/test_google_geocoder3.rb
86
+ - test/test_multi_ip_geocoder.rb
57
87
  has_rdoc: true
58
88
  homepage:
59
89
  licenses: []
@@ -65,21 +95,27 @@ rdoc_options:
65
95
  require_paths:
66
96
  - lib
67
97
  required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
68
99
  requirements:
69
100
  - - ">="
70
101
  - !ruby/object:Gem::Version
102
+ hash: 3
103
+ segments:
104
+ - 0
71
105
  version: "0"
72
- version:
73
106
  required_rubygems_version: !ruby/object:Gem::Requirement
107
+ none: false
74
108
  requirements:
75
109
  - - ">="
76
110
  - !ruby/object:Gem::Version
111
+ hash: 3
112
+ segments:
113
+ - 0
77
114
  version: "0"
78
- version:
79
115
  requirements: []
80
116
 
81
117
  rubyforge_project: geokit
82
- rubygems_version: 1.3.2
118
+ rubygems_version: 1.3.7
83
119
  signing_key:
84
120
  specification_version: 3
85
121
  summary: Geokit provides geocoding and distance calculation in an easy-to-use API
@@ -90,6 +126,7 @@ test_files:
90
126
  - test/test_geoloc.rb
91
127
  - test/test_geoplugin_geocoder.rb
92
128
  - test/test_google_geocoder.rb
129
+ - test/test_google_geocoder3.rb
93
130
  - test/test_google_reverse_geocoder.rb
94
131
  - test/test_inflector.rb
95
132
  - test/test_ipgeocoder.rb