geocoder 1.1.9 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of geocoder might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +9 -5
- data/CHANGELOG.md +19 -0
- data/README.md +175 -10
- data/Rakefile +1 -1
- data/gemfiles/Gemfile.mongoid-2.4.x +1 -0
- data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +28 -0
- data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +28 -0
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +27 -0
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +17 -0
- data/lib/geocoder.rb +4 -12
- data/lib/geocoder/cache.rb +3 -2
- data/lib/geocoder/calculations.rb +39 -0
- data/lib/geocoder/configuration.rb +1 -7
- data/lib/geocoder/ip_address.rb +12 -0
- data/lib/geocoder/lookup.rb +10 -1
- data/lib/geocoder/lookups/baidu.rb +7 -6
- data/lib/geocoder/lookups/baidu_ip.rb +54 -0
- data/lib/geocoder/lookups/base.rb +37 -9
- data/lib/geocoder/lookups/bing.rb +10 -5
- data/lib/geocoder/lookups/cloudmade.rb +35 -0
- data/lib/geocoder/lookups/freegeoip.rb +5 -1
- data/lib/geocoder/lookups/geocodio.rb +42 -0
- data/lib/geocoder/lookups/google_premier.rb +1 -1
- data/lib/geocoder/lookups/here.rb +62 -0
- data/lib/geocoder/lookups/mapquest.rb +2 -1
- data/lib/geocoder/lookups/maxmind_local.rb +58 -0
- data/lib/geocoder/lookups/nominatim.rb +8 -0
- data/lib/geocoder/lookups/smarty_streets.rb +45 -0
- data/lib/geocoder/lookups/yahoo.rb +1 -1
- data/lib/geocoder/models/active_record.rb +5 -3
- data/lib/geocoder/models/base.rb +1 -4
- data/lib/geocoder/models/mongo_base.rb +4 -2
- data/lib/geocoder/query.rb +4 -4
- data/lib/geocoder/railtie.rb +1 -1
- data/lib/geocoder/request.rb +10 -8
- data/lib/geocoder/results/baidu_ip.rb +62 -0
- data/lib/geocoder/results/cloudmade.rb +39 -0
- data/lib/geocoder/results/geocodio.rb +66 -0
- data/lib/geocoder/results/here.rb +62 -0
- data/lib/geocoder/results/maxmind_local.rb +49 -0
- data/lib/geocoder/results/smarty_streets.rb +106 -0
- data/lib/geocoder/results/test.rb +20 -3
- data/lib/geocoder/results/yandex.rb +7 -3
- data/lib/geocoder/sql.rb +16 -15
- data/lib/geocoder/stores/active_record.rb +6 -2
- data/lib/geocoder/stores/base.rb +8 -1
- data/lib/geocoder/version.rb +1 -1
- data/lib/maxmind_database.rb +109 -0
- data/lib/oauth_util.rb +1 -1
- data/lib/tasks/geocoder.rake +3 -1
- data/lib/tasks/maxmind.rake +73 -0
- data/test/fixtures/baidu_ip_202_198_16_3 +19 -0
- data/test/fixtures/baidu_ip_invalid_key +1 -0
- data/test/fixtures/baidu_ip_no_results +1 -0
- data/test/fixtures/cloudmade_invalid_key +1 -0
- data/test/fixtures/cloudmade_madison_square_garden +1 -0
- data/test/fixtures/cloudmade_no_results +1 -0
- data/test/fixtures/geocodio_1101_pennsylvania_ave +1 -0
- data/test/fixtures/geocodio_bad_api_key +3 -0
- data/test/fixtures/geocodio_invalid +4 -0
- data/test/fixtures/geocodio_no_results +1 -0
- data/test/fixtures/geocodio_over_query_limit +4 -0
- data/test/fixtures/here_madison_square_garden +72 -0
- data/test/fixtures/here_no_results +8 -0
- data/test/fixtures/nominatim_over_limit +1 -0
- data/test/fixtures/smarty_streets_11211 +1 -0
- data/test/fixtures/smarty_streets_madison_square_garden +47 -0
- data/test/fixtures/smarty_streets_no_results +1 -0
- data/test/fixtures/yandex_canada_rue_dupuis_14 +446 -0
- data/test/fixtures/yandex_new_york +1 -0
- data/test/integration/http_client_test.rb +25 -0
- data/test/mongoid_test_helper.rb +2 -2
- data/test/test_helper.rb +98 -30
- data/test/{active_record_test.rb → unit/active_record_test.rb} +4 -3
- data/test/{cache_test.rb → unit/cache_test.rb} +3 -1
- data/test/{calculations_test.rb → unit/calculations_test.rb} +22 -13
- data/test/{configuration_test.rb → unit/configuration_test.rb} +4 -27
- data/test/{error_handling_test.rb → unit/error_handling_test.rb} +10 -9
- data/test/{geocoder_test.rb → unit/geocoder_test.rb} +26 -7
- data/test/{https_test.rb → unit/https_test.rb} +4 -3
- data/test/unit/ip_address_test.rb +24 -0
- data/test/{lookup_test.rb → unit/lookup_test.rb} +33 -20
- data/test/unit/lookups/bing_test.rb +68 -0
- data/test/unit/lookups/dstk_test.rb +26 -0
- data/test/unit/lookups/esri_test.rb +48 -0
- data/test/unit/lookups/freegeoip_test.rb +27 -0
- data/test/unit/lookups/geocoder_ca_test.rb +17 -0
- data/test/unit/lookups/geocodio_test.rb +55 -0
- data/test/unit/lookups/google_premier_test.rb +22 -0
- data/test/unit/lookups/google_test.rb +84 -0
- data/test/unit/lookups/mapquest_test.rb +60 -0
- data/test/unit/lookups/maxmind_local_test.rb +28 -0
- data/test/unit/lookups/maxmind_test.rb +63 -0
- data/test/unit/lookups/nominatim_test.rb +31 -0
- data/test/unit/lookups/smarty_streets_test.rb +71 -0
- data/test/unit/lookups/yahoo_test.rb +35 -0
- data/test/{method_aliases_test.rb → unit/method_aliases_test.rb} +5 -4
- data/test/unit/model_test.rb +38 -0
- data/test/{mongoid_test.rb → unit/mongoid_test.rb} +10 -9
- data/test/unit/near_test.rb +87 -0
- data/test/{oauth_util_test.rb → unit/oauth_util_test.rb} +3 -2
- data/test/{proxy_test.rb → unit/proxy_test.rb} +2 -1
- data/test/{query_test.rb → unit/query_test.rb} +7 -8
- data/test/unit/rake_task_test.rb +21 -0
- data/test/{request_test.rb → unit/request_test.rb} +8 -2
- data/test/{result_test.rb → unit/result_test.rb} +29 -1
- data/test/{test_mode_test.rb → unit/test_mode_test.rb} +12 -1
- metadata +80 -27
- data/test/custom_block_test.rb +0 -32
- data/test/integration/smoke_test.rb +0 -26
- data/test/near_test.rb +0 -61
- data/test/services_test.rb +0 -393
@@ -31,7 +31,7 @@ module Geocoder::Lookup
|
|
31
31
|
|
32
32
|
def sign(string)
|
33
33
|
raw_private_key = url_safe_base64_decode(configuration.api_key[0])
|
34
|
-
digest = OpenSSL::Digest
|
34
|
+
digest = OpenSSL::Digest.new('sha1')
|
35
35
|
raw_signature = OpenSSL::HMAC.digest(digest, raw_private_key, string)
|
36
36
|
url_safe_base64_encode(raw_signature)
|
37
37
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/here'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class Here < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Here"
|
9
|
+
end
|
10
|
+
|
11
|
+
def required_api_key_parts
|
12
|
+
[]
|
13
|
+
end
|
14
|
+
|
15
|
+
def query_url(query)
|
16
|
+
"#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.api.here.com/6.2/#{if query.reverse_geocode? then 'reverse' end}geocode.json?" + url_query_string(query)
|
17
|
+
end
|
18
|
+
|
19
|
+
private # ---------------------------------------------------------------
|
20
|
+
|
21
|
+
def results(query)
|
22
|
+
return [] unless doc = fetch_data(query)
|
23
|
+
return [] unless doc['Response'] && doc['Response']['View']
|
24
|
+
if r=doc['Response']['View']
|
25
|
+
return [] if r.nil? || !r.is_a?(Array) || r.empty?
|
26
|
+
return r.first['Result']
|
27
|
+
end
|
28
|
+
[]
|
29
|
+
end
|
30
|
+
|
31
|
+
def query_url_params(query)
|
32
|
+
options = {
|
33
|
+
:gen=>4,
|
34
|
+
:app_id=>api_key,
|
35
|
+
:app_code=>api_code
|
36
|
+
}
|
37
|
+
|
38
|
+
if query.reverse_geocode?
|
39
|
+
super.merge(options).merge(
|
40
|
+
:prox=>query.sanitized_text,
|
41
|
+
:mode=>:retrieveAddresses
|
42
|
+
)
|
43
|
+
else
|
44
|
+
super.merge(options).merge(
|
45
|
+
:searchtext=>query.sanitized_text
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def api_key
|
51
|
+
if a=configuration.api_key
|
52
|
+
return a.first if a.is_a?(Array)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def api_code
|
57
|
+
if a=configuration.api_key
|
58
|
+
return a.last if a.is_a?(Array)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -14,7 +14,7 @@ module Geocoder::Lookup
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def query_url(query)
|
17
|
-
domain = configuration[:
|
17
|
+
domain = configuration[:open] ? "open" : "www"
|
18
18
|
version = configuration[:version] || 1
|
19
19
|
url = "#{protocol}://#{domain}.mapquestapi.com/geocoding/v#{version}/#{search_type(query)}?"
|
20
20
|
url + url_query_string(query)
|
@@ -53,6 +53,7 @@ module Geocoder::Lookup
|
|
53
53
|
raise_error(Geocoder::Error, messages) ||
|
54
54
|
warn("Mapquest Geocoding API error: #{messages}")
|
55
55
|
end
|
56
|
+
[]
|
56
57
|
end
|
57
58
|
|
58
59
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
require 'geocoder/lookups/base'
|
3
|
+
require 'geocoder/results/maxmind_local'
|
4
|
+
|
5
|
+
module Geocoder::Lookup
|
6
|
+
class MaxmindLocal < Base
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
if !configuration[:file].nil?
|
10
|
+
begin
|
11
|
+
gem = RUBY_PLATFORM == 'java' ? 'jgeoip' : 'geoip'
|
12
|
+
require gem
|
13
|
+
rescue LoadError
|
14
|
+
raise "Could not load geoip dependency. To use MaxMind Local lookup you must add the #{gem} gem to your Gemfile or have it installed in your system."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def name
|
21
|
+
"MaxMind Local"
|
22
|
+
end
|
23
|
+
|
24
|
+
def required_api_key_parts
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def results(query)
|
31
|
+
if configuration[:file]
|
32
|
+
geoip_class = RUBY_PLATFORM == "java" ? JGeoIP : GeoIP
|
33
|
+
result = geoip_class.new(configuration[:file]).city(query.to_s)
|
34
|
+
result.nil? ? [] : [result.to_hash]
|
35
|
+
elsif configuration[:package] == :city
|
36
|
+
addr = IPAddr.new(query.text).to_i
|
37
|
+
q = "SELECT l.country, l.region, l.city
|
38
|
+
FROM maxmind_geolite_city_location l JOIN maxmind_geolite_city_blocks b USING (loc_id)
|
39
|
+
WHERE b.start_ip_num <= #{addr} AND #{addr} <= b.end_ip_num"
|
40
|
+
format_result(q, [:country_name, :region_name, :city_name])
|
41
|
+
elsif configuration[:package] == :country
|
42
|
+
addr = IPAddr.new(query.text).to_i
|
43
|
+
q = "SELECT country, country_code FROM maxmind_geolite_country
|
44
|
+
WHERE start_ip_num <= #{addr} AND #{addr} <= end_ip_num"
|
45
|
+
format_result(q, [:country_name, :country_code2])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def format_result(query, attr_names)
|
50
|
+
if r = ActiveRecord::Base.connection.execute(query).first
|
51
|
+
r = r.values if r.is_a?(Hash) # some db adapters return Hash, some Array
|
52
|
+
[Hash[*attr_names.zip(r).flatten]]
|
53
|
+
else
|
54
|
+
[]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -25,6 +25,14 @@ module Geocoder::Lookup
|
|
25
25
|
doc.is_a?(Array) ? doc : [doc]
|
26
26
|
end
|
27
27
|
|
28
|
+
def parse_raw_data(raw_data)
|
29
|
+
if raw_data.include?("Bandwidth limit exceeded")
|
30
|
+
raise_error(Geocoder::OverQueryLimitError) || warn("Over API query limit.")
|
31
|
+
else
|
32
|
+
super(raw_data)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
28
36
|
def query_url_params(query)
|
29
37
|
params = {
|
30
38
|
:format => "json",
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/smarty_streets'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class SmartyStreets < Base
|
6
|
+
def name
|
7
|
+
"SmartyStreets"
|
8
|
+
end
|
9
|
+
|
10
|
+
def required_api_key_parts
|
11
|
+
%w(auth-token)
|
12
|
+
end
|
13
|
+
|
14
|
+
def query_url(query)
|
15
|
+
path = zipcode_only?(query) ? "zipcode" : "street-address"
|
16
|
+
"#{protocol}://api.smartystreets.com/#{path}?#{url_query_string(query)}"
|
17
|
+
end
|
18
|
+
|
19
|
+
private # ---------------------------------------------------------------
|
20
|
+
|
21
|
+
def zipcode_only?(query)
|
22
|
+
!query.text.is_a?(Array) and query.to_s.strip =~ /\A\d{5}(-\d{4})?\Z/
|
23
|
+
end
|
24
|
+
|
25
|
+
def query_url_params(query)
|
26
|
+
params = {}
|
27
|
+
if zipcode_only?(query)
|
28
|
+
params[:zipcode] = query.sanitized_text
|
29
|
+
else
|
30
|
+
params[:street] = query.sanitized_text
|
31
|
+
end
|
32
|
+
if configuration.api_key.is_a?(Array)
|
33
|
+
params[:"auth-id"] = configuration.api_key[0]
|
34
|
+
params[:"auth-token"] = configuration.api_key[1]
|
35
|
+
else
|
36
|
+
params[:"auth-token"] = configuration.api_key
|
37
|
+
end
|
38
|
+
params.merge(super)
|
39
|
+
end
|
40
|
+
|
41
|
+
def results(query)
|
42
|
+
fetch_data(query) || []
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -50,7 +50,7 @@ module Geocoder::Lookup
|
|
50
50
|
# to warning message.
|
51
51
|
#
|
52
52
|
def parse_raw_data(raw_data)
|
53
|
-
if raw_data.match
|
53
|
+
if raw_data.match(/^<\?xml/)
|
54
54
|
if raw_data.include?("Rate Limit Exceeded")
|
55
55
|
raise_error(Geocoder::OverQueryLimitError) || warn("Over API query limit.")
|
56
56
|
elsif raw_data =~ /<yahoo:description>(Please provide valid credentials.*)<\/yahoo:description>/i
|
@@ -16,7 +16,8 @@ module Geocoder
|
|
16
16
|
:longitude => options[:longitude] || :longitude,
|
17
17
|
:geocode_block => block,
|
18
18
|
:units => options[:units],
|
19
|
-
:method => options[:method]
|
19
|
+
:method => options[:method],
|
20
|
+
:lookup => options[:lookup]
|
20
21
|
)
|
21
22
|
end
|
22
23
|
|
@@ -30,8 +31,9 @@ module Geocoder
|
|
30
31
|
:latitude => latitude_attr,
|
31
32
|
:longitude => longitude_attr,
|
32
33
|
:reverse_block => block,
|
33
|
-
:units
|
34
|
-
:method
|
34
|
+
:units => options[:units],
|
35
|
+
:method => options[:method],
|
36
|
+
:lookup => options[:lookup]
|
35
37
|
)
|
36
38
|
end
|
37
39
|
|
data/lib/geocoder/models/base.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'geocoder'
|
2
|
-
|
3
1
|
module Geocoder
|
4
2
|
|
5
3
|
##
|
@@ -29,7 +27,7 @@ module Geocoder
|
|
29
27
|
private # ----------------------------------------------------------------
|
30
28
|
|
31
29
|
def geocoder_init(options)
|
32
|
-
unless @geocoder_options
|
30
|
+
unless defined?(@geocoder_options)
|
33
31
|
@geocoder_options = {}
|
34
32
|
require "geocoder/stores/#{geocoder_file_name}"
|
35
33
|
include Geocoder::Store.const_get(geocoder_module_name)
|
@@ -39,4 +37,3 @@ module Geocoder
|
|
39
37
|
end
|
40
38
|
end
|
41
39
|
end
|
42
|
-
|
@@ -19,7 +19,8 @@ module Geocoder
|
|
19
19
|
:geocode_block => block,
|
20
20
|
:units => options[:units],
|
21
21
|
:method => options[:method],
|
22
|
-
:skip_index => options[:skip_index] || false
|
22
|
+
:skip_index => options[:skip_index] || false,
|
23
|
+
:lookup => options[:lookup]
|
23
24
|
)
|
24
25
|
end
|
25
26
|
|
@@ -34,7 +35,8 @@ module Geocoder
|
|
34
35
|
:reverse_block => block,
|
35
36
|
:units => options[:units],
|
36
37
|
:method => options[:method],
|
37
|
-
:skip_index => options[:skip_index] || false
|
38
|
+
:skip_index => options[:skip_index] || false,
|
39
|
+
:lookup => options[:lookup]
|
38
40
|
)
|
39
41
|
end
|
40
42
|
|
data/lib/geocoder/query.rb
CHANGED
@@ -33,9 +33,9 @@ module Geocoder
|
|
33
33
|
#
|
34
34
|
def lookup
|
35
35
|
if ip_address?
|
36
|
-
name = Configuration.ip_lookup || Geocoder::Lookup.ip_services.first
|
36
|
+
name = options[:ip_lookup] || Configuration.ip_lookup || Geocoder::Lookup.ip_services.first
|
37
37
|
else
|
38
|
-
name = Configuration.lookup || Geocoder::Lookup.street_services.first
|
38
|
+
name = options[:lookup] || Configuration.lookup || Geocoder::Lookup.street_services.first
|
39
39
|
end
|
40
40
|
Lookup.get(name)
|
41
41
|
end
|
@@ -63,14 +63,14 @@ module Geocoder
|
|
63
63
|
# dot-delimited numbers.
|
64
64
|
#
|
65
65
|
def ip_address?
|
66
|
-
|
66
|
+
IpAddress.new(text).valid? rescue false
|
67
67
|
end
|
68
68
|
|
69
69
|
##
|
70
70
|
# Is the Query text a loopback IP address?
|
71
71
|
#
|
72
72
|
def loopback_ip_address?
|
73
|
-
|
73
|
+
ip_address? && IpAddress.new(text).loopback?
|
74
74
|
end
|
75
75
|
|
76
76
|
##
|
data/lib/geocoder/railtie.rb
CHANGED
data/lib/geocoder/request.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
|
-
require 'geocoder'
|
2
|
-
|
3
1
|
module Geocoder
|
4
2
|
module Request
|
5
3
|
|
6
4
|
def location
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
@location ||= begin
|
6
|
+
detected_ip = env['HTTP_X_REAL_IP'] || (
|
7
|
+
env['HTTP_X_FORWARDED_FOR'] &&
|
8
|
+
env['HTTP_X_FORWARDED_FOR'].split(",").first.strip
|
9
|
+
)
|
10
|
+
detected_ip = IpAddress.new(detected_ip.to_s)
|
11
|
+
if detected_ip.valid? and !detected_ip.loopback?
|
12
|
+
real_ip = detected_ip.to_s
|
12
13
|
else
|
13
|
-
|
14
|
+
real_ip = self.ip
|
14
15
|
end
|
16
|
+
Geocoder.search(real_ip).first
|
15
17
|
end
|
16
18
|
@location
|
17
19
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder::Result
|
4
|
+
class BaiduIp < Base
|
5
|
+
def coordinates
|
6
|
+
[point['y'].to_f, point['x'].to_f]
|
7
|
+
end
|
8
|
+
|
9
|
+
def address
|
10
|
+
@data['address']
|
11
|
+
end
|
12
|
+
|
13
|
+
def state
|
14
|
+
province
|
15
|
+
end
|
16
|
+
|
17
|
+
def province
|
18
|
+
address_detail['province']
|
19
|
+
end
|
20
|
+
|
21
|
+
def city
|
22
|
+
address_detail['city']
|
23
|
+
end
|
24
|
+
|
25
|
+
def district
|
26
|
+
address_detail['district']
|
27
|
+
end
|
28
|
+
|
29
|
+
def street
|
30
|
+
address_detail['street']
|
31
|
+
end
|
32
|
+
|
33
|
+
def street_number
|
34
|
+
address_detail['street_number']
|
35
|
+
end
|
36
|
+
|
37
|
+
def state_code
|
38
|
+
""
|
39
|
+
end
|
40
|
+
|
41
|
+
def postal_code
|
42
|
+
""
|
43
|
+
end
|
44
|
+
|
45
|
+
def country
|
46
|
+
"China"
|
47
|
+
end
|
48
|
+
|
49
|
+
def country_code
|
50
|
+
"CN"
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def address_detail
|
55
|
+
@data['address_detail']
|
56
|
+
end
|
57
|
+
|
58
|
+
def point
|
59
|
+
@data['point']
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder::Result
|
4
|
+
class Cloudmade < Base
|
5
|
+
|
6
|
+
def coordinates
|
7
|
+
@data["centroid"]["coordinates"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def street
|
11
|
+
@data["location"]["road"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def city
|
15
|
+
@data["location"]["city"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def state
|
19
|
+
@data["location"]["county"]
|
20
|
+
end
|
21
|
+
alias_method :state_code, :state
|
22
|
+
|
23
|
+
def country
|
24
|
+
@data["location"]["country"]
|
25
|
+
end
|
26
|
+
alias_method :country_code, :country
|
27
|
+
|
28
|
+
def postal_code
|
29
|
+
@data["location"]["postcode"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def address
|
33
|
+
[street, city, state, postal_code, country].compact.reject{|s| s.length == 0 }.join(", ")
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|