geocoder 1.1.3 → 1.1.6
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.
- data/.travis.yml +4 -0
- data/{CHANGELOG.rdoc → CHANGELOG.md} +109 -35
- data/README.md +645 -0
- data/examples/autoexpire_cache.rb +28 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +18 -22
- data/lib/geocoder/cache.rb +2 -1
- data/lib/geocoder/calculations.rb +13 -13
- data/lib/geocoder/cli.rb +17 -19
- data/lib/geocoder/configuration.rb +68 -42
- data/lib/geocoder/configuration_hash.rb +11 -0
- data/lib/geocoder/exceptions.rb +3 -0
- data/lib/geocoder/lookup.rb +81 -0
- data/lib/geocoder/lookups/base.rb +106 -56
- data/lib/geocoder/lookups/bing.rb +25 -11
- data/lib/geocoder/lookups/freegeoip.rb +11 -7
- data/lib/geocoder/lookups/geocoder_ca.rb +17 -9
- data/lib/geocoder/lookups/google.rb +29 -8
- data/lib/geocoder/lookups/google_premier.rb +20 -11
- data/lib/geocoder/lookups/mapquest.rb +29 -19
- data/lib/geocoder/lookups/maxmind.rb +72 -0
- data/lib/geocoder/lookups/nominatim.rb +21 -13
- data/lib/geocoder/lookups/test.rb +12 -6
- data/lib/geocoder/lookups/yahoo.rb +63 -13
- data/lib/geocoder/lookups/yandex.rb +26 -11
- data/lib/geocoder/models/mongoid.rb +1 -2
- data/lib/geocoder/query.rb +103 -0
- data/lib/geocoder/request.rb +7 -1
- data/lib/geocoder/results/base.rb +8 -2
- data/lib/geocoder/results/google.rb +6 -0
- data/lib/geocoder/results/mapquest.rb +19 -34
- data/lib/geocoder/results/maxmind.rb +136 -0
- data/lib/geocoder/results/nominatim.rb +14 -3
- data/lib/geocoder/results/yahoo.rb +9 -2
- data/lib/geocoder/sql.rb +106 -0
- data/lib/geocoder/stores/active_record.rb +75 -142
- data/lib/geocoder/stores/base.rb +3 -2
- data/lib/geocoder/stores/mongo_base.rb +2 -2
- data/lib/geocoder/version.rb +1 -1
- data/lib/geocoder.rb +11 -89
- data/lib/hash_recursive_merge.rb +74 -0
- data/lib/oauth_util.rb +112 -0
- data/test/active_record_test.rb +15 -0
- data/test/cache_test.rb +19 -0
- data/test/calculations_test.rb +11 -4
- data/test/configuration_test.rb +26 -51
- data/test/error_handling_test.rb +15 -11
- data/test/fixtures/bing_invalid_key +1 -0
- data/test/fixtures/mapquest_madison_square_garden +52 -0
- data/test/fixtures/mapquest_no_results +7 -0
- data/test/fixtures/maxmind_24_24_24_21 +1 -0
- data/test/fixtures/maxmind_24_24_24_22 +1 -0
- data/test/fixtures/maxmind_24_24_24_23 +1 -0
- data/test/fixtures/maxmind_24_24_24_24 +1 -0
- data/test/fixtures/maxmind_74_200_247_59 +1 -0
- data/test/fixtures/maxmind_invalid_key +1 -0
- data/test/fixtures/maxmind_no_results +1 -0
- data/test/fixtures/yahoo_error +1 -0
- data/test/fixtures/yahoo_invalid_key +2 -0
- data/test/fixtures/yahoo_madison_square_garden +52 -0
- data/test/fixtures/yahoo_no_results +10 -0
- data/test/fixtures/yahoo_over_limit +2 -0
- data/test/https_test.rb +3 -3
- data/test/integration/smoke_test.rb +8 -6
- data/test/lookup_test.rb +92 -13
- data/test/near_test.rb +11 -0
- data/test/oauth_util_test.rb +30 -0
- data/test/proxy_test.rb +2 -2
- data/test/query_test.rb +42 -0
- data/test/result_test.rb +4 -3
- data/test/services_test.rb +164 -26
- data/test/test_helper.rb +93 -112
- data/test/test_mode_test.rb +3 -4
- metadata +52 -35
- data/README.rdoc +0 -552
- data/test/fixtures/mapquest_madison_square_garden.json +0 -27
- data/test/fixtures/mapquest_no_results.json +0 -1
- data/test/fixtures/yahoo_garbage.json +0 -50
- data/test/fixtures/yahoo_madison_square_garden.json +0 -46
- data/test/fixtures/yahoo_no_results.json +0 -10
- data/test/input_handling_test.rb +0 -43
- /data/test/fixtures/{bing_madison_square_garden.json → bing_madison_square_garden} +0 -0
- /data/test/fixtures/{bing_no_results.json → bing_no_results} +0 -0
- /data/test/fixtures/{bing_reverse.json → bing_reverse} +0 -0
- /data/test/fixtures/{freegeoip_74_200_247_59.json → freegeoip_74_200_247_59} +0 -0
- /data/test/fixtures/{freegeoip_no_results.json → freegeoip_no_results} +0 -0
- /data/test/fixtures/{geocoder_ca_madison_square_garden.json → geocoder_ca_madison_square_garden} +0 -0
- /data/test/fixtures/{geocoder_ca_no_results.json → geocoder_ca_no_results} +0 -0
- /data/test/fixtures/{geocoder_ca_reverse.json → geocoder_ca_reverse} +0 -0
- /data/test/fixtures/{google_garbage.json → google_garbage} +0 -0
- /data/test/fixtures/{google_madison_square_garden.json → google_madison_square_garden} +0 -0
- /data/test/fixtures/{google_no_city_data.json → google_no_city_data} +0 -0
- /data/test/fixtures/{google_no_locality.json → google_no_locality} +0 -0
- /data/test/fixtures/{google_no_results.json → google_no_results} +0 -0
- /data/test/fixtures/{nominatim_madison_square_garden.json → nominatim_madison_square_garden} +0 -0
- /data/test/fixtures/{nominatim_no_results.json → nominatim_no_results} +0 -0
- /data/test/fixtures/{yandex_invalid_key.json → yandex_invalid_key} +0 -0
- /data/test/fixtures/{yandex_kremlin.json → yandex_kremlin} +0 -0
- /data/test/fixtures/{yandex_no_results.json → yandex_no_results} +0 -0
|
@@ -5,12 +5,18 @@ module Geocoder
|
|
|
5
5
|
module Lookup
|
|
6
6
|
class Test < Base
|
|
7
7
|
|
|
8
|
-
def
|
|
9
|
-
|
|
8
|
+
def name
|
|
9
|
+
"Test"
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def self.
|
|
13
|
-
stubs
|
|
12
|
+
def self.add_stub(query_text, results)
|
|
13
|
+
stubs[query_text] = results
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.read_stub(query_text)
|
|
17
|
+
stubs.fetch(query_text) {
|
|
18
|
+
raise ArgumentError, "unknown stub request #{query_text}"
|
|
19
|
+
}
|
|
14
20
|
end
|
|
15
21
|
|
|
16
22
|
def self.stubs
|
|
@@ -23,8 +29,8 @@ module Geocoder
|
|
|
23
29
|
|
|
24
30
|
private
|
|
25
31
|
|
|
26
|
-
def results(query
|
|
27
|
-
Geocoder::Lookup::Test.read_stub(query)
|
|
32
|
+
def results(query)
|
|
33
|
+
Geocoder::Lookup::Test.read_stub(query.text)
|
|
28
34
|
end
|
|
29
35
|
|
|
30
36
|
end
|
|
@@ -1,34 +1,84 @@
|
|
|
1
1
|
require 'geocoder/lookups/base'
|
|
2
2
|
require "geocoder/results/yahoo"
|
|
3
|
+
require 'oauth_util'
|
|
3
4
|
|
|
4
5
|
module Geocoder::Lookup
|
|
5
6
|
class Yahoo < Base
|
|
6
7
|
|
|
8
|
+
def name
|
|
9
|
+
"Yahoo BOSS"
|
|
10
|
+
end
|
|
11
|
+
|
|
7
12
|
def map_link_url(coordinates)
|
|
8
13
|
"http://maps.yahoo.com/#lat=#{coordinates[0]}&lon=#{coordinates[1]}"
|
|
9
14
|
end
|
|
10
15
|
|
|
16
|
+
def required_api_key_parts
|
|
17
|
+
["consumer key", "consumer secret"]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def query_url(query)
|
|
21
|
+
parsed_url = URI.parse(raw_url(query))
|
|
22
|
+
o = OauthUtil.new
|
|
23
|
+
o.consumer_key = configuration.api_key[0]
|
|
24
|
+
o.consumer_secret = configuration.api_key[1]
|
|
25
|
+
base_url + o.sign(parsed_url).query_string
|
|
26
|
+
end
|
|
27
|
+
|
|
11
28
|
private # ---------------------------------------------------------------
|
|
12
29
|
|
|
13
|
-
def results(query
|
|
14
|
-
return [] unless doc = fetch_data(query
|
|
15
|
-
|
|
16
|
-
|
|
30
|
+
def results(query)
|
|
31
|
+
return [] unless doc = fetch_data(query)
|
|
32
|
+
doc = doc['bossresponse']
|
|
33
|
+
if doc['responsecode'].to_i == 200
|
|
34
|
+
if doc['placefinder']['count'].to_i > 0
|
|
35
|
+
return doc['placefinder']['results']
|
|
36
|
+
else
|
|
37
|
+
return []
|
|
38
|
+
end
|
|
17
39
|
else
|
|
18
|
-
warn "Yahoo Geocoding API error: #{doc['
|
|
40
|
+
warn "Yahoo Geocoding API error: #{doc['responsecode']} (#{doc['reason']})."
|
|
19
41
|
return []
|
|
20
42
|
end
|
|
21
43
|
end
|
|
22
44
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
45
|
+
##
|
|
46
|
+
# Yahoo returns errors as XML even when JSON format is specified.
|
|
47
|
+
# Handle that here, without parsing the XML
|
|
48
|
+
# (which would add unnecessary complexity).
|
|
49
|
+
#
|
|
50
|
+
def parse_raw_data(raw_data)
|
|
51
|
+
if raw_data.match /^<\?xml/
|
|
52
|
+
if raw_data.include?("Rate Limit Exceeded")
|
|
53
|
+
raise_error(Geocoder::OverQueryLimitError) || warn("Over API query limit.")
|
|
54
|
+
elsif raw_data.include?("Please provide valid credentials")
|
|
55
|
+
raise_error(Geocoder::InvalidApiKey) || warn("Invalid API key.")
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
super(raw_data)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def query_url_params(query)
|
|
63
|
+
{
|
|
64
|
+
:location => query.sanitized_text,
|
|
26
65
|
:flags => "JXTSR",
|
|
27
|
-
:gflags => "AC#{'R' if
|
|
28
|
-
:locale => "#{
|
|
29
|
-
:appid =>
|
|
30
|
-
}
|
|
31
|
-
|
|
66
|
+
:gflags => "AC#{'R' if query.reverse_geocode?}",
|
|
67
|
+
:locale => "#{configuration.language}_US",
|
|
68
|
+
:appid => configuration.api_key
|
|
69
|
+
}.merge(super)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def cache_key(query)
|
|
73
|
+
raw_url(query)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def base_url
|
|
77
|
+
"#{protocol}://yboss.yahooapis.com/geo/placefinder?"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def raw_url(query)
|
|
81
|
+
base_url + url_query_string(query)
|
|
32
82
|
end
|
|
33
83
|
end
|
|
34
84
|
end
|
|
@@ -4,16 +4,28 @@ require "geocoder/results/yandex"
|
|
|
4
4
|
module Geocoder::Lookup
|
|
5
5
|
class Yandex < Base
|
|
6
6
|
|
|
7
|
+
def name
|
|
8
|
+
"Yandex"
|
|
9
|
+
end
|
|
10
|
+
|
|
7
11
|
def map_link_url(coordinates)
|
|
8
12
|
"http://maps.yandex.ru/?ll=#{coordinates.reverse.join(',')}"
|
|
9
13
|
end
|
|
10
14
|
|
|
15
|
+
def query_url(query)
|
|
16
|
+
"#{protocol}://geocode-maps.yandex.ru/1.x/?" + url_query_string(query)
|
|
17
|
+
end
|
|
18
|
+
|
|
11
19
|
private # ---------------------------------------------------------------
|
|
12
20
|
|
|
13
|
-
def results(query
|
|
14
|
-
return [] unless doc = fetch_data(query
|
|
21
|
+
def results(query)
|
|
22
|
+
return [] unless doc = fetch_data(query)
|
|
15
23
|
if err = doc['error']
|
|
16
|
-
|
|
24
|
+
if err["status"] == 401 and err["message"] == "invalid key"
|
|
25
|
+
raise_error(Geocoder::InvalidApiKey) || warn("Invalid API key.")
|
|
26
|
+
else
|
|
27
|
+
warn "Yandex Geocoding API error: #{err['status']} (#{err['message']})."
|
|
28
|
+
end
|
|
17
29
|
return []
|
|
18
30
|
end
|
|
19
31
|
if doc = doc['response']['GeoObjectCollection']
|
|
@@ -25,15 +37,18 @@ module Geocoder::Lookup
|
|
|
25
37
|
end
|
|
26
38
|
end
|
|
27
39
|
|
|
28
|
-
def
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
def query_url_params(query)
|
|
41
|
+
if query.reverse_geocode?
|
|
42
|
+
q = query.coordinates.reverse.join(",")
|
|
43
|
+
else
|
|
44
|
+
q = query.sanitized_text
|
|
45
|
+
end
|
|
46
|
+
{
|
|
47
|
+
:geocode => q,
|
|
32
48
|
:format => "json",
|
|
33
|
-
:plng => "#{
|
|
34
|
-
:key =>
|
|
35
|
-
}
|
|
36
|
-
"http://geocode-maps.yandex.ru/1.x/?" + hash_to_query(params)
|
|
49
|
+
:plng => "#{configuration.language}", # supports ru, uk, be
|
|
50
|
+
:key => configuration.api_key
|
|
51
|
+
}.merge(super)
|
|
37
52
|
end
|
|
38
53
|
end
|
|
39
54
|
end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require 'mongoid/version'
|
|
2
1
|
require 'geocoder/models/base'
|
|
3
2
|
require 'geocoder/models/mongo_base'
|
|
4
3
|
|
|
@@ -19,7 +18,7 @@ module Geocoder
|
|
|
19
18
|
super(options)
|
|
20
19
|
if options[:skip_index] == false
|
|
21
20
|
# create 2d index
|
|
22
|
-
if (::Mongoid::VERSION >= "3"
|
|
21
|
+
if defined?(::Mongoid::VERSION) && ::Mongoid::VERSION >= "3"
|
|
23
22
|
index({ geocoder_options[:coordinates].to_sym => '2d' },
|
|
24
23
|
{:min => -180, :max => 180})
|
|
25
24
|
else
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module Geocoder
|
|
2
|
+
class Query
|
|
3
|
+
attr_accessor :text, :options
|
|
4
|
+
|
|
5
|
+
def initialize(text, options = {})
|
|
6
|
+
self.text = text
|
|
7
|
+
self.options = options
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def execute
|
|
11
|
+
lookup.search(text, options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
text
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def sanitized_text
|
|
19
|
+
if coordinates?
|
|
20
|
+
text.split(/\s*,\s*/).join(',')
|
|
21
|
+
else
|
|
22
|
+
text
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Get a Lookup object (which communicates with the remote geocoding API)
|
|
28
|
+
# appropriate to the Query text.
|
|
29
|
+
#
|
|
30
|
+
def lookup
|
|
31
|
+
if ip_address?
|
|
32
|
+
name = Configuration.ip_lookup || Geocoder::Lookup.ip_services.first
|
|
33
|
+
else
|
|
34
|
+
name = Configuration.lookup || Geocoder::Lookup.street_services.first
|
|
35
|
+
end
|
|
36
|
+
Lookup.get(name)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def url
|
|
40
|
+
lookup.query_url(self)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
##
|
|
44
|
+
# Is the Query blank? (ie, should we not bother searching?)
|
|
45
|
+
# A query is considered blank if its text is nil or empty string AND
|
|
46
|
+
# no URL parameters are specified.
|
|
47
|
+
#
|
|
48
|
+
def blank?
|
|
49
|
+
!params_given? and (
|
|
50
|
+
(text.is_a?(Array) and text.compact.size < 2) or
|
|
51
|
+
text.to_s.match(/^\s*$/)
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
##
|
|
56
|
+
# Does the Query text look like an IP address?
|
|
57
|
+
#
|
|
58
|
+
# Does not check for actual validity, just the appearance of four
|
|
59
|
+
# dot-delimited numbers.
|
|
60
|
+
#
|
|
61
|
+
def ip_address?
|
|
62
|
+
!!text.to_s.match(/^(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
##
|
|
66
|
+
# Is the Query text a loopback IP address?
|
|
67
|
+
#
|
|
68
|
+
def loopback_ip_address?
|
|
69
|
+
!!(text == "0.0.0.0" or text.to_s.match(/^127/))
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Does the given string look like latitude/longitude coordinates?
|
|
74
|
+
#
|
|
75
|
+
def coordinates?
|
|
76
|
+
text.is_a?(Array) or (
|
|
77
|
+
text.is_a?(String) and
|
|
78
|
+
!!text.to_s.match(/^-?[0-9\.]+, *-?[0-9\.]+$/)
|
|
79
|
+
)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
##
|
|
83
|
+
# Return the latitude/longitude coordinates specified in the query,
|
|
84
|
+
# or nil if none.
|
|
85
|
+
#
|
|
86
|
+
def coordinates
|
|
87
|
+
sanitized_text.split(',') if coordinates?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
# Should reverse geocoding be performed for this query?
|
|
92
|
+
#
|
|
93
|
+
def reverse_geocode?
|
|
94
|
+
coordinates?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private # ----------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
def params_given?
|
|
100
|
+
!!(options[:params].is_a?(Hash) and options[:params].keys.size > 0)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
data/lib/geocoder/request.rb
CHANGED
|
@@ -5,7 +5,13 @@ module Geocoder
|
|
|
5
5
|
|
|
6
6
|
def location
|
|
7
7
|
unless defined?(@location)
|
|
8
|
-
|
|
8
|
+
if env.has_key?('HTTP_X_REAL_IP')
|
|
9
|
+
@location = Geocoder.search(env['HTTP_X_REAL_IP']).first
|
|
10
|
+
elsif env.has_key?('HTTP_X_FORWARDED_FOR')
|
|
11
|
+
@location = Geocoder.search(env['HTTP_X_FORWARDED_FOR']).first
|
|
12
|
+
else
|
|
13
|
+
@location = Geocoder.search(ip).first
|
|
14
|
+
end
|
|
9
15
|
end
|
|
10
16
|
@location
|
|
11
17
|
end
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
module Geocoder
|
|
2
2
|
module Result
|
|
3
3
|
class Base
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
# data (hash) fetched from geocoding service
|
|
6
|
+
attr_accessor :data
|
|
7
|
+
|
|
8
|
+
# true if result came from cache, false if from request to geocoding
|
|
9
|
+
# service; nil if cache is not configured
|
|
10
|
+
attr_accessor :cache_hit
|
|
5
11
|
|
|
6
12
|
##
|
|
7
|
-
# Takes a hash of
|
|
13
|
+
# Takes a hash of data from a parsed geocoding service response.
|
|
8
14
|
#
|
|
9
15
|
def initialize(data)
|
|
10
16
|
@data = data
|
|
@@ -2,65 +2,50 @@ require 'geocoder/results/base'
|
|
|
2
2
|
|
|
3
3
|
module Geocoder::Result
|
|
4
4
|
class Mapquest < Base
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@data['address']['house_number']
|
|
5
|
+
def latitude
|
|
6
|
+
@data["latLng"]["lat"]
|
|
8
7
|
end
|
|
9
8
|
|
|
10
|
-
def
|
|
11
|
-
@data[
|
|
9
|
+
def longitude
|
|
10
|
+
@data["latLng"]["lng"]
|
|
12
11
|
end
|
|
13
12
|
|
|
14
|
-
def
|
|
15
|
-
|
|
13
|
+
def coordinates
|
|
14
|
+
[latitude, longitude]
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
def city
|
|
19
|
-
@data['
|
|
18
|
+
@data['adminArea5']
|
|
20
19
|
end
|
|
21
20
|
|
|
22
|
-
def
|
|
23
|
-
@data['
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def town
|
|
27
|
-
@data['address']['town']
|
|
21
|
+
def street
|
|
22
|
+
@data['street']
|
|
28
23
|
end
|
|
29
24
|
|
|
30
25
|
def state
|
|
31
|
-
@data['
|
|
26
|
+
@data['adminArea3']
|
|
32
27
|
end
|
|
33
28
|
|
|
34
29
|
alias_method :state_code, :state
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
#FIXME: these might not be right, unclear with MQ documentation
|
|
32
|
+
alias_method :provinice, :state
|
|
33
|
+
alias_method :province_code, :state
|
|
39
34
|
|
|
40
|
-
def
|
|
41
|
-
@data['
|
|
35
|
+
def postal_code
|
|
36
|
+
@data['postalCode'].to_s
|
|
42
37
|
end
|
|
43
38
|
|
|
44
39
|
def country
|
|
45
|
-
@data['
|
|
40
|
+
@data['adminArea1']
|
|
46
41
|
end
|
|
47
42
|
|
|
48
43
|
def country_code
|
|
49
|
-
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def coordinates
|
|
53
|
-
[@data['lat'].to_f, @data['lon'].to_f]
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def self.response_attributes
|
|
57
|
-
%w[place_id boundingbox license polygonpoints display_name class type stadium suburb]
|
|
44
|
+
country
|
|
58
45
|
end
|
|
59
46
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
@data[a]
|
|
63
|
-
end
|
|
47
|
+
def address
|
|
48
|
+
[street, city, state, postal_code, country].reject{|s| s.length == 0 }.join(", ")
|
|
64
49
|
end
|
|
65
50
|
end
|
|
66
51
|
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class Maxmind < Base
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# Hash mapping service names to names of returned fields.
|
|
8
|
+
#
|
|
9
|
+
def self.field_names
|
|
10
|
+
{
|
|
11
|
+
:country => [
|
|
12
|
+
:country_code,
|
|
13
|
+
:error
|
|
14
|
+
],
|
|
15
|
+
|
|
16
|
+
:city => [
|
|
17
|
+
:country_code,
|
|
18
|
+
:region_code,
|
|
19
|
+
:city_name,
|
|
20
|
+
:latitude,
|
|
21
|
+
:longitude,
|
|
22
|
+
:error
|
|
23
|
+
],
|
|
24
|
+
|
|
25
|
+
:city_isp_org => [
|
|
26
|
+
:country_code,
|
|
27
|
+
:region_code,
|
|
28
|
+
:city_name,
|
|
29
|
+
:postal_code,
|
|
30
|
+
:latitude,
|
|
31
|
+
:longitude,
|
|
32
|
+
:metro_code,
|
|
33
|
+
:area_code,
|
|
34
|
+
:isp_name,
|
|
35
|
+
:organization_name,
|
|
36
|
+
:error
|
|
37
|
+
],
|
|
38
|
+
|
|
39
|
+
:omni => [
|
|
40
|
+
:country_code,
|
|
41
|
+
:country_name,
|
|
42
|
+
:region_code,
|
|
43
|
+
:region_name,
|
|
44
|
+
:city_name,
|
|
45
|
+
:latitude,
|
|
46
|
+
:longitude,
|
|
47
|
+
:metro_code,
|
|
48
|
+
:area_code,
|
|
49
|
+
:time_zone,
|
|
50
|
+
:continent_code,
|
|
51
|
+
:postal_code,
|
|
52
|
+
:isp_name,
|
|
53
|
+
:organization_name,
|
|
54
|
+
:domain,
|
|
55
|
+
:as_number,
|
|
56
|
+
:netspeed,
|
|
57
|
+
:user_type,
|
|
58
|
+
:accuracy_radius,
|
|
59
|
+
:country_confidence_factor,
|
|
60
|
+
:city_confidence_factor,
|
|
61
|
+
:region_confidence_factor,
|
|
62
|
+
:postal_confidence_factor,
|
|
63
|
+
:error
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# Name of the MaxMind service being used.
|
|
70
|
+
# Inferred from format of @data.
|
|
71
|
+
#
|
|
72
|
+
def service_name
|
|
73
|
+
self.class.field_names.to_a.each do |n,f|
|
|
74
|
+
return n if f.size == @data.size
|
|
75
|
+
end
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def field_names
|
|
80
|
+
self.class.field_names[service_name]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def data_hash
|
|
84
|
+
@data_hash ||= Hash[*field_names.zip(@data).flatten]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def coordinates
|
|
88
|
+
[data_hash[:latitude].to_f, data_hash[:longitude].to_f]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def address(format = :full)
|
|
92
|
+
s = state_code.to_s == "" ? "" : ", #{state_code}"
|
|
93
|
+
"#{city}#{s} #{postal_code}, #{country_code}".sub(/^[ ,]*/, "")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def city
|
|
97
|
+
data_hash[:city_name]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def state # not given by MaxMind
|
|
101
|
+
data_hash[:region_name] || data_hash[:region_code]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def state_code
|
|
105
|
+
data_hash[:region_code]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def country #not given by MaxMind
|
|
109
|
+
data_hash[:country_name] || data_hash[:country_code]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def country_code
|
|
113
|
+
data_hash[:country_code]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def postal_code
|
|
117
|
+
data_hash[:postal_code]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def method_missing(method, *args, &block)
|
|
121
|
+
if field_names.include?(method)
|
|
122
|
+
data_hash[method]
|
|
123
|
+
else
|
|
124
|
+
super
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def respond_to?(method)
|
|
129
|
+
if field_names.include?(method)
|
|
130
|
+
true
|
|
131
|
+
else
|
|
132
|
+
super
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -5,8 +5,9 @@ module Geocoder::Result
|
|
|
5
5
|
|
|
6
6
|
def poi
|
|
7
7
|
%w[stadium bus_stop tram_stop].each do |key|
|
|
8
|
-
@data['address'][key] if @data['address'].key?(key)
|
|
8
|
+
return @data['address'][key] if @data['address'].key?(key)
|
|
9
9
|
end
|
|
10
|
+
return nil
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def house_number
|
|
@@ -69,14 +70,24 @@ module Geocoder::Result
|
|
|
69
70
|
[@data['lat'].to_f, @data['lon'].to_f]
|
|
70
71
|
end
|
|
71
72
|
|
|
73
|
+
def place_class
|
|
74
|
+
@data['class']
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def place_type
|
|
78
|
+
@data['type']
|
|
79
|
+
end
|
|
80
|
+
|
|
72
81
|
def self.response_attributes
|
|
73
82
|
%w[place_id osm_type osm_id boundingbox license
|
|
74
83
|
polygonpoints display_name class type stadium]
|
|
75
84
|
end
|
|
76
85
|
|
|
77
86
|
response_attributes.each do |a|
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
unless method_defined?(a)
|
|
88
|
+
define_method a do
|
|
89
|
+
@data[a]
|
|
90
|
+
end
|
|
80
91
|
end
|
|
81
92
|
end
|
|
82
93
|
end
|
|
@@ -31,17 +31,24 @@ module Geocoder::Result
|
|
|
31
31
|
@data['postal']
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
def address_hash
|
|
35
|
+
@data['hash']
|
|
36
|
+
end
|
|
37
|
+
|
|
34
38
|
def self.response_attributes
|
|
35
39
|
%w[quality offsetlat offsetlon radius boundingbox name
|
|
36
40
|
line1 line2 line3 line4 cross house street xstreet unittype unit
|
|
41
|
+
city state statecode country countrycode postal
|
|
37
42
|
neighborhood county countycode
|
|
38
43
|
level0 level1 level2 level3 level4 level0code level1code level2code
|
|
39
44
|
timezone areacode uzip hash woeid woetype]
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
response_attributes.each do |a|
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
unless method_defined?(a)
|
|
49
|
+
define_method a do
|
|
50
|
+
@data[a]
|
|
51
|
+
end
|
|
45
52
|
end
|
|
46
53
|
end
|
|
47
54
|
end
|