geokit 1.8.5 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +0 -1
  3. data/CHANGELOG.md +7 -0
  4. data/README.markdown +31 -14
  5. data/fixtures/vcr_cassettes/geonames_geocode.yml +1 -1
  6. data/fixtures/vcr_cassettes/geonames_geocode_premium.yml +42 -0
  7. data/fixtures/vcr_cassettes/google_country_code_biased_result_orly.yml +160 -0
  8. data/fixtures/vcr_cassettes/google_country_code_biased_result_toledo.yml +111 -0
  9. data/fixtures/vcr_cassettes/google_result_toledo_default_bias.yml +275 -0
  10. data/fixtures/vcr_cassettes/google_sublocality.yml +126 -0
  11. data/fixtures/vcr_cassettes/mapbox_forward_geocode.yml +59 -0
  12. data/fixtures/vcr_cassettes/mapbox_reverse_geocode.yml +63 -0
  13. data/fixtures/vcr_cassettes/opencage_city.yml +51 -0
  14. data/fixtures/vcr_cassettes/opencage_full.yml +65 -0
  15. data/fixtures/vcr_cassettes/opencage_language_response_es.yml +66 -0
  16. data/fixtures/vcr_cassettes/opencage_reverse_madrid.yml +51 -0
  17. data/fixtures/vcr_cassettes/opencage_reverse_prilep.yml +53 -0
  18. data/geokit.gemspec +5 -3
  19. data/lib/geokit/bounds.rb +40 -31
  20. data/lib/geokit/core_ext.rb +1 -1
  21. data/lib/geokit/geo_loc.rb +63 -41
  22. data/lib/geokit/geocoders.rb +13 -13
  23. data/lib/geokit/geocoders/bing.rb +9 -9
  24. data/lib/geokit/geocoders/ca_geocoder.rb +29 -29
  25. data/lib/geokit/geocoders/fcc.rb +4 -4
  26. data/lib/geokit/geocoders/free_geo_ip.rb +6 -7
  27. data/lib/geokit/geocoders/geo_plugin.rb +5 -6
  28. data/lib/geokit/geocoders/geocodio.rb +2 -2
  29. data/lib/geokit/geocoders/geonames.rb +18 -12
  30. data/lib/geokit/geocoders/google.rb +31 -30
  31. data/lib/geokit/geocoders/ip.rb +3 -4
  32. data/lib/geokit/geocoders/mapbox.rb +94 -0
  33. data/lib/geokit/geocoders/mapquest.rb +5 -5
  34. data/lib/geokit/geocoders/opencage.rb +93 -0
  35. data/lib/geokit/geocoders/openstreetmap.rb +9 -6
  36. data/lib/geokit/geocoders/ripe.rb +3 -3
  37. data/lib/geokit/geocoders/us_geocoder.rb +10 -9
  38. data/lib/geokit/geocoders/yahoo.rb +33 -34
  39. data/lib/geokit/geocoders/yandex.rb +17 -17
  40. data/lib/geokit/inflectors.rb +4 -10
  41. data/lib/geokit/lat_lng.rb +50 -26
  42. data/lib/geokit/mappable.rb +83 -83
  43. data/lib/geokit/multi_geocoder.rb +25 -20
  44. data/lib/geokit/net_adapter/net_http.rb +7 -4
  45. data/lib/geokit/polygon.rb +36 -4
  46. data/lib/geokit/version.rb +1 -1
  47. data/test/helper.rb +15 -13
  48. data/test/test_base_geocoder.rb +6 -7
  49. data/test/test_bing_geocoder.rb +20 -21
  50. data/test/test_bounds.rb +26 -28
  51. data/test/test_ca_geocoder.rb +9 -10
  52. data/test/test_fcc_geocoder.rb +1 -1
  53. data/test/test_free_geo_ip_geocoder.rb +1 -1
  54. data/test/test_geo_plugin_geocoder.rb +9 -9
  55. data/test/test_geoloc.rb +7 -6
  56. data/test/test_geonames_geocoder.rb +28 -6
  57. data/test/test_google_geocoder.rb +210 -176
  58. data/test/test_inflector.rb +0 -1
  59. data/test/test_ipgeocoder.rb +17 -18
  60. data/test/test_latlng.rb +105 -85
  61. data/test/test_map_quest.rb +18 -21
  62. data/test/test_mapbox_geocoder.rb +31 -0
  63. data/test/test_mappable.rb +46 -0
  64. data/test/test_maxmind_geocoder.rb +1 -3
  65. data/test/test_multi_geocoder.rb +8 -9
  66. data/test/test_multi_ip_geocoder.rb +3 -5
  67. data/test/test_net_adapter.rb +4 -4
  68. data/test/test_opencage_geocoder.rb +108 -0
  69. data/test/test_openstreetmap_geocoder.rb +62 -44
  70. data/test/{test_polygon_contains.rb → test_polygon.rb} +30 -20
  71. data/test/test_ripe_geocoder.rb +2 -0
  72. data/test/test_us_geocoder.rb +7 -8
  73. data/test/test_yahoo_geocoder.rb +20 -21
  74. data/test/test_yandex_geocoder.rb +34 -35
  75. metadata +79 -56
  76. data/fixtures/vcr_cassettes/google_country_code_biased_result.yml +0 -401
@@ -3,7 +3,7 @@ module Geokit
3
3
  # Another geocoding web service
4
4
  # http://www.geonames.org
5
5
  class GeonamesGeocoder < Geocoder
6
- config :key
6
+ config :key, :premium
7
7
 
8
8
  private
9
9
 
@@ -13,29 +13,35 @@ module Geokit
13
13
  end
14
14
 
15
15
  def self.submit_url(address)
16
+ if key.nil? || key.empty?
17
+ raise Geokit::Geocoders::GeocodeError.new('Geonames requires a key to use their service.')
18
+ end
19
+
16
20
  address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
17
21
  # geonames need a space seperated search string
18
- address_str.gsub!(/,/, " ")
19
- params = "/postalCodeSearch?placename=#{Geokit::Inflector::url_escape(address_str)}&maxRows=10"
22
+ address_str.gsub!(/,/, ' ')
23
+ params = "/postalCodeSearch?placename=#{Geokit::Inflector.url_escape(address_str)}&maxRows=10"
20
24
 
21
- if key
25
+ if premium
22
26
  "http://ws.geonames.net#{params}&username=#{key}"
23
27
  else
24
- "http://ws.geonames.org#{params}"
28
+ "http://api.geonames.org#{params}&username=#{key}"
25
29
  end
26
30
  end
27
31
 
28
32
  XML_MAPPINGS = {
29
- :city => 'name',
30
- :state => 'adminName1',
31
- :zip => 'postalcode',
32
- :country_code => 'countryCode',
33
- :lat => 'lat',
34
- :lng => 'lng'
33
+ city: 'name',
34
+ state_name: 'adminName1',
35
+ state_code: 'adminCode1',
36
+ zip: 'postalcode',
37
+ country_code: 'countryCode',
38
+ lat: 'lat',
39
+ lng: 'lng'
35
40
  }
36
41
 
37
42
  def self.parse_xml(xml)
38
- return GeoLoc.new unless xml.elements['geonames/totalResultsCount'].text.to_i > 0
43
+ count = xml.elements['geonames/totalResultsCount']
44
+ return GeoLoc.new unless !count.nil? && count.text.to_i > 0
39
45
  loc = new_loc
40
46
  # only take the first result
41
47
  set_mappings(loc, xml.elements['geonames/code'], XML_MAPPINGS)
@@ -5,11 +5,12 @@ module Geokit
5
5
  self.secure = true
6
6
 
7
7
  private
8
+
8
9
  # ==== OPTIONS
9
10
  # * :language - See: https://developers.google.com/maps/documentation/geocoding
10
11
  def self.do_reverse_geocode(latlng, options = {})
11
- latlng=LatLng.normalize(latlng)
12
- url = submit_url("latlng=#{Geokit::Inflector::url_escape(latlng.ll)}", options)
12
+ latlng = LatLng.normalize(latlng)
13
+ url = submit_url("latlng=#{Geokit::Inflector.url_escape(latlng.ll)}", options)
13
14
  process :json, url
14
15
  end
15
16
 
@@ -25,10 +26,10 @@ module Geokit
25
26
  # you can pass a Geokit::Bounds object as the :bias value.
26
27
  #
27
28
  # ==== EXAMPLES
28
- # # By default, the geocoder will return Syracuse, NY
29
- # Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse').country_code # => 'US'
30
- # # With country code biasing, it returns Syracuse in Sicily, Italy
31
- # Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse', :bias => :it).country_code # => 'IT'
29
+ # # By default, the geocoder will return Toledo, OH
30
+ # Geokit::Geocoders::GoogleGeocoder.geocode('Toledo').country_code # => 'US'
31
+ # # With country code biasing, it returns Toledo (spannish city), Spain
32
+ # Geokit::Geocoders::GoogleGeocoder.geocode('Toledo', :bias => :es).country_code # => 'Es'
32
33
  #
33
34
  # # By default, the geocoder will return Winnetka, IL
34
35
  # Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka').state # => 'IL'
@@ -38,7 +39,7 @@ module Geokit
38
39
  def self.do_geocode(address, options = {})
39
40
  bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ''
40
41
  address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
41
- url = submit_url("address=#{Geokit::Inflector::url_escape(address_str)}#{bias_str}", options)
42
+ url = submit_url("address=#{Geokit::Inflector.url_escape(address_str)}#{bias_str}", options)
42
43
  process :json, url
43
44
  end
44
45
 
@@ -48,14 +49,13 @@ module Geokit
48
49
  require 'base64'
49
50
  require 'openssl'
50
51
  # Decode the private key
51
- rawKey = Base64.decode64(google_cryptographic_key.tr('-_','+/'))
52
+ rawKey = Base64.decode64(google_cryptographic_key.tr('-_', '+/'))
52
53
  # create a signature using the private key and the URL
53
54
  rawSignature = OpenSSL::HMAC.digest('sha1', rawKey, urlToSign)
54
55
  # encode the signature into base64 for url use form.
55
- Base64.encode64(rawSignature).tr('+/','-_').gsub(/\n/, '')
56
+ Base64.encode64(rawSignature).tr('+/', '-_').gsub(/\n/, '')
56
57
  end
57
58
 
58
-
59
59
  def self.submit_url(query_string, options = {})
60
60
  language_str = options[:language] ? "&language=#{options[:language]}" : ''
61
61
  query_string = "/maps/api/geocode/json?sensor=false&#{query_string}#{language_str}"
@@ -72,7 +72,6 @@ module Geokit
72
72
  end
73
73
  end
74
74
 
75
-
76
75
  def self.construct_bias_string_from_options(bias)
77
76
  case bias
78
77
  when String, Symbol
@@ -80,7 +79,7 @@ module Geokit
80
79
  "&region=#{bias.to_s.downcase}"
81
80
  when Bounds
82
81
  # viewport biasing
83
- url_escaped_string = Geokit::Inflector::url_escape("#{bias.sw.to_s}|#{bias.ne.to_s}")
82
+ url_escaped_string = Geokit::Inflector.url_escape("#{bias.sw}|#{bias.ne}")
84
83
  "&bounds=#{url_escaped_string}"
85
84
  end
86
85
  end
@@ -99,13 +98,12 @@ module Geokit
99
98
  single_json_to_geoloc(addr)
100
99
  end
101
100
 
102
- all = unsorted.sort_by(&:accuracy).reverse
101
+ all = unsorted.sort {|a, b| b.accuracy <=> a.accuracy }
103
102
  encoded = all.first
104
103
  encoded.all = all
105
104
  encoded
106
105
  end
107
106
 
108
-
109
107
  # location_type stores additional data about the specified location.
110
108
  # The following values are currently supported:
111
109
  # "ROOFTOP" indicates that the returned result is a precise geocode
@@ -123,10 +121,10 @@ module Geokit
123
121
  # these do not map well. Perhaps we should guess better based on size
124
122
  # of bounding box where it exists? Does it really matter?
125
123
  ACCURACY = {
126
- "ROOFTOP" => 9,
127
- "RANGE_INTERPOLATED" => 8,
128
- "GEOMETRIC_CENTER" => 5,
129
- "APPROXIMATE" => 4
124
+ 'ROOFTOP' => 9,
125
+ 'RANGE_INTERPOLATED' => 8,
126
+ 'GEOMETRIC_CENTER' => 5,
127
+ 'APPROXIMATE' => 4
130
128
  }
131
129
 
132
130
  def self.single_json_to_geoloc(addr)
@@ -137,7 +135,7 @@ module Geokit
137
135
  set_address_components(loc, addr)
138
136
  set_precision(loc, addr)
139
137
  if loc.street_name
140
- loc.street_address=[loc.street_number, loc.street_name].join(' ').strip
138
+ loc.street_address = [loc.street_number, loc.street_name].join(' ').strip
141
139
  end
142
140
 
143
141
  ll = addr['geometry']['location']
@@ -160,39 +158,42 @@ module Geokit
160
158
  addr['address_components'].each do |comp|
161
159
  types = comp['types']
162
160
  case
163
- when types.include?("subpremise")
161
+ when types.include?('subpremise')
164
162
  loc.sub_premise = comp['short_name']
165
- when types.include?("street_number")
163
+ when types.include?('street_number')
166
164
  loc.street_number = comp['short_name']
167
- when types.include?("route")
165
+ when types.include?('route')
168
166
  loc.street_name = comp['long_name']
169
- when types.include?("locality")
167
+ when types.include?('locality')
170
168
  loc.city = comp['long_name']
171
- when types.include?("administrative_area_level_1")
172
- loc.state = comp['short_name']
169
+ when types.include?('administrative_area_level_1')
170
+ loc.state_code = comp['short_name']
171
+ loc.state_name = comp['long_name']
173
172
  loc.province = comp['short_name']
174
- when types.include?("postal_code")
173
+ when types.include?('postal_code')
175
174
  loc.zip = comp['long_name']
176
- when types.include?("country")
175
+ when types.include?('country')
177
176
  loc.country_code = comp['short_name']
178
177
  loc.country = comp['long_name']
179
- when types.include?("administrative_area_level_2")
178
+ when types.include?('administrative_area_level_2')
180
179
  loc.district = comp['long_name']
181
180
  when types.include?('neighborhood')
182
181
  loc.neighborhood = comp['short_name']
182
+ when types.include?('sublocality')
183
+ loc.city = comp['long_name'] if loc.city.nil?
183
184
  end
184
185
  end
185
186
  end
186
187
 
187
188
  def self.set_precision(loc, addr)
188
189
  loc.accuracy = ACCURACY[addr['geometry']['location_type']]
189
- loc.precision=%w{unknown country state state city zip zip+4 street address building}[loc.accuracy]
190
+ loc.precision = %w{unknown country state state city zip zip+4 street address building}[loc.accuracy]
190
191
  # try a few overrides where we can
191
192
  if loc.sub_premise
192
193
  loc.accuracy = 9
193
194
  loc.precision = 'building'
194
195
  end
195
- if loc.street_name && loc.precision=='city'
196
+ if loc.street_name && loc.precision == 'city'
196
197
  loc.precision = 'street'
197
198
  loc.accuracy = 7
198
199
  end
@@ -34,7 +34,7 @@ module Geokit
34
34
  # then instantiates a GeoLoc instance to populate with location data.
35
35
  def self.parse_yaml(yaml) # :nodoc:
36
36
  loc = new_loc
37
- loc.city, loc.state = yaml['City'].split(', ')
37
+ loc.city, loc.state_code = yaml['City'].split(', ')
38
38
  loc.country, loc.country_code = yaml['Country'].split(' (')
39
39
  loc.lat = yaml['Latitude']
40
40
  loc.lng = yaml['Longitude']
@@ -51,10 +51,10 @@ module Geokit
51
51
  if (enc_string = extract_charset(res))
52
52
  if defined?(Encoding) && Encoding.aliases.values.include?(enc_string.upcase)
53
53
  res.body.force_encoding(enc_string.upcase) if res.body.respond_to?(:force_encoding)
54
- res.body.encode("UTF-8")
54
+ res.body.encode('UTF-8')
55
55
  else
56
56
  require 'iconv'
57
- res.body.replace Iconv.conv("UTF8", "iso88591", res.body)
57
+ res.body.replace Iconv.conv('UTF8', 'iso88591', res.body)
58
58
  end
59
59
  end
60
60
  end
@@ -69,4 +69,3 @@ module Geokit
69
69
  end
70
70
  end
71
71
  end
72
-
@@ -0,0 +1,94 @@
1
+ module Geokit
2
+ module Geocoders
3
+ # Mapbox geocoder implementation. Requires the Geokit::Geocoders::MapboxGeocoder:key variable to
4
+ # contain a Mapbox access token. Conforms to the interface set by the Geocoder class.
5
+ class MapboxGeocoder < Geocoder
6
+ config :key
7
+ self.secure = true
8
+
9
+ private
10
+
11
+ # Template method which does the reverse-geocode lookup.
12
+ def self.do_reverse_geocode(latlng)
13
+ latlng = LatLng.normalize(latlng)
14
+ url = "#{protocol}://api.tiles.mapbox.com/v4/geocode/mapbox.places-v1/"
15
+ url += "#{latlng.lng},#{latlng.lat}.json?access_token=#{key}"
16
+ process :json, url
17
+ end
18
+
19
+ # Template method which does the geocode lookup.
20
+ def self.do_geocode(address)
21
+ address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
22
+ url = "#{protocol}://api.tiles.mapbox.com/v4/geocode/mapbox.places-v1/"
23
+ url += "#{Geokit::Inflector.url_escape(address_str)}.json?access_token=#{key}"
24
+ process :json, url
25
+ end
26
+
27
+ def self.parse_json(results)
28
+ return GeoLoc.new unless results['features'].count > 0
29
+ loc = nil
30
+ results['features'].each do |feature|
31
+ extracted_geoloc = extract_geoloc(feature)
32
+ if loc.nil?
33
+ loc = extracted_geoloc
34
+ else
35
+ loc.all.push(extracted_geoloc)
36
+ end
37
+ end
38
+ loc
39
+ end
40
+
41
+ def self.extract_geoloc(result_json)
42
+ loc = new_loc
43
+ loc.lng = result_json['center'][0]
44
+ loc.lat = result_json['center'][1]
45
+ set_address_components(result_json, loc)
46
+ set_precision(loc)
47
+ set_bounds(result_json['bbox'], loc)
48
+ loc.success = true
49
+ loc
50
+ end
51
+
52
+ def self.set_address_components(result_json, loc)
53
+ if result_json['context']
54
+ result_json['context'].each do |context|
55
+ if context['id'] =~ /^country\./
56
+ loc.country = context['text']
57
+ elsif context['id'] =~ /^province\./
58
+ loc.state = context['text']
59
+ elsif context['id'] =~ /^city\./
60
+ loc.city = context['text']
61
+ elsif context['id'] =~ /^postcode-/
62
+ loc.zip = context['text']
63
+ loc.country_code = context['id'].split('.')[0].gsub(/^postcode-/, '').upcase
64
+ end
65
+ end
66
+ if loc.country_code && !loc.country
67
+ loc.country = loc.country_code
68
+ end
69
+ end
70
+ if result_json['place_name']
71
+ loc.full_address = result_json['place_name']
72
+ end
73
+ end
74
+
75
+ PRECISION_VALUES = %w{unknown country state city zip full_address}
76
+
77
+ def self.set_precision(loc)
78
+ for i in 1...PRECISION_VALUES.length - 1
79
+ if loc.send(PRECISION_VALUES[i]) && loc.send(PRECISION_VALUES[i]).length
80
+ loc.precision = PRECISION_VALUES[i]
81
+ else
82
+ break
83
+ end
84
+ end
85
+ end
86
+
87
+ def self.set_bounds(result_json, loc)
88
+ if bounds = result_json
89
+ loc.suggested_bounds = Bounds.normalize([bounds[1], bounds[0]], [bounds[3], bounds[2]])
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,7 +1,7 @@
1
1
  module Geokit
2
2
  module Geocoders
3
- # MapQuest geocoder implementation. Requires the Geokit::Geocoders::mapquest variable to
4
- # contain a MapQuest API key. Conforms to the interface set by the Geocoder class.
3
+ # MapQuest geocoder implementation. Requires the Geokit::Geocoders::MapQuestGeocoder:key
4
+ # variable to contain a MapQuest API key. Conforms to the interface set by the Geocoder class.
5
5
  class MapQuestGeocoder < Geocoder
6
6
  config :key
7
7
  self.secure = true
@@ -10,7 +10,7 @@ module Geokit
10
10
 
11
11
  # Template method which does the reverse-geocode lookup.
12
12
  def self.do_reverse_geocode(latlng)
13
- latlng=LatLng.normalize(latlng)
13
+ latlng = LatLng.normalize(latlng)
14
14
  url = "#{protocol}://www.mapquestapi.com/geocoding/v1/reverse?key=#{key}&location=#{latlng.lat},#{latlng.lng}"
15
15
  process :json, url
16
16
  end
@@ -18,7 +18,7 @@ module Geokit
18
18
  # Template method which does the geocode lookup.
19
19
  def self.do_geocode(address)
20
20
  address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
21
- url = "#{protocol}://www.mapquestapi.com/geocoding/v1/address?key=#{key}&location=#{Geokit::Inflector::url_escape(address_str)}"
21
+ url = "#{protocol}://www.mapquestapi.com/geocoding/v1/address?key=#{key}&location=#{Geokit::Inflector.url_escape(address_str)}"
22
22
  process :json, url
23
23
  end
24
24
 
@@ -34,7 +34,7 @@ module Geokit
34
34
  loc.all.push(extracted_geoloc)
35
35
  end
36
36
  end
37
- end
37
+ end
38
38
  loc
39
39
  end
40
40
 
@@ -0,0 +1,93 @@
1
+ module Geokit
2
+ module Geocoders
3
+ # OpenCage geocoder implementation. Requires the Geokit::Geocoders::OpencageGeocoder.key
4
+ # variable to contain an API key. Conforms to the interface set by the Geocoder class.
5
+ class OpencageGeocoder < Geocoder
6
+ config :key
7
+ self.secure = true
8
+
9
+ private
10
+
11
+ # Template method which does the geocode lookup.
12
+ def self.do_geocode(address, options = {})
13
+ options_str = generate_param_for_option(:language, options)
14
+ options_str << generate_param_for_option(:bounds, options)
15
+ options_str << generate_param_for_option(:min_confidence, options)
16
+
17
+ address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
18
+ url = "#{protocol}://api.opencagedata.com/geocode/v1/json?"
19
+ url += "key=#{key}#{options_str}&"
20
+ url += "query=#{Geokit::Inflector.url_escape(address_str)}&"
21
+ url += 'no_annotations=1'
22
+ process :json, url
23
+ end
24
+ # Template method which does the reverse-geocode lookup.
25
+ def self.do_reverse_geocode(latlng)
26
+ latlng = LatLng.normalize(latlng)
27
+ url = "#{protocol}://api.opencagedata.com/geocode/v1/json?"
28
+ url += "key=#{key}&query=#{latlng.lat},#{latlng.lng}"
29
+ process :json, url
30
+ end
31
+
32
+ def self.generate_param_for(param, value)
33
+ "&#{param}=#{Geokit::Inflector.url_escape(value.to_s)}"
34
+ end
35
+
36
+ def self.generate_param_for_option(param, options)
37
+ options[param] ? "&#{param}=#{Geokit::Inflector.url_escape(options[param])}" : ''
38
+ end
39
+
40
+ def self.generate_bool_param_for_option(param, options)
41
+ options[param] ? "&#{param}=1" : "&#{param}=0"
42
+ end
43
+
44
+ def self.parse_json(results)
45
+ return GeoLoc.new if results.empty?
46
+ if results.is_a?(Hash)
47
+ return GeoLoc.new unless results['status']['message'] == 'OK'
48
+ end
49
+
50
+ loc = nil
51
+ results['results'].each do |result|
52
+ extracted_geoloc = extract_geoloc(result)
53
+ if loc.nil?
54
+ loc = extracted_geoloc
55
+ else
56
+ loc.all.push(extracted_geoloc)
57
+ end
58
+ end
59
+ loc
60
+ end
61
+
62
+ def self.extract_geoloc(result_json)
63
+ loc = new_loc
64
+ loc.lat = result_json['geometry']['lat']
65
+ loc.lng = result_json['geometry']['lng']
66
+ set_address_components(result_json['components'], loc)
67
+ set_precision(result_json, loc)
68
+ loc.success = true
69
+ loc
70
+ end
71
+
72
+ def self.set_address_components(address_data, loc)
73
+ return unless address_data
74
+ loc.country = address_data['country']
75
+ loc.country_code = address_data['country_code'].upcase if address_data['country_code']
76
+ loc.state_name = address_data['state']
77
+ loc.city = address_data['city']
78
+ loc.city = address_data['county'] if loc.city.nil? && address_data['county']
79
+ loc.zip = address_data['postcode']
80
+ loc.district = address_data['city_district']
81
+ loc.district = address_data['state_district'] if loc.district.nil? && address_data['state_district']
82
+ loc.street_address = "#{address_data['road']} #{address_data['house_number']}".strip if address_data['road']
83
+ loc.street_name = address_data['road']
84
+ loc.street_number = address_data['house_number']
85
+ end
86
+
87
+ def self.set_precision(result_json, loc)
88
+ # a value between 1 (worse) and 10 (best). 0 means unknown
89
+ loc.precision = result_json['confidence']
90
+ end
91
+ end
92
+ end
93
+ end