geokit 1.7.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +6 -14
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +11 -0
  4. data/Gemfile +2 -1
  5. data/MIT-LICENSE +20 -0
  6. data/README.markdown +44 -39
  7. data/Rakefile +15 -0
  8. data/fixtures/vcr_cassettes/bing_full.yml +102 -0
  9. data/fixtures/vcr_cassettes/bing_full_au.yml +91 -0
  10. data/fixtures/vcr_cassettes/bing_full_de.yml +91 -0
  11. data/fixtures/vcr_cassettes/fcc_reverse_geocode.yml +37 -0
  12. data/fixtures/vcr_cassettes/free_geo_ip_geocode.yml +36 -0
  13. data/fixtures/vcr_cassettes/geo_plugin_geocode.yml +38 -0
  14. data/fixtures/vcr_cassettes/geonames_geocode.yml +304 -0
  15. data/fixtures/vcr_cassettes/{google3_city.yml → google_city.yml} +0 -0
  16. data/fixtures/vcr_cassettes/{google3_country_code_biased_result.yml → google_country_code_biased_result.yml} +0 -0
  17. data/fixtures/vcr_cassettes/{google3_full.yml → google_full.yml} +0 -0
  18. data/fixtures/vcr_cassettes/{google3_full_short.yml → google_full_short.yml} +0 -0
  19. data/fixtures/vcr_cassettes/{google3_language_response_fr.yml → google_language_response_fr.yml} +0 -0
  20. data/fixtures/vcr_cassettes/{google3_multi.yml → google_multi.yml} +0 -0
  21. data/fixtures/vcr_cassettes/{google3_reverse_madrid.yml → google_reverse_madrid.yml} +0 -0
  22. data/fixtures/vcr_cassettes/ripe_geocode.yml +66 -0
  23. data/fixtures/vcr_cassettes/ripe_geocode_au.yml +66 -0
  24. data/geokit.gemspec +1 -1
  25. data/lib/geokit.rb +5 -0
  26. data/lib/geokit/bounds.rb +96 -0
  27. data/lib/geokit/core_ext.rb +17 -0
  28. data/lib/geokit/geo_loc.rb +134 -0
  29. data/lib/geokit/geocoders.rb +48 -35
  30. data/lib/geokit/geocoders/base_ip.rb +43 -0
  31. data/lib/geokit/geocoders/bing.rb +101 -0
  32. data/lib/geokit/geocoders/ca_geocoder.rb +50 -0
  33. data/lib/geokit/{services → geocoders}/fcc.rb +17 -20
  34. data/lib/geokit/geocoders/free_geo_ip.rb +34 -0
  35. data/lib/geokit/geocoders/geo_plugin.rb +33 -0
  36. data/lib/geokit/geocoders/geonames.rb +53 -0
  37. data/lib/geokit/{services/google3.rb → geocoders/google.rb} +59 -57
  38. data/lib/geokit/geocoders/ip.rb +69 -0
  39. data/lib/geokit/geocoders/mapquest.rb +72 -0
  40. data/lib/geokit/geocoders/maxmind.rb +29 -0
  41. data/lib/geokit/geocoders/openstreetmap.rb +119 -0
  42. data/lib/geokit/geocoders/ripe.rb +41 -0
  43. data/lib/geokit/{services → geocoders}/us_geocoder.rb +15 -20
  44. data/lib/geokit/{services → geocoders}/yahoo.rb +52 -55
  45. data/lib/geokit/geocoders/yandex.rb +61 -0
  46. data/lib/geokit/inflectors.rb +1 -2
  47. data/lib/geokit/lat_lng.rb +129 -0
  48. data/lib/geokit/mappable.rb +41 -424
  49. data/lib/geokit/multi_geocoder.rb +6 -2
  50. data/lib/geokit/polygon.rb +46 -0
  51. data/lib/geokit/version.rb +1 -1
  52. data/test/helper.rb +2 -12
  53. data/test/test_base_geocoder.rb +0 -10
  54. data/test/test_bing_geocoder.rb +60 -0
  55. data/test/test_fcc_geocoder.rb +23 -0
  56. data/test/test_free_geo_ip_geocoder.rb +23 -0
  57. data/test/test_geo_plugin_geocoder.rb +23 -0
  58. data/test/test_geonames_geocoder.rb +23 -0
  59. data/test/test_google_geocoder.rb +208 -235
  60. data/test/test_maxmind_geocoder.rb +35 -4
  61. data/test/test_multi_geocoder.rb +3 -1
  62. data/test/test_ripe_geocoder.rb +35 -0
  63. data/test/test_yahoo_geocoder.rb +0 -12
  64. metadata +78 -52
  65. data/LICENSE +0 -25
  66. data/Manifest.txt +0 -21
  67. data/data/GeoLiteCity.dat +0 -0
  68. data/lib/geokit/services/ca_geocoder.rb +0 -55
  69. data/lib/geokit/services/geo_plugin.rb +0 -31
  70. data/lib/geokit/services/geonames.rb +0 -53
  71. data/lib/geokit/services/google.rb +0 -158
  72. data/lib/geokit/services/ip.rb +0 -103
  73. data/lib/geokit/services/maxmind.rb +0 -39
  74. data/lib/geokit/services/openstreetmap.rb +0 -119
  75. data/lib/geokit/services/ripe.rb +0 -32
  76. data/lib/geokit/services/yandex.rb +0 -51
  77. data/test/test_google_geocoder3.rb +0 -238
  78. data/test/test_google_reverse_geocoder.rb +0 -49
@@ -0,0 +1,66 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://stat.ripe.net/data/geoloc/data.json?resource=74.125.237.209
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ""
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Vary:
20
+ - Cookie, Accept-Encoding
21
+ Content-Type:
22
+ - application/json; charset=utf-8
23
+ Set-Cookie:
24
+ - stat-session=36d43b5353a80b7f74c583a0bda4ea17; expires=Fri, 27-Dec-2013 15:12:05 GMT; Max-Age=1209600; Path=/
25
+ Transfer-Encoding:
26
+ - chunked
27
+ Date:
28
+ - Fri, 13 Dec 2013 15:12:05 GMT
29
+ Server:
30
+ - lighttpd/1.4.32
31
+ body:
32
+ encoding: US-ASCII
33
+ string: |-
34
+ {
35
+ "cached": true,
36
+ "data": {
37
+ "locations": [
38
+ {
39
+ "city": "Mountain View",
40
+ "country": "CA(US)",
41
+ "covered_percentage": 100,
42
+ "latitude": 37.419199999999996,
43
+ "longitude": -122.0574,
44
+ "prefixes": [
45
+ "74.125.192.0/18"
46
+ ]
47
+ }
48
+ ],
49
+ "query_time": "2013-11-01T00:00:00",
50
+ "resource": "74.125.237.209",
51
+ "unknown_percentage": 0.0
52
+ },
53
+ "data_call_status": "supported",
54
+ "messages": [],
55
+ "process_time": 3,
56
+ "query_id": "ed345b04-6408-11e3-9667-782bcb346712",
57
+ "see_also": [],
58
+ "server_id": "stat-app2",
59
+ "status": "ok",
60
+ "status_code": 200,
61
+ "time": "2013-12-13T15:12:05.342893",
62
+ "version": "2.0"
63
+ }
64
+ http_version:
65
+ recorded_at: Fri, 13 Dec 2013 15:12:02 GMT
66
+ recorded_with: VCR 2.8.0
@@ -0,0 +1,66 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://stat.ripe.net/data/geoloc/data.json?resource=118.210.24.54
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ""
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ User-Agent:
13
+ - Ruby
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Vary:
20
+ - Cookie, Accept-Encoding
21
+ Content-Type:
22
+ - application/json; charset=utf-8
23
+ Set-Cookie:
24
+ - stat-session=8dcf7a7e881c4ec64aa1a7dfcc1335c9; expires=Fri, 27-Dec-2013 15:14:20 GMT; Max-Age=1209600; Path=/
25
+ Transfer-Encoding:
26
+ - chunked
27
+ Date:
28
+ - Fri, 13 Dec 2013 15:14:20 GMT
29
+ Server:
30
+ - lighttpd/1.4.32
31
+ body:
32
+ encoding: US-ASCII
33
+ string: |-
34
+ {
35
+ "cached": true,
36
+ "data": {
37
+ "locations": [
38
+ {
39
+ "city": "Adelaide",
40
+ "country": "AU",
41
+ "covered_percentage": 100,
42
+ "latitude": -34.928699999999999,
43
+ "longitude": 138.5986,
44
+ "prefixes": [
45
+ "118.210.16.0/20"
46
+ ]
47
+ }
48
+ ],
49
+ "query_time": "2013-11-01T00:00:00",
50
+ "resource": "118.210.24.54",
51
+ "unknown_percentage": 0.0
52
+ },
53
+ "data_call_status": "supported",
54
+ "messages": [],
55
+ "process_time": 3,
56
+ "query_id": "3dfcd85e-6409-11e3-a402-782bcb346712",
57
+ "see_also": [],
58
+ "server_id": "stat-app2",
59
+ "status": "ok",
60
+ "status_code": 200,
61
+ "time": "2013-12-13T15:14:20.874304",
62
+ "version": "2.0"
63
+ }
64
+ http_version:
65
+ recorded_at: Fri, 13 Dec 2013 15:14:18 GMT
66
+ recorded_with: VCR 2.8.0
data/geokit.gemspec CHANGED
@@ -6,7 +6,7 @@ require 'geokit/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "geokit"
8
8
  spec.version = Geokit::VERSION
9
- spec.authors = ["Michael Noack, James Cox, Andre Lewis & Bill Eisenhauer"]
9
+ spec.authors = ["Michael Noack", "James Cox", "Andre Lewis", "Bill Eisenhauer"]
10
10
  spec.email = ["michael+geokit@noack.com.au"]
11
11
  spec.description = %q{Geokit provides geocoding and distance calculation in an easy-to-use API}
12
12
  spec.summary = %q{Geokit: encoding and distance calculation gem}
data/lib/geokit.rb CHANGED
@@ -22,5 +22,10 @@ end
22
22
 
23
23
  path = File.expand_path(File.dirname(__FILE__))
24
24
  $:.unshift path unless $:.include?(path)
25
+ require 'geokit/core_ext'
25
26
  require 'geokit/geocoders'
26
27
  require 'geokit/mappable'
28
+ require 'geokit/bounds'
29
+ require 'geokit/lat_lng'
30
+ require 'geokit/geo_loc'
31
+ require 'geokit/polygon'
@@ -0,0 +1,96 @@
1
+ module Geokit
2
+ # Bounds represents a rectangular bounds, defined by the SW and NE corners
3
+ class Bounds
4
+ # sw and ne are LatLng objects
5
+ attr_accessor :sw, :ne
6
+
7
+ # provide sw and ne to instantiate a new Bounds instance
8
+ def initialize(sw,ne)
9
+ raise ArgumentError if !(sw.is_a?(Geokit::LatLng) && ne.is_a?(Geokit::LatLng))
10
+ @sw,@ne=sw,ne
11
+ end
12
+
13
+ #returns the a single point which is the center of the rectangular bounds
14
+ def center
15
+ @sw.midpoint_to(@ne)
16
+ end
17
+
18
+ # a simple string representation:sw,ne
19
+ def to_s
20
+ "#{@sw.to_s},#{@ne.to_s}"
21
+ end
22
+
23
+ # a two-element array of two-element arrays: sw,ne
24
+ def to_a
25
+ [@sw.to_a, @ne.to_a]
26
+ end
27
+
28
+ # Returns true if the bounds contain the passed point.
29
+ # allows for bounds which cross the meridian
30
+ def contains?(point)
31
+ point=Geokit::LatLng.normalize(point)
32
+ res = point.lat > @sw.lat && point.lat < @ne.lat
33
+ if crosses_meridian?
34
+ res &= point.lng < @ne.lng || point.lng > @sw.lng
35
+ else
36
+ res &= point.lng < @ne.lng && point.lng > @sw.lng
37
+ end
38
+ res
39
+ end
40
+
41
+ # returns true if the bounds crosses the international dateline
42
+ def crosses_meridian?
43
+ @sw.lng > @ne.lng
44
+ end
45
+
46
+ # Returns true if the candidate object is logically equal. Logical equivalence
47
+ # is true if the lat and lng attributes are the same for both objects.
48
+ def ==(other)
49
+ return false unless other.is_a?(Bounds)
50
+ sw == other.sw && ne == other.ne
51
+ end
52
+
53
+ # Equivalent to Google Maps API's .toSpan() method on GLatLng's.
54
+ #
55
+ # Returns a LatLng object, whose coordinates represent the size of a rectangle
56
+ # defined by these bounds.
57
+ def to_span
58
+ lat_span = (@ne.lat - @sw.lat).abs
59
+ lng_span = (crosses_meridian? ? 360 + @ne.lng - @sw.lng : @ne.lng - @sw.lng).abs
60
+ Geokit::LatLng.new(lat_span, lng_span)
61
+ end
62
+
63
+ class <<self
64
+
65
+ # returns an instance of bounds which completely encompases the given circle
66
+ def from_point_and_radius(point,radius,options={})
67
+ point=LatLng.normalize(point)
68
+ p0=point.endpoint(0,radius,options)
69
+ p90=point.endpoint(90,radius,options)
70
+ p180=point.endpoint(180,radius,options)
71
+ p270=point.endpoint(270,radius,options)
72
+ sw=Geokit::LatLng.new(p180.lat,p270.lng)
73
+ ne=Geokit::LatLng.new(p0.lat,p90.lng)
74
+ Geokit::Bounds.new(sw,ne)
75
+ end
76
+
77
+ # Takes two main combinations of arguments to create a bounds:
78
+ # point,point (this is the only one which takes two arguments
79
+ # [point,point]
80
+ # . . . where a point is anything LatLng#normalize can handle (which is quite a lot)
81
+ #
82
+ # NOTE: everything combination is assumed to pass points in the order sw, ne
83
+ def normalize (thing,other=nil)
84
+ # maybe this will be simple -- an actual bounds object is passed, and we can all go home
85
+ return thing if thing.is_a? Bounds
86
+
87
+ # no? OK, if there's no "other," the thing better be a two-element array
88
+ thing,other=thing if !other && thing.is_a?(Array) && thing.size==2
89
+
90
+ # Now that we're set with a thing and another thing, let LatLng do the heavy lifting.
91
+ # Exceptions may be thrown
92
+ Bounds.new(Geokit::LatLng.normalize(thing),Geokit::LatLng.normalize(other))
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,17 @@
1
+ unless nil.respond_to?(:try)
2
+ class Object
3
+ def try(*a, &b)
4
+ if a.empty? && block_given?
5
+ yield self
6
+ else
7
+ __send__(*a, &b)
8
+ end
9
+ end
10
+ end
11
+
12
+ class NilClass
13
+ def try(*args)
14
+ nil
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,134 @@
1
+ module Geokit
2
+ # This class encapsulates the result of a geocoding call.
3
+ # It's primary purpose is to homogenize the results of multiple
4
+ # geocoding providers. It also provides some additional functionality, such as
5
+ # the "full address" method for geocoders that do not provide a
6
+ # full address in their results (for example, Yahoo), and the "is_us" method.
7
+ #
8
+ # Some geocoders can return multple results. Geoloc can capture multiple results through
9
+ # its "all" method.
10
+ #
11
+ # For the geocoder setting the results, it would look something like this:
12
+ # geo=GeoLoc.new(first_result)
13
+ # geo.all.push(second_result)
14
+ # geo.all.push(third_result)
15
+ #
16
+ # Then, for the user of the result:
17
+ #
18
+ # puts geo.full_address # just like usual
19
+ # puts geo.all.size => 3 # there's three results total
20
+ # puts geo.all.first # all is just an array or additional geolocs,
21
+ # so do what you want with it
22
+ class GeoLoc < LatLng
23
+
24
+ # Location attributes. Full address is a concatenation of all values. For example:
25
+ # 100 Spear St, San Francisco, CA, 94101, US
26
+ # Street number and street name are extracted from the street address attribute if they don't exist
27
+ attr_accessor :street_number, :street_name, :street_address, :city, :state, :zip, :country_code, :country
28
+ attr_accessor :full_address, :all, :district, :province, :sub_premise, :neighborhood
29
+ # Attributes set upon return from geocoding. Success will be true for successful
30
+ # geocode lookups. The provider will be set to the name of the providing geocoder.
31
+ # Finally, precision is an indicator of the accuracy of the geocoding.
32
+ attr_accessor :success, :provider, :precision, :suggested_bounds
33
+ # accuracy is set for Yahoo and Google geocoders, it is a numeric value of the
34
+ # precision. see http://code.google.com/apis/maps/documentation/geocoding/#GeocodingAccuracy
35
+ attr_accessor :accuracy
36
+ # FCC Attributes
37
+ attr_accessor :district_fips, :state_fips, :block_fips
38
+
39
+
40
+ # Constructor expects a hash of symbols to correspond with attributes.
41
+ def initialize(h={})
42
+ @all = [self]
43
+
44
+ @street_address=h[:street_address]
45
+ @sub_premise=nil
46
+ @street_number=nil
47
+ @street_name=nil
48
+ @city=h[:city]
49
+ @state=h[:state]
50
+ @zip=h[:zip]
51
+ @country_code=h[:country_code]
52
+ @province = h[:province]
53
+ @success=false
54
+ @precision='unknown'
55
+ @full_address=nil
56
+ super(h[:lat],h[:lng])
57
+ end
58
+
59
+ # Returns true if geocoded to the United States.
60
+ def is_us?
61
+ country_code == 'US'
62
+ end
63
+
64
+ def success?
65
+ success == true
66
+ end
67
+
68
+ # full_address is provided by google but not by yahoo. It is intended that the google
69
+ # geocoding method will provide the full address, whereas for yahoo it will be derived
70
+ # from the parts of the address we do have.
71
+ def full_address
72
+ @full_address ? @full_address : to_geocodeable_s
73
+ end
74
+
75
+ # Extracts the street number from the street address where possible.
76
+ def street_number
77
+ @street_number ||= street_address[/(\d*)/] if street_address
78
+ @street_number
79
+ end
80
+
81
+ # Returns the street name portion of the street address where possible
82
+ def street_name
83
+ @street_name||=street_address[street_number.length, street_address.length].strip if street_address
84
+ @street_name
85
+ end
86
+
87
+ # gives you all the important fields as key-value pairs
88
+ def hash
89
+ res={}
90
+ [:success, :lat, :lng, :country_code, :city, :state, :zip, :street_address, :province,
91
+ :district, :provider, :full_address, :is_us?, :ll, :precision, :district_fips, :state_fips,
92
+ :block_fips, :sub_premise].each { |s| res[s] = self.send(s.to_s) }
93
+ res
94
+ end
95
+ alias to_hash hash
96
+
97
+ # Sets the city after capitalizing each word within the city name.
98
+ def city=(city)
99
+ @city = Geokit::Inflector::titleize(city) if city
100
+ end
101
+
102
+ # Sets the street address after capitalizing each word within the street address.
103
+ def street_address=(address)
104
+ @street_address = if address && provider != 'google'
105
+ Geokit::Inflector::titleize(address)
106
+ else
107
+ address
108
+ end
109
+ end
110
+
111
+ # Returns a comma-delimited string consisting of the street address, city, state,
112
+ # zip, and country code. Only includes those attributes that are non-blank.
113
+ def to_geocodeable_s
114
+ a=[street_address, district, city, province, state, zip, country_code].compact
115
+ a.delete_if { |e| !e || e == '' }
116
+ a.join(', ')
117
+ end
118
+
119
+ def to_yaml_properties
120
+ (instance_variables - ['@all', :@all]).sort
121
+ end
122
+
123
+ def encode_with(coder)
124
+ to_yaml_properties.each do |name|
125
+ coder[name[1..-1].to_s] = instance_variable_get(name.to_s)
126
+ end
127
+ end
128
+
129
+ # Returns a string representation of the instance.
130
+ def to_s
131
+ "Provider: #{provider}\nStreet: #{street_address}\nCity: #{city}\nState: #{state}\nZip: #{zip}\nLatitude: #{lat}\nLongitude: #{lng}\nCountry: #{country_code}\nSuccess: #{success}"
132
+ end
133
+ end
134
+ end
@@ -10,9 +10,6 @@ require 'multi_json'
10
10
  module Geokit
11
11
  require File.join(File.dirname(__FILE__), 'inflectors')
12
12
 
13
- class TooManyQueriesError < StandardError; end
14
-
15
-
16
13
  # Contains a range of geocoders:
17
14
  #
18
15
  # ### "regular" address geocoders
@@ -33,15 +30,14 @@ module Geokit
33
30
  #
34
31
  # Some of these geocoders require configuration. You don't have to provide it here. See the README.
35
32
  module Geocoders
36
- @@proxy_addr = nil
37
- @@proxy_port = nil
38
- @@proxy_user = nil
39
- @@proxy_pass = nil
33
+ @@proxy = nil
40
34
  @@request_timeout = nil
35
+ @@bing = 'REPLACE_WITH_YOUR_BING_KEY'
36
+ @@bing_options = {}
41
37
  @@yahoo_consumer_key = 'REPLACE_WITH_YOUR_YAHOO_BOSS_OAUTH_CONSUMER_KEY'
42
38
  @@yahoo_consumer_secret = 'REPLACE_WITH_YOUR_YAHOO_BOSS_OAUTH_CONSUMER_SECRET'
43
- @@yandex = 'REPLACE_WITH_YOUR_YANDEX_KEY'
44
- @@google = 'REPLACE_WITH_YOUR_GOOGLE_KEY'
39
+ @@yandex = nil
40
+ @@mapquest = 'REPLACE_WITH_YOUR_MAPQUEST_KEY'
45
41
  @@google_client_id = nil
46
42
  @@google_cryptographic_key = nil
47
43
  @@google_channel = nil
@@ -84,6 +80,7 @@ module Geokit
84
80
 
85
81
  # Error which is thrown in the event a geocoding error occurs.
86
82
  class GeocodeError < StandardError; end
83
+ class TooManyQueriesError < StandardError; end
87
84
 
88
85
  # -------------------------------------------------------------------------------------------
89
86
  # Geocoder Base class -- every geocoder should inherit from this
@@ -95,36 +92,39 @@ module Geokit
95
92
  # Main method which calls the do_geocode template method which subclasses
96
93
  # are responsible for implementing. Returns a populated GeoLoc or an
97
94
  # empty one with a failed success code.
98
- def self.geocode(address, options = {})
99
- res = do_geocode(address, options)
100
- return res.nil? ? GeoLoc.new : res
95
+ def self.geocode(address, *args)
96
+ do_geocode(address, *args) || GeoLoc.new
97
+ rescue TooManyQueriesError, GeocodeError
98
+ raise
99
+ rescue
100
+ logger.error "Caught an error during #{self.class} geocoding call: #{$!}"
101
+ GeoLoc.new
101
102
  end
102
103
  # Main method which calls the do_reverse_geocode template method which subclasses
103
104
  # are responsible for implementing. Returns a populated GeoLoc or an
104
105
  # empty one with a failed success code.
105
106
  def self.reverse_geocode(latlng)
106
- res = do_reverse_geocode(latlng)
107
- return res.success? ? res : GeoLoc.new
107
+ do_reverse_geocode(latlng) || GeoLoc.new
108
108
  end
109
109
 
110
110
  # Call the geocoder service using the timeout if configured.
111
111
  def self.call_geocoder_service(url)
112
112
  Timeout::timeout(Geokit::Geocoders::request_timeout) { return self.do_get(url) } if Geokit::Geocoders::request_timeout
113
- return self.do_get(url)
113
+ self.do_get(url)
114
114
  rescue TimeoutError
115
- return nil
115
+ nil
116
116
  end
117
117
 
118
118
  # Not all geocoders can do reverse geocoding. So, unless the subclass explicitly overrides this method,
119
119
  # a call to reverse_geocode will return an empty GeoLoc. If you happen to be using MultiGeocoder,
120
120
  # this will cause it to failover to the next geocoder, which will hopefully be one which supports reverse geocoding.
121
121
  def self.do_reverse_geocode(latlng)
122
- return GeoLoc.new
122
+ GeoLoc.new
123
123
  end
124
124
 
125
125
  protected
126
126
 
127
- def self.logger()
127
+ def self.logger
128
128
  Geokit::Geocoders::logger
129
129
  end
130
130
 
@@ -135,31 +135,44 @@ module Geokit
135
135
  uri = URI.parse(url)
136
136
  req = Net::HTTP::Get.new(url)
137
137
  req.basic_auth(uri.user, uri.password) if uri.userinfo
138
- res = Net::HTTP::new(uri.host, uri.port,
139
- Geokit::Geocoders::proxy_addr,
140
- Geokit::Geocoders::proxy_port,
141
- Geokit::Geocoders::proxy_user,
142
- Geokit::Geocoders::proxy_pass).start { |http| http.request(req) }
143
- return res
138
+ net_http_args = [uri.host, uri.port]
139
+ if (proxy_uri_string = Geokit::Geocoders::proxy)
140
+ proxy_uri = URI.parse(proxy_uri_string)
141
+ net_http_args += [proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password]
142
+ end
143
+ Net::HTTP::new(*net_http_args).start { |http| http.request(req) }
144
+ end
145
+
146
+ def self.parse(format, body, *args)
147
+ case format
148
+ when :json then parse_json(MultiJson.load(body), *args)
149
+ when :xml then parse_xml(REXML::Document.new(body), *args)
150
+ when :yaml then parse_yaml(YAML::load(body), *args)
151
+ end
144
152
  end
145
153
 
146
- # Adds subclass' geocode method making it conveniently available through
147
- # the base class.
148
- def self.inherited(clazz)
149
- class_name = clazz.name.split('::').last
150
- src = <<-END_SRC
151
- def self.#{Geokit::Inflector.underscore(class_name)}(address, options = {})
152
- #{class_name}.geocode(address, options)
153
- end
154
- END_SRC
155
- class_eval(src)
154
+ def self.set_mappings(loc, xml, mappings)
155
+ mappings.each_pair do |field, xml_field|
156
+ loc.send("#{field}=", xml.elements[xml_field].try(:text))
157
+ end
158
+ end
159
+
160
+ def self.transcode_to_utf8(body)
161
+ require 'iconv' unless String.method_defined?(:encode)
162
+ if String.method_defined?(:encode)
163
+ body.encode!('UTF-8', 'UTF-8', :invalid => :replace)
164
+ else
165
+ ic = Iconv.new('UTF-8', 'UTF-8//IGNORE')
166
+ body = ic.iconv(body)
167
+ end
156
168
  end
157
169
  end
158
170
 
159
171
  # -------------------------------------------------------------------------------------------
160
172
  # "Regular" Address geocoders
161
173
  # -------------------------------------------------------------------------------------------
162
- Dir[File.join(File.dirname(__FILE__), "/services/*.rb")].each {|f| require f}
174
+ require File.join(File.dirname(__FILE__), 'geocoders/base_ip')
175
+ Dir[File.join(File.dirname(__FILE__), "/geocoders/*.rb")].each {|f| require f}
163
176
 
164
177
  require File.join(File.dirname(__FILE__), 'multi_geocoder')
165
178
  end