geokit 1.8.5 → 1.9.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 (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