geokit 1.7.1 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/Manifest.txt DELETED
@@ -1,21 +0,0 @@
1
- History.txt
2
- Manifest.txt
3
- README.markdown
4
- Rakefile
5
- geokit.gemspec
6
- lib/geokit.rb
7
- lib/geokit/geocoders.rb
8
- lib/geokit/mappable.rb
9
- test/test_base_geocoder.rb
10
- test/test_bounds.rb
11
- test/test_ca_geocoder.rb
12
- test/test_geoloc.rb
13
- test/test_geoplugin_geocoder.rb
14
- test/test_google_geocoder.rb
15
- test/test_google_reverse_geocoder.rb
16
- test/test_inflector.rb
17
- test/test_ipgeocoder.rb
18
- test/test_latlng.rb
19
- test/test_multi_geocoder.rb
20
- test/test_us_geocoder.rb
21
- test/test_yahoo_geocoder.rb
data/data/GeoLiteCity.dat DELETED
Binary file
@@ -1,55 +0,0 @@
1
-
2
- # Geocoder CA geocoder implementation. Requires the Geokit::Geocoders::GEOCODER_CA variable to
3
- # contain true or false based upon whether authentication is to occur. Conforms to the
4
- # interface set by the Geocoder class.
5
- #
6
- # Returns a response like:
7
- # <?xml version="1.0" encoding="UTF-8" ?>
8
- # <geodata>
9
- # <latt>49.243086</latt>
10
- # <longt>-123.153684</longt>
11
- # </geodata>
12
- module Geokit
13
- module Geocoders
14
- class CaGeocoder < Geocoder
15
-
16
- private
17
-
18
- # Template method which does the geocode lookup.
19
- def self.do_geocode(address, options = {})
20
- raise ArgumentError('Geocoder.ca requires a GeoLoc argument') unless address.is_a?(GeoLoc)
21
- url = construct_request(address)
22
- res = self.call_geocoder_service(url)
23
- return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
24
- xml = res.body
25
- logger.debug "Geocoder.ca geocoding. Address: #{address}. Result: #{xml}"
26
- # Parse the document.
27
- doc = REXML::Document.new(xml)
28
- address.lat = doc.elements['//latt'].text
29
- address.lng = doc.elements['//longt'].text
30
- address.success = true
31
- return address
32
- rescue
33
- logger.error "Caught an error during Geocoder.ca geocoding call: "+$!
34
- return GeoLoc.new
35
- end
36
-
37
- # Formats the request in the format acceptable by the CA geocoder.
38
- def self.construct_request(location)
39
- url = ""
40
- url += add_ampersand(url) + "stno=#{location.street_number}" if location.street_address
41
- url += add_ampersand(url) + "addresst=#{Geokit::Inflector::url_escape(location.street_name)}" if location.street_address
42
- url += add_ampersand(url) + "city=#{Geokit::Inflector::url_escape(location.city)}" if location.city
43
- url += add_ampersand(url) + "prov=#{location.state}" if location.state
44
- url += add_ampersand(url) + "postal=#{location.zip}" if location.zip
45
- url += add_ampersand(url) + "auth=#{Geokit::Geocoders::geocoder_ca}" if Geokit::Geocoders::geocoder_ca
46
- url += add_ampersand(url) + "geoit=xml"
47
- 'http://geocoder.ca/?' + url
48
- end
49
-
50
- def self.add_ampersand(url)
51
- url && url.length > 0 ? "&" : ""
52
- end
53
- end
54
- end
55
- end
@@ -1,31 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
- # Provides geocoding based upon an IP address. The underlying web service is geoplugin.net
4
- class GeoPluginGeocoder < Geocoder
5
- private
6
-
7
- def self.do_geocode(ip, options = {})
8
- return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
9
- response = self.call_geocoder_service("http://www.geoplugin.net/xml.gp?ip=#{ip}")
10
- return response.is_a?(Net::HTTPSuccess) ? parse_xml(response.body) : GeoLoc.new
11
- rescue
12
- logger.error "Caught an error during GeoPluginGeocoder geocoding call: "+$!
13
- return GeoLoc.new
14
- end
15
-
16
- def self.parse_xml(xml)
17
- xml = REXML::Document.new(xml)
18
- geo = GeoLoc.new
19
- geo.provider='geoPlugin'
20
- geo.city = xml.elements['//geoplugin_city'].text
21
- geo.state = xml.elements['//geoplugin_region'].text
22
- geo.country_code = xml.elements['//geoplugin_countryCode'].text
23
- geo.lat = xml.elements['//geoplugin_latitude'].text.to_f
24
- geo.lng = xml.elements['//geoplugin_longitude'].text.to_f
25
- geo.success = !!geo.city && !geo.city.empty?
26
- return geo
27
- end
28
- end
29
-
30
- end
31
- end
@@ -1,53 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
- # Another geocoding web service
4
- # http://www.geonames.org
5
- class GeonamesGeocoder < Geocoder
6
-
7
- private
8
-
9
- # Template method which does the geocode lookup.
10
- def self.do_geocode(address, options = {})
11
- address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
12
- # geonames need a space seperated search string
13
- address_str.gsub!(/,/, " ")
14
- params = "/postalCodeSearch?placename=#{Geokit::Inflector::url_escape(address_str)}&maxRows=10"
15
-
16
- if(Geokit::Geocoders::geonames)
17
- url = "http://ws.geonames.net#{params}&username=#{Geokit::Geocoders::geonames}"
18
- else
19
- url = "http://ws.geonames.org#{params}"
20
- end
21
-
22
- res = self.call_geocoder_service(url)
23
-
24
- return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
25
-
26
- xml=res.body
27
- logger.debug "Geonames geocoding. Address: #{address}. Result: #{xml}"
28
- doc=REXML::Document.new(xml)
29
-
30
- if(doc.elements['//geonames/totalResultsCount'].text.to_i > 0)
31
- res=GeoLoc.new
32
-
33
- # only take the first result
34
- res.lat=doc.elements['//code/lat'].text if doc.elements['//code/lat']
35
- res.lng=doc.elements['//code/lng'].text if doc.elements['//code/lng']
36
- res.country_code=doc.elements['//code/countryCode'].text if doc.elements['//code/countryCode']
37
- res.provider='genomes'
38
- res.city=doc.elements['//code/name'].text if doc.elements['//code/name']
39
- res.state=doc.elements['//code/adminName1'].text if doc.elements['//code/adminName1']
40
- res.zip=doc.elements['//code/postalcode'].text if doc.elements['//code/postalcode']
41
- res.success=true
42
- return res
43
- else
44
- logger.info "Geonames was unable to geocode address: "+address
45
- return GeoLoc.new
46
- end
47
-
48
- rescue
49
- logger.error "Caught an error during Geonames geocoding call: "+$!
50
- end
51
- end
52
- end
53
- end
@@ -1,158 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
- # -------------------------------------------------------------------------------------------
4
- # Address geocoders that also provide reverse geocoding
5
- # -------------------------------------------------------------------------------------------
6
-
7
- # Google geocoder implementation. Requires the Geokit::Geocoders::GOOGLE variable to
8
- # contain a Google API key. Conforms to the interface set by the Geocoder class.
9
- class GoogleGeocoder < Geocoder
10
-
11
- private
12
-
13
- # Template method which does the reverse-geocode lookup.
14
- def self.do_reverse_geocode(latlng)
15
- latlng=LatLng.normalize(latlng)
16
- res = self.call_geocoder_service("http://maps.google.com/maps/geo?ll=#{Geokit::Inflector::url_escape(latlng.ll)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8")
17
- # res = Net::HTTP.get_response(URI.parse("http://maps.google.com/maps/geo?ll=#{Geokit::Inflector::url_escape(address_str)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8"))
18
- return GeoLoc.new unless (res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPOK))
19
- xml = self.transcode_to_utf8(res.body)
20
- logger.debug "Google reverse-geocoding. LL: #{latlng}. Result: #{xml}"
21
- return self.xml2GeoLoc(xml)
22
- end
23
-
24
- # Template method which does the geocode lookup.
25
- #
26
- # Supports viewport/country code biasing
27
- #
28
- # ==== OPTIONS
29
- # * :bias - This option makes the Google Geocoder return results biased to a particular
30
- # country or viewport. Country code biasing is achieved by passing the ccTLD
31
- # ('uk' for .co.uk, for example) as a :bias value. For a list of ccTLD's,
32
- # look here: http://en.wikipedia.org/wiki/CcTLD. By default, the geocoder
33
- # will be biased to results within the US (ccTLD .com).
34
- #
35
- # If you'd like the Google Geocoder to prefer results within a given viewport,
36
- # you can pass a Geokit::Bounds object as the :bias value.
37
- #
38
- # ==== EXAMPLES
39
- # # By default, the geocoder will return Syracuse, NY
40
- # Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse').country_code # => 'US'
41
- # # With country code biasing, it returns Syracuse in Sicily, Italy
42
- # Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse', :bias => :it).country_code # => 'IT'
43
- #
44
- # # By default, the geocoder will return Winnetka, IL
45
- # Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka').state # => 'IL'
46
- # # When biased to an bounding box around California, it will now return the Winnetka neighbourhood, CA
47
- # bounds = Geokit::Bounds.normalize([34.074081, -118.694401], [34.321129, -118.399487])
48
- # Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka', :bias => bounds).state # => 'CA'
49
- def self.do_geocode(address, options = {})
50
- bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ''
51
- address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
52
- res = self.call_geocoder_service("http://maps.google.com/maps/geo?q=#{Geokit::Inflector::url_escape(address_str)}&output=xml#{bias_str}&key=#{Geokit::Geocoders::google}&oe=utf-8")
53
- return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
54
- xml = self.transcode_to_utf8(res.body)
55
- logger.debug "Google geocoding. Address: #{address}. Result: #{xml}"
56
- return self.xml2GeoLoc(xml, address)
57
- end
58
-
59
- def self.construct_bias_string_from_options(bias)
60
- if bias.is_a?(String) or bias.is_a?(Symbol)
61
- # country code biasing
62
- "&gl=#{bias.to_s.downcase}"
63
- elsif bias.is_a?(Bounds)
64
- # viewport biasing
65
- "&ll=#{precise_ll(bias.center)}&spn=#{precise_ll(bias.to_span)}"
66
- end
67
- end
68
-
69
- # Precision to 6 decimal places as per:
70
- # https://developers.google.com/maps/documentation/staticmaps/?hl=en#Latlons
71
- def self.precise_ll(loc)
72
- "#{"%.6f" % loc.lat},#{"%.6f" % loc.lng}"
73
- end
74
-
75
- def self.xml2GeoLoc(xml, address="")
76
- doc=REXML::Document.new(xml)
77
-
78
- if doc.elements['//kml/Response/Status/code'].text == '200'
79
- geoloc = nil
80
- # Google can return multiple results as //Placemark elements.
81
- # iterate through each and extract each placemark as a geoloc
82
- doc.each_element('//Placemark') do |e|
83
- extracted_geoloc = extract_placemark(e) # g is now an instance of GeoLoc
84
- if geoloc.nil?
85
- # first time through, geoloc is still nil, so we make it the geoloc we just extracted
86
- geoloc = extracted_geoloc
87
- else
88
- # second (and subsequent) iterations, we push additional
89
- # geolocs onto "geoloc.all"
90
- geoloc.all.push(extracted_geoloc)
91
- end
92
- end
93
- return geoloc
94
- elsif doc.elements['//kml/Response/Status/code'].text == '620'
95
- raise Geokit::TooManyQueriesError
96
- else
97
- logger.info "Google was unable to geocode address: "+address
98
- return GeoLoc.new
99
- end
100
-
101
- rescue Geokit::TooManyQueriesError
102
- # re-raise because of other rescue
103
- raise Geokit::TooManyQueriesError, "Google returned a 620 status, too many queries. The given key has gone over the requests limit in the 24 hour period or has submitted too many requests in too short a period of time. If you're sending multiple requests in parallel or in a tight loop, use a timer or pause in your code to make sure you don't send the requests too quickly."
104
- rescue
105
- logger.error "Caught an error during Google geocoding call: "+$!
106
- return GeoLoc.new
107
- end
108
-
109
- # extracts a single geoloc from a //placemark element in the google results xml
110
- def self.extract_placemark(doc)
111
- res = GeoLoc.new
112
- coordinates=doc.elements['.//coordinates'].text.to_s.split(',')
113
-
114
- #basics
115
- res.lat=coordinates[1]
116
- res.lng=coordinates[0]
117
- res.country_code=doc.elements['.//CountryNameCode'].text if doc.elements['.//CountryNameCode']
118
- res.provider='google'
119
-
120
- #extended -- false if not not available
121
- res.city = doc.elements['.//LocalityName'].text if doc.elements['.//LocalityName']
122
- res.state = doc.elements['.//AdministrativeAreaName'].text if doc.elements['.//AdministrativeAreaName']
123
- res.province = doc.elements['.//SubAdministrativeAreaName'].text if doc.elements['.//SubAdministrativeAreaName']
124
- res.full_address = doc.elements['.//address'].text if doc.elements['.//address'] # google provides it
125
- res.zip = doc.elements['.//PostalCodeNumber'].text if doc.elements['.//PostalCodeNumber']
126
- res.street_address = doc.elements['.//ThoroughfareName'].text if doc.elements['.//ThoroughfareName']
127
- res.country = doc.elements['.//CountryName'].text if doc.elements['.//CountryName']
128
- res.district = doc.elements['.//DependentLocalityName'].text if doc.elements['.//DependentLocalityName']
129
- # Translate accuracy into Yahoo-style token address, street, zip, zip+4, city, state, country
130
- # For Google, 1=low accuracy, 8=high accuracy
131
- address_details=doc.elements['.//*[local-name() = "AddressDetails"]']
132
- res.accuracy = address_details ? address_details.attributes['Accuracy'].to_i : 0
133
- res.precision=%w{unknown country state state city zip zip+4 street address building}[res.accuracy]
134
-
135
- # google returns a set of suggested boundaries for the geocoded result
136
- if suggested_bounds = doc.elements['//LatLonBox']
137
- res.suggested_bounds = Bounds.normalize(
138
- [suggested_bounds.attributes['south'], suggested_bounds.attributes['west']],
139
- [suggested_bounds.attributes['north'], suggested_bounds.attributes['east']])
140
- end
141
-
142
- res.success=true
143
-
144
- return res
145
- end
146
-
147
- def self.transcode_to_utf8(body)
148
- require 'iconv' unless String.method_defined?(:encode)
149
- if String.method_defined?(:encode)
150
- body.encode!('UTF-8', 'UTF-8', :invalid => :replace)
151
- else
152
- ic = Iconv.new('UTF-8', 'UTF-8//IGNORE')
153
- body = ic.iconv(body)
154
- end
155
- end
156
- end
157
- end
158
- end
@@ -1,103 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
- # Provides geocoding based upon an IP address. The underlying web service is a hostip.info
4
- # which sources their data through a combination of publicly available information as well
5
- # as community contributions.
6
- class IpGeocoder < Geocoder
7
-
8
- # A number of non-routable IP ranges.
9
- #
10
- # --
11
- # Sources for these:
12
- # RFC 3330: Special-Use IPv4 Addresses
13
- # The bogon list: http://www.cymru.com/Documents/bogon-list.html
14
-
15
- NON_ROUTABLE_IP_RANGES = [
16
- IPAddr.new('0.0.0.0/8'), # "This" Network
17
- IPAddr.new('10.0.0.0/8'), # Private-Use Networks
18
- IPAddr.new('14.0.0.0/8'), # Public-Data Networks
19
- IPAddr.new('127.0.0.0/8'), # Loopback
20
- IPAddr.new('169.254.0.0/16'), # Link local
21
- IPAddr.new('172.16.0.0/12'), # Private-Use Networks
22
- IPAddr.new('192.0.2.0/24'), # Test-Net
23
- IPAddr.new('192.168.0.0/16'), # Private-Use Networks
24
- IPAddr.new('198.18.0.0/15'), # Network Interconnect Device Benchmark Testing
25
- IPAddr.new('224.0.0.0/4'), # Multicast
26
- IPAddr.new('240.0.0.0/4') # Reserved for future use
27
- ].freeze
28
-
29
- private
30
-
31
- # Given an IP address, returns a GeoLoc instance which contains latitude,
32
- # longitude, city, and country code. Sets the success attribute to false if the ip
33
- # parameter does not match an ip address.
34
- def self.do_geocode(ip, options = {})
35
- return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
36
- return GeoLoc.new if self.private_ip_address?(ip)
37
- url = "http://api.hostip.info/get_html.php?ip=#{ip}&position=true"
38
- response = self.call_geocoder_service(url)
39
- ensure_utf8_encoding(response)
40
- response.is_a?(Net::HTTPSuccess) ? parse_body(response.body) : GeoLoc.new
41
- rescue
42
- logger.error "Caught an error during HostIp geocoding call: " + $!.to_s
43
- return GeoLoc.new
44
- end
45
-
46
- # Converts the body to YAML since its in the form of:
47
- #
48
- # Country: UNITED STATES (US)
49
- # City: Sugar Grove, IL
50
- # Latitude: 41.7696
51
- # Longitude: -88.4588
52
- #
53
- # then instantiates a GeoLoc instance to populate with location data.
54
- def self.parse_body(body) # :nodoc:
55
- body = body.encode('UTF-8') if body.respond_to? :encode
56
- yaml = YAML.load(body)
57
- res = GeoLoc.new
58
- res.provider = 'hostip'
59
- res.city, res.state = yaml['City'].split(', ')
60
- res.country, res.country_code = yaml['Country'].split(' (')
61
- res.lat = yaml['Latitude']
62
- res.lng = yaml['Longitude']
63
- res.country_code.chop!
64
- res.success = !(res.city =~ /\(.+\)/)
65
- res
66
- end
67
-
68
- # Forces UTF-8 encoding on the body
69
- # Rails expects string input to be UTF-8
70
- # hostip.info specifies the charset encoding in the headers
71
- # thus extract encoding from headers and tell Rails about it by forcing it
72
- def self.ensure_utf8_encoding(response)
73
- if (enc_string = extract_charset(response))
74
- if defined?(Encoding) && Encoding.aliases.values.include?(enc_string.upcase)
75
- response.body.force_encoding(enc_string.upcase) if response.body.respond_to?(:force_encoding)
76
- response.body.encode("UTF-8")
77
- else
78
- require 'iconv'
79
- response.body.replace Iconv.conv("UTF8", "iso88591", response.body)
80
- end
81
- end
82
- end
83
-
84
- # Extracts charset out of the response headers
85
- def self.extract_charset(response)
86
- if (content_type = response['content-type'])
87
- capture = content_type.match(/charset=(.+)/)
88
- capture && capture[1]
89
- end
90
- end
91
-
92
- # Checks whether the IP address belongs to a private address range.
93
- #
94
- # This function is used to reduce the number of useless queries made to
95
- # the geocoding service. Such queries can occur frequently during
96
- # integration tests.
97
- def self.private_ip_address?(ip)
98
- return NON_ROUTABLE_IP_RANGES.any? { |range| range.include?(ip) }
99
- end
100
- end
101
- end
102
- end
103
-
@@ -1,39 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
-
4
- @@geoip_data_path = File.expand_path(File.join(File.dirname(__FILE__),'../../..','data','GeoLiteCity.dat'))
5
- __define_accessors
6
-
7
- # Provides geocoding based upon an IP address. The underlying web service is MaxMind
8
- class MaxmindGeocoder < Geocoder
9
- private
10
-
11
- def self.do_geocode(ip, options = {})
12
- # return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
13
- return maxmind(ip)
14
- rescue
15
- logger.error "Caught an error during MaxMind geocoding call: " + $!.to_s
16
- return GeoLoc.new
17
- end
18
-
19
-
20
- def self.maxmind(ip)
21
- res = GeoIP.new(Geokit::Geocoders::geoip_data_path).city(ip)
22
-
23
- loc = GeoLoc.new(
24
- :provider => 'maxmind_city',
25
- :lat => res.latitude,
26
- :lng => res.longitude,
27
- :city => res.city_name,
28
- :state => res.region_name,
29
- :zip => res.postal_code,
30
- :country_code => res.country_code3
31
- )
32
-
33
- # loc.success = res.city_name && res.city_name != ''
34
- loc.success = (res.longitude > 0 && res.latitude > 0)
35
- return loc
36
- end
37
- end
38
- end
39
- end