geocoder 1.5.1 → 1.8.5

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 (100) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +107 -0
  3. data/LICENSE +1 -1
  4. data/README.md +364 -243
  5. data/bin/console +13 -0
  6. data/examples/app_defined_lookup_services.rb +22 -0
  7. data/lib/easting_northing.rb +171 -0
  8. data/lib/generators/geocoder/config/templates/initializer.rb +6 -1
  9. data/lib/geocoder/cache.rb +16 -33
  10. data/lib/geocoder/cache_stores/base.rb +40 -0
  11. data/lib/geocoder/cache_stores/generic.rb +35 -0
  12. data/lib/geocoder/cache_stores/redis.rb +34 -0
  13. data/lib/geocoder/configuration.rb +19 -5
  14. data/lib/geocoder/configuration_hash.rb +4 -4
  15. data/lib/geocoder/ip_address.rb +11 -1
  16. data/lib/geocoder/lookup.rb +42 -6
  17. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  18. data/lib/geocoder/lookups/amap.rb +2 -2
  19. data/lib/geocoder/lookups/amazon_location_service.rb +58 -0
  20. data/lib/geocoder/lookups/azure.rb +56 -0
  21. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +15 -2
  22. data/lib/geocoder/lookups/base.rb +4 -1
  23. data/lib/geocoder/lookups/bing.rb +2 -2
  24. data/lib/geocoder/lookups/esri.rb +24 -5
  25. data/lib/geocoder/lookups/freegeoip.rb +12 -10
  26. data/lib/geocoder/lookups/geoapify.rb +78 -0
  27. data/lib/geocoder/lookups/geocodio.rb +1 -1
  28. data/lib/geocoder/lookups/geoip2.rb +4 -0
  29. data/lib/geocoder/lookups/geoportail_lu.rb +1 -1
  30. data/lib/geocoder/lookups/google.rb +7 -2
  31. data/lib/geocoder/lookups/google_places_details.rb +26 -12
  32. data/lib/geocoder/lookups/google_places_search.rb +44 -2
  33. data/lib/geocoder/lookups/google_premier.rb +4 -0
  34. data/lib/geocoder/lookups/here.rb +27 -31
  35. data/lib/geocoder/lookups/ip2location.rb +10 -14
  36. data/lib/geocoder/lookups/ip2location_io.rb +62 -0
  37. data/lib/geocoder/lookups/ip2location_lite.rb +40 -0
  38. data/lib/geocoder/lookups/ipbase.rb +49 -0
  39. data/lib/geocoder/lookups/ipdata_co.rb +1 -1
  40. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  41. data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
  42. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  43. data/lib/geocoder/lookups/latlon.rb +1 -2
  44. data/lib/geocoder/lookups/location_iq.rb +5 -1
  45. data/lib/geocoder/lookups/mapbox.rb +3 -3
  46. data/lib/geocoder/lookups/maxmind_local.rb +7 -1
  47. data/lib/geocoder/lookups/melissa_street.rb +41 -0
  48. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  49. data/lib/geocoder/lookups/osmnames.rb +57 -0
  50. data/lib/geocoder/lookups/pc_miler.rb +85 -0
  51. data/lib/geocoder/lookups/pdok_nl.rb +43 -0
  52. data/lib/geocoder/lookups/photon.rb +89 -0
  53. data/lib/geocoder/lookups/pickpoint.rb +1 -1
  54. data/lib/geocoder/lookups/smarty_streets.rb +6 -1
  55. data/lib/geocoder/lookups/telize.rb +1 -1
  56. data/lib/geocoder/lookups/tencent.rb +9 -9
  57. data/lib/geocoder/lookups/test.rb +5 -0
  58. data/lib/geocoder/lookups/twogis.rb +58 -0
  59. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  60. data/lib/geocoder/lookups/yandex.rb +6 -7
  61. data/lib/geocoder/query.rb +1 -1
  62. data/lib/geocoder/results/abstract_api.rb +146 -0
  63. data/lib/geocoder/results/amazon_location_service.rb +62 -0
  64. data/lib/geocoder/results/azure.rb +65 -0
  65. data/lib/geocoder/results/baidu.rb +0 -4
  66. data/lib/geocoder/results/ban_data_gouv_fr.rb +28 -3
  67. data/lib/geocoder/results/db_ip_com.rb +1 -1
  68. data/lib/geocoder/results/esri.rb +5 -2
  69. data/lib/geocoder/results/geoapify.rb +179 -0
  70. data/lib/geocoder/results/here.rb +20 -22
  71. data/lib/geocoder/results/ip2location_io.rb +21 -0
  72. data/lib/geocoder/results/ip2location_lite.rb +47 -0
  73. data/lib/geocoder/results/ipbase.rb +40 -0
  74. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  75. data/lib/geocoder/results/ipqualityscore.rb +54 -0
  76. data/lib/geocoder/results/ipregistry.rb +304 -0
  77. data/lib/geocoder/results/mapbox.rb +34 -10
  78. data/lib/geocoder/results/melissa_street.rb +46 -0
  79. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  80. data/lib/geocoder/results/nominatim.rb +27 -15
  81. data/lib/geocoder/results/osmnames.rb +56 -0
  82. data/lib/geocoder/results/pc_miler.rb +98 -0
  83. data/lib/geocoder/results/pdok_nl.rb +62 -0
  84. data/lib/geocoder/results/photon.rb +119 -0
  85. data/lib/geocoder/results/twogis.rb +76 -0
  86. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  87. data/lib/geocoder/results/yandex.rb +217 -59
  88. data/lib/geocoder/sql.rb +4 -4
  89. data/lib/geocoder/util.rb +29 -0
  90. data/lib/geocoder/version.rb +1 -1
  91. data/lib/maxmind_database.rb +12 -12
  92. data/lib/tasks/maxmind.rake +1 -1
  93. metadata +81 -23
  94. data/examples/autoexpire_cache_dalli.rb +0 -62
  95. data/examples/autoexpire_cache_redis.rb +0 -28
  96. data/lib/geocoder/lookups/dstk.rb +0 -22
  97. data/lib/geocoder/lookups/geocoder_us.rb +0 -51
  98. data/lib/geocoder/results/dstk.rb +0 -6
  99. data/lib/geocoder/results/geocoder_us.rb +0 -39
  100. data/lib/hash_recursive_merge.rb +0 -74
@@ -0,0 +1,65 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Azure < Base
5
+ def address
6
+ @data['address']['freeformAddress']
7
+ end
8
+
9
+ def building_number
10
+ @data['address']['buildingNumber']
11
+ end
12
+
13
+ def city
14
+ @data['address']['municipality']
15
+ end
16
+
17
+ def coordinates
18
+ if @data['position'].is_a?(String) # reverse geocoding result
19
+ @data['position'].split(',').map(&:to_f)
20
+ elsif @data['position'].is_a?(Hash) # forward geocoding result
21
+ [@data['position']['lat'], @data['position']['lon']]
22
+ end
23
+ end
24
+
25
+ def country
26
+ @data['address']['country']
27
+ end
28
+
29
+ def country_code
30
+ @data['address']['countryCode']
31
+ end
32
+
33
+ def district
34
+ @data['address']['municipalitySubdivision']
35
+ end
36
+
37
+ def postal_code
38
+ @data['address']['postalCode']
39
+ end
40
+
41
+ def province
42
+ @data['address']['countrySubdivision']
43
+ end
44
+
45
+ def state
46
+ @data['address']['countrySubdivision']
47
+ end
48
+
49
+ def state_code
50
+ @data['address']['countrySubdivisionCode']
51
+ end
52
+
53
+ def street_name
54
+ @data['address']['streetName']
55
+ end
56
+
57
+ def street_number
58
+ @data['address']['streetNumber']
59
+ end
60
+
61
+ def viewport
62
+ @data['viewport'] || {}
63
+ end
64
+ end
65
+ end
@@ -7,10 +7,6 @@ module Geocoder::Result
7
7
  ['lat', 'lng'].map{ |i| @data['location'][i] }
8
8
  end
9
9
 
10
- def address
11
- @data['formatted_address']
12
- end
13
-
14
10
  def province
15
11
  @data['addressComponent'] and @data['addressComponent']['province'] or ""
16
12
  end
@@ -4,10 +4,31 @@ require 'geocoder/results/base'
4
4
  module Geocoder::Result
5
5
  class BanDataGouvFr < Base
6
6
 
7
+ STATE_CODE_MAPPINGS = {
8
+ "Guadeloupe" => "01",
9
+ "Martinique" => "02",
10
+ "Guyane" => "03",
11
+ "La Réunion" => "04",
12
+ "Mayotte" => "06",
13
+ "Île-de-France" => "11",
14
+ "Centre-Val de Loire" => "24",
15
+ "Bourgogne-Franche-Comté" => "27",
16
+ "Normandie" => "28",
17
+ "Hauts-de-France" => "32",
18
+ "Grand Est" => "44",
19
+ "Pays de la Loire" => "52",
20
+ "Bretagne" => "53",
21
+ "Nouvelle-Aquitaine" => "75",
22
+ "Occitanie" => "76",
23
+ "Auvergne-Rhône-Alpes" => "84",
24
+ "Provence-Alpes-Côte d'Azur" => "93",
25
+ "Corse" => "94"
26
+ }.freeze
27
+
7
28
  #### BASE METHODS ####
8
29
 
9
30
  def self.response_attributes
10
- %w[limit attribution version licence type features]
31
+ %w[limit attribution version licence type features center]
11
32
  end
12
33
 
13
34
  response_attributes.each do |a|
@@ -209,6 +230,10 @@ module Geocoder::Result
209
230
  end
210
231
  end
211
232
 
233
+ def region_code
234
+ STATE_CODE_MAPPINGS[region_name]
235
+ end
236
+
212
237
  def country
213
238
  "France"
214
239
  end
@@ -235,7 +260,7 @@ module Geocoder::Result
235
260
  alias_method :street, :street_name
236
261
  alias_method :city, :city_name
237
262
  alias_method :state, :region_name
238
- alias_method :state_code, :state
263
+ alias_method :state_code, :region_code
239
264
 
240
265
  #### CITIES' METHODS ####
241
266
 
@@ -250,7 +275,7 @@ module Geocoder::Result
250
275
  private
251
276
 
252
277
  def city?(result_type)
253
- %w(village town city).include?(result_type)
278
+ result_type == 'municipality'
254
279
  end
255
280
 
256
281
  end
@@ -16,7 +16,7 @@ module Geocoder::Result
16
16
  end
17
17
 
18
18
  def state_code
19
- @data['stateProv']
19
+ @data['stateProvCode']
20
20
  end
21
21
  alias_method :state, :state_code
22
22
 
@@ -16,11 +16,14 @@ module Geocoder::Result
16
16
  end
17
17
  end
18
18
 
19
- def state_code
19
+ def state
20
20
  attributes['Region']
21
21
  end
22
22
 
23
- alias_method :state, :state_code
23
+ def state_code
24
+ abbr = attributes['RegionAbbr']
25
+ abbr.to_s == "" ? state : abbr
26
+ end
24
27
 
25
28
  def country
26
29
  country_key = reverse_geocode? ? "CountryCode" : "Country"
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'geocoder/results/base'
4
+
5
+ module Geocoder
6
+ module Result
7
+ # https://apidocs.geoapify.com/docs/geocoding/api
8
+ class Geoapify < Base
9
+ def address(_format = :full)
10
+ properties['formatted']
11
+ end
12
+
13
+ def address_line1
14
+ properties['address_line1']
15
+ end
16
+
17
+ def address_line2
18
+ properties['address_line2']
19
+ end
20
+
21
+ def house_number
22
+ properties['housenumber']
23
+ end
24
+
25
+ def street
26
+ properties['street']
27
+ end
28
+
29
+ def postal_code
30
+ properties['postcode']
31
+ end
32
+
33
+ def district
34
+ properties['district']
35
+ end
36
+
37
+ def suburb
38
+ properties['suburb']
39
+ end
40
+
41
+ def city
42
+ properties['city']
43
+ end
44
+
45
+ def county
46
+ properties['county']
47
+ end
48
+
49
+ def state
50
+ properties['state']
51
+ end
52
+
53
+ # Not currently available in the API
54
+ def state_code
55
+ ''
56
+ end
57
+
58
+ def country
59
+ properties['country']
60
+ end
61
+
62
+ def country_code
63
+ return unless properties['country_code']
64
+
65
+ properties['country_code'].upcase
66
+ end
67
+
68
+ def coordinates
69
+ return unless properties['lat']
70
+ return unless properties['lon']
71
+
72
+ [properties['lat'], properties['lon']]
73
+ end
74
+
75
+ # See: https://tools.ietf.org/html/rfc7946#section-3.1
76
+ #
77
+ # Each feature has a "Point" type in the Geoapify API.
78
+ def geometry
79
+ return unless data['geometry']
80
+
81
+ symbol_hash data['geometry']
82
+ end
83
+
84
+ # See: https://tools.ietf.org/html/rfc7946#section-5
85
+ def bounds
86
+ data['bbox']
87
+ end
88
+
89
+ # Type of the result, one of:
90
+ #
91
+ # * :unknown
92
+ # * :amenity
93
+ # * :building
94
+ # * :street
95
+ # * :suburb
96
+ # * :district
97
+ # * :postcode
98
+ # * :city
99
+ # * :county
100
+ # * :state
101
+ # * :country
102
+ #
103
+ def type
104
+ return :unknown unless properties['result_type']
105
+
106
+ properties['result_type'].to_sym
107
+ end
108
+
109
+ # Distance in meters to given bias:proximity or to given coordinates for
110
+ # reverse geocoding
111
+ def distance
112
+ properties['distance']
113
+ end
114
+
115
+ # Calculated rank for the result, containing the following keys:
116
+ #
117
+ # * `popularity` - The popularity score of the result
118
+ # * `confidence` - The confidence value of the result (0-1)
119
+ # * `match_type` - The result's match type, one of following:
120
+ # * full_match
121
+ # * inner_part
122
+ # * match_by_building
123
+ # * match_by_street
124
+ # * match_by_postcode
125
+ # * match_by_city_or_disrict
126
+ # * match_by_country_or_state
127
+ #
128
+ # Example:
129
+ # {
130
+ # popularity: 8.615793062435909,
131
+ # confidence: 0.88,
132
+ # match_type: :full_match
133
+ # }
134
+ def rank
135
+ return unless properties['rank']
136
+
137
+ r = symbol_hash(properties['rank'])
138
+ r[:match_type] = r[:match_type].to_sym if r[:match_type]
139
+ r
140
+ end
141
+
142
+ # Examples:
143
+ #
144
+ # Open
145
+ # {
146
+ # sourcename: 'openstreetmap',
147
+ # wheelchair: 'limited',
148
+ # wikidata: 'Q186125',
149
+ # wikipedia: 'en:Madison Square Garden',
150
+ # website: 'http://www.thegarden.com/',
151
+ # phone: '12124656741',
152
+ # osm_type: 'W',
153
+ # osm_id: 138141251,
154
+ # continent: 'North America',
155
+ # }
156
+ def datasource
157
+ return unless properties['datasource']
158
+
159
+ symbol_hash properties['datasource']
160
+ end
161
+
162
+ private
163
+
164
+ def properties
165
+ @properties ||= data['properties'] || {}
166
+ end
167
+
168
+ def symbol_hash(orig_hash)
169
+ {}.tap do |result|
170
+ orig_hash.each_key do |key|
171
+ next unless orig_hash[key]
172
+
173
+ result[key.to_sym] = orig_hash[key]
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -7,73 +7,71 @@ module Geocoder::Result
7
7
  # A string in the given format.
8
8
  #
9
9
  def address(format = :full)
10
- address_data['Label']
10
+ address_data["label"]
11
11
  end
12
12
 
13
13
  ##
14
14
  # A two-element array: [lat, lon].
15
15
  #
16
16
  def coordinates
17
- fail unless d = @data['Location']['DisplayPosition']
18
- [d['Latitude'].to_f, d['Longitude'].to_f]
17
+ fail unless d = @data["position"]
18
+ [d["lat"].to_f, d["lng"].to_f]
19
19
  end
20
20
 
21
21
  def route
22
- address_data['Street']
22
+ address_data["street"]
23
23
  end
24
24
 
25
25
  def street_number
26
- address_data['HouseNumber']
26
+ address_data["houseNumber"]
27
27
  end
28
28
 
29
29
  def state
30
- address_data['County']
30
+ address_data["state"]
31
31
  end
32
32
 
33
33
  def province
34
- address_data['County']
34
+ address_data["county"]
35
35
  end
36
36
 
37
37
  def postal_code
38
- address_data['PostalCode']
38
+ address_data["postalCode"]
39
39
  end
40
40
 
41
41
  def city
42
- address_data['City']
42
+ address_data["city"]
43
43
  end
44
44
 
45
45
  def state_code
46
- address_data['State']
46
+ address_data["stateCode"]
47
47
  end
48
48
 
49
49
  def province_code
50
- address_data['State']
50
+ address_data["state"]
51
51
  end
52
52
 
53
53
  def country
54
- fail unless d = address_data['AdditionalData']
55
- if v = d.find{|ad| ad['key']=='CountryName'}
56
- return v['value']
57
- end
54
+ address_data["countryName"]
58
55
  end
59
56
 
60
57
  def country_code
61
- address_data['Country']
58
+ address_data["countryCode"]
62
59
  end
63
60
 
64
61
  def viewport
65
- map_view = data['Location']['MapView'] || fail
66
- south = map_view['BottomRight']['Latitude']
67
- west = map_view['TopLeft']['Longitude']
68
- north = map_view['TopLeft']['Latitude']
69
- east = map_view['BottomRight']['Longitude']
62
+ return [] if data["resultType"] == "place"
63
+ map_view = data["mapView"]
64
+ south = map_view["south"]
65
+ west = map_view["west"]
66
+ north = map_view["north"]
67
+ east = map_view["east"]
70
68
  [south, west, north, east]
71
69
  end
72
70
 
73
71
  private # ----------------------------------------------------------------
74
72
 
75
73
  def address_data
76
- @data['Location']['Address'] || fail
74
+ @data["address"] || fail
77
75
  end
78
76
  end
79
77
  end
@@ -0,0 +1,21 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Ip2locationIo < Base
5
+
6
+ def address(format = :full)
7
+ "#{city_name} #{zip_code}, #{country_name}".sub(/^[ ,]*/, '')
8
+ end
9
+
10
+ def self.response_attributes
11
+ %w[ip country_code country_name region_name city_name latitude longitude
12
+ zip_code time_zone asn as is_proxy]
13
+ end
14
+
15
+ response_attributes.each do |attr|
16
+ define_method attr do
17
+ @data[attr] || ""
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Ip2locationLite < Base
5
+
6
+ def coordinates
7
+ [@data[:latitude], @data[:longitude]]
8
+ end
9
+
10
+ def city
11
+ @data[:city]
12
+ end
13
+
14
+ def state
15
+ @data[:region]
16
+ end
17
+
18
+ def state_code
19
+ "" # Not available in Maxmind's database
20
+ end
21
+
22
+ def country
23
+ @data[:country_long]
24
+ end
25
+
26
+ def country_code
27
+ @data[:country_short]
28
+ end
29
+
30
+ def postal_code
31
+ @data[:zipcode]
32
+ end
33
+
34
+ def self.response_attributes
35
+ %w[country_short country_long region latitude longitude isp
36
+ domain netspeed areacode iddcode timezone zipcode weatherstationname
37
+ weatherstationcode mcc mnc mobilebrand elevation usagetype addresstype
38
+ category district asn as]
39
+ end
40
+
41
+ response_attributes.each do |a|
42
+ define_method a do
43
+ @data[a] || ""
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Ipbase < Base
5
+ def ip
6
+ @data["data"]['ip']
7
+ end
8
+
9
+ def country_code
10
+ @data["data"]["location"]["country"]["alpha2"]
11
+ end
12
+
13
+ def country
14
+ @data["data"]["location"]["country"]["name"]
15
+ end
16
+
17
+ def state_code
18
+ @data["data"]["location"]["region"]["alpha2"]
19
+ end
20
+
21
+ def state
22
+ @data["data"]["location"]["region"]["name"]
23
+ end
24
+
25
+ def city
26
+ @data["data"]["location"]["city"]["name"]
27
+ end
28
+
29
+ def postal_code
30
+ @data["data"]["location"]["zip"]
31
+ end
32
+
33
+ def coordinates
34
+ [
35
+ @data["data"]["location"]["latitude"].to_f,
36
+ @data["data"]["location"]["longitude"].to_f
37
+ ]
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,59 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Ipgeolocation < Base
5
+
6
+ def coordinates
7
+ [@data['latitude'].to_f, @data['longitude'].to_f]
8
+ end
9
+
10
+ def address(format = :full)
11
+ "#{city}, #{state} #{postal_code}, #{country_name}".sub(/^[ ,]*/, "")
12
+ end
13
+
14
+ def state
15
+ @data['state_prov']
16
+ end
17
+
18
+ def state_code
19
+ @data['state_prov']
20
+ end
21
+
22
+ def country
23
+ @data['country_name']
24
+ end
25
+
26
+ def country_code
27
+ @data['country_code2']
28
+ end
29
+
30
+ def postal_code
31
+ @data['zipcode']
32
+ end
33
+
34
+ def self.response_attributes
35
+ [
36
+ ['ip', ''],
37
+ ['hostname', ''],
38
+ ['continent_code', ''],
39
+ ['continent_name', ''],
40
+ ['country_code2', ''],
41
+ ['country_code3', ''],
42
+ ['country_name', ''],
43
+ ['country_capital',''],
44
+ ['district',''],
45
+ ['state_prov',''],
46
+ ['city', ''],
47
+ ['zipcode', ''],
48
+ ['time_zone', {}],
49
+ ['currency', {}]
50
+ ]
51
+ end
52
+
53
+ response_attributes.each do |attr, default|
54
+ define_method attr do
55
+ @data[attr] || default
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,54 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder
4
+ module Result
5
+ class Ipqualityscore < Base
6
+
7
+ def self.key_method_mappings
8
+ {
9
+ 'request_id' => :request_id,
10
+ 'success' => :success?,
11
+ 'message' => :message,
12
+ 'city' => :city,
13
+ 'region' => :state,
14
+ 'country_code' => :country_code,
15
+ 'mobile' => :mobile?,
16
+ 'fraud_score' => :fraud_score,
17
+ 'ISP' => :isp,
18
+ 'ASN' => :asn,
19
+ 'organization' => :organization,
20
+ 'is_crawler' => :crawler?,
21
+ 'host' => :host,
22
+ 'proxy' => :proxy?,
23
+ 'vpn' => :vpn?,
24
+ 'tor' => :tor?,
25
+ 'active_vpn' => :active_vpn?,
26
+ 'active_tor' => :active_tor?,
27
+ 'recent_abuse' => :recent_abuse?,
28
+ 'bot_status' => :bot?,
29
+ 'connection_type' => :connection_type,
30
+ 'abuse_velocity' => :abuse_velocity,
31
+ 'timezone' => :timezone,
32
+ }
33
+ end
34
+
35
+ key_method_mappings.each_pair do |key, meth|
36
+ define_method meth do
37
+ @data[key]
38
+ end
39
+ end
40
+
41
+ alias_method :state_code, :state
42
+ alias_method :country, :country_code
43
+
44
+ def postal_code
45
+ '' # No suitable fallback
46
+ end
47
+
48
+ def address
49
+ [city, state, country_code].compact.reject(&:empty?).join(', ')
50
+ end
51
+
52
+ end
53
+ end
54
+ end