geocoder 1.1.4 → 1.1.8
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} +120 -39
- data/README.md +200 -54
- data/examples/autoexpire_cache_dalli.rb +62 -0
- data/examples/{autoexpire_cache.rb → autoexpire_cache_redis.rb} +4 -6
- data/lib/generators/geocoder/config/templates/initializer.rb +19 -23
- data/lib/geocoder/cache.rb +6 -1
- data/lib/geocoder/calculations.rb +45 -13
- data/lib/geocoder/cli.rb +10 -11
- data/lib/geocoder/configuration.rb +67 -43
- data/lib/geocoder/configuration_hash.rb +11 -0
- data/lib/geocoder/exceptions.rb +3 -0
- data/lib/geocoder/lookup.rb +3 -1
- data/lib/geocoder/lookups/base.rb +89 -27
- data/lib/geocoder/lookups/bing.rb +21 -11
- data/lib/geocoder/lookups/esri.rb +48 -0
- data/lib/geocoder/lookups/freegeoip.rb +8 -4
- data/lib/geocoder/lookups/geocoder_ca.rb +11 -7
- data/lib/geocoder/lookups/google.rb +18 -9
- data/lib/geocoder/lookups/google_premier.rb +16 -8
- data/lib/geocoder/lookups/mapquest.rb +33 -5
- data/lib/geocoder/lookups/maxmind.rb +88 -0
- data/lib/geocoder/lookups/nominatim.rb +13 -8
- data/lib/geocoder/lookups/ovi.rb +52 -0
- data/lib/geocoder/lookups/test.rb +10 -0
- data/lib/geocoder/lookups/yahoo.rb +51 -38
- data/lib/geocoder/lookups/yandex.rb +17 -9
- data/lib/geocoder/models/mongoid.rb +1 -1
- data/lib/geocoder/query.rb +20 -5
- data/lib/geocoder/request.rb +7 -1
- data/lib/geocoder/results/base.rb +8 -2
- data/lib/geocoder/results/esri.rb +51 -0
- data/lib/geocoder/results/google.rb +34 -0
- data/lib/geocoder/results/mapquest.rb +46 -2
- data/lib/geocoder/results/maxmind.rb +135 -0
- data/lib/geocoder/results/nominatim.rb +0 -10
- data/lib/geocoder/results/ovi.rb +62 -0
- data/lib/geocoder/results/test.rb +2 -1
- data/lib/geocoder/results/yahoo.rb +9 -2
- data/lib/geocoder/results/yandex.rb +12 -2
- data/lib/geocoder/sql.rb +6 -4
- data/lib/geocoder/stores/active_record.rb +57 -30
- data/lib/geocoder/stores/base.rb +3 -2
- data/lib/geocoder/stores/mongo_base.rb +2 -1
- data/lib/geocoder/version.rb +1 -1
- data/lib/geocoder.rb +2 -4
- data/lib/hash_recursive_merge.rb +74 -0
- data/lib/oauth_util.rb +112 -0
- data/test/cache_test.rb +19 -0
- data/test/calculations_test.rb +10 -4
- data/test/configuration_test.rb +26 -51
- data/test/error_handling_test.rb +8 -4
- data/test/fixtures/bing_invalid_key +1 -0
- data/test/fixtures/esri_madison_square_garden +59 -0
- data/test/fixtures/esri_no_results +8 -0
- data/test/fixtures/esri_reverse +21 -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/ovi_madison_square_garden +72 -0
- data/test/fixtures/ovi_no_results +8 -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/fixtures/yandex_no_city_and_town +112 -0
- data/test/https_test.rb +3 -3
- data/test/integration/smoke_test.rb +2 -2
- data/test/lookup_test.rb +84 -11
- data/test/near_test.rb +43 -0
- data/test/oauth_util_test.rb +30 -0
- data/test/proxy_test.rb +2 -2
- data/test/query_test.rb +13 -0
- data/test/request_test.rb +29 -0
- data/test/result_test.rb +12 -2
- data/test/services_test.rb +208 -57
- data/test/test_helper.rb +66 -100
- data/test/test_mode_test.rb +35 -26
- metadata +58 -35
- data/test/fixtures/mapquest_madison_square_garden.json +0 -27
- data/test/fixtures/mapquest_no_results.json +0 -1
- data/test/fixtures/yahoo_madison_square_garden.json +0 -52
- data/test/fixtures/yahoo_no_results.json +0 -10
- data/test/fixtures/yahoo_v1_madison_square_garden.json +0 -46
- data/test/fixtures/yahoo_v1_no_results.json +0 -10
- /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
data/lib/geocoder/query.rb
CHANGED
|
@@ -36,11 +36,20 @@ module Geocoder
|
|
|
36
36
|
Lookup.get(name)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
def url
|
|
40
|
+
lookup.query_url(self)
|
|
41
|
+
end
|
|
42
|
+
|
|
39
43
|
##
|
|
40
|
-
# Is the Query
|
|
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.
|
|
41
47
|
#
|
|
42
48
|
def blank?
|
|
43
|
-
|
|
49
|
+
!params_given? and (
|
|
50
|
+
(text.is_a?(Array) and text.compact.size < 2) or
|
|
51
|
+
text.to_s.match(/\A\s*\z/)
|
|
52
|
+
)
|
|
44
53
|
end
|
|
45
54
|
|
|
46
55
|
##
|
|
@@ -50,14 +59,14 @@ module Geocoder
|
|
|
50
59
|
# dot-delimited numbers.
|
|
51
60
|
#
|
|
52
61
|
def ip_address?
|
|
53
|
-
!!text.to_s.match(
|
|
62
|
+
!!text.to_s.match(/\A(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\z/)
|
|
54
63
|
end
|
|
55
64
|
|
|
56
65
|
##
|
|
57
66
|
# Is the Query text a loopback IP address?
|
|
58
67
|
#
|
|
59
68
|
def loopback_ip_address?
|
|
60
|
-
!!(text == "0.0.0.0" or text.to_s.match(
|
|
69
|
+
!!(self.ip_address? and (text == "0.0.0.0" or text.to_s.match(/\A127/)))
|
|
61
70
|
end
|
|
62
71
|
|
|
63
72
|
##
|
|
@@ -66,7 +75,7 @@ module Geocoder
|
|
|
66
75
|
def coordinates?
|
|
67
76
|
text.is_a?(Array) or (
|
|
68
77
|
text.is_a?(String) and
|
|
69
|
-
!!text.to_s.match(
|
|
78
|
+
!!text.to_s.match(/\A-?[0-9\.]+, *-?[0-9\.]+\z/)
|
|
70
79
|
)
|
|
71
80
|
end
|
|
72
81
|
|
|
@@ -84,5 +93,11 @@ module Geocoder
|
|
|
84
93
|
def reverse_geocode?
|
|
85
94
|
coordinates?
|
|
86
95
|
end
|
|
96
|
+
|
|
97
|
+
private # ----------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
def params_given?
|
|
100
|
+
!!(options[:params].is_a?(Hash) and options[:params].keys.size > 0)
|
|
101
|
+
end
|
|
87
102
|
end
|
|
88
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'].split(/\s*,\s*/)[0]).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
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class Esri < Base
|
|
5
|
+
|
|
6
|
+
def address
|
|
7
|
+
address = reverse_geocode? ? 'Address' : 'Match_addr'
|
|
8
|
+
attributes[address]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def city
|
|
12
|
+
attributes['City']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def state_code
|
|
16
|
+
attributes['Region']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
alias_method :state, :state_code
|
|
20
|
+
|
|
21
|
+
def country
|
|
22
|
+
country = reverse_geocode? ? "CountryCode" : "Country"
|
|
23
|
+
attributes[country]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
alias_method :country_code, :country
|
|
27
|
+
|
|
28
|
+
def postal_code
|
|
29
|
+
attributes['Postal']
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def coordinates
|
|
33
|
+
[geometry["y"], geometry["x"]]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def attributes
|
|
39
|
+
reverse_geocode? ? @data['address'] : @data['locations'].first['feature']['attributes']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def geometry
|
|
43
|
+
reverse_geocode? ? @data["location"] : @data['locations'].first['feature']["geometry"]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def reverse_geocode?
|
|
47
|
+
@data['locations'].nil?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -11,6 +11,12 @@ module Geocoder::Result
|
|
|
11
11
|
formatted_address
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
def neighborhood
|
|
15
|
+
if neighborhood = address_components_of_type(:neighborhood).first
|
|
16
|
+
neighborhood['long_name']
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
14
20
|
def city
|
|
15
21
|
fields = [:locality, :sublocality,
|
|
16
22
|
:administrative_area_level_3,
|
|
@@ -35,6 +41,18 @@ module Geocoder::Result
|
|
|
35
41
|
end
|
|
36
42
|
end
|
|
37
43
|
|
|
44
|
+
def sub_state
|
|
45
|
+
if state = address_components_of_type(:administrative_area_level_2).first
|
|
46
|
+
state['long_name']
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def sub_state_code
|
|
51
|
+
if state = address_components_of_type(:administrative_area_level_2).first
|
|
52
|
+
state['short_name']
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
38
56
|
def country
|
|
39
57
|
if country = address_components_of_type(:country).first
|
|
40
58
|
country['long_name']
|
|
@@ -53,6 +71,22 @@ module Geocoder::Result
|
|
|
53
71
|
end
|
|
54
72
|
end
|
|
55
73
|
|
|
74
|
+
def route
|
|
75
|
+
if route = address_components_of_type(:route).first
|
|
76
|
+
route['long_name']
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def street_number
|
|
81
|
+
if street_number = address_components_of_type(:street_number).first
|
|
82
|
+
street_number['long_name']
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def street_address
|
|
87
|
+
[street_number, route].compact.join(' ')
|
|
88
|
+
end
|
|
89
|
+
|
|
56
90
|
def types
|
|
57
91
|
@data['types']
|
|
58
92
|
end
|
|
@@ -1,7 +1,51 @@
|
|
|
1
1
|
require 'geocoder/results/base'
|
|
2
|
-
require 'geocoder/results/nominatim'
|
|
3
2
|
|
|
4
3
|
module Geocoder::Result
|
|
5
|
-
class Mapquest <
|
|
4
|
+
class Mapquest < Base
|
|
5
|
+
def latitude
|
|
6
|
+
@data["latLng"]["lat"]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def longitude
|
|
10
|
+
@data["latLng"]["lng"]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def coordinates
|
|
14
|
+
[latitude, longitude]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def city
|
|
18
|
+
@data['adminArea5']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def street
|
|
22
|
+
@data['street']
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def state
|
|
26
|
+
@data['adminArea3']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
alias_method :state_code, :state
|
|
30
|
+
|
|
31
|
+
#FIXME: these might not be right, unclear with MQ documentation
|
|
32
|
+
alias_method :province, :state
|
|
33
|
+
alias_method :province_code, :state
|
|
34
|
+
|
|
35
|
+
def postal_code
|
|
36
|
+
@data['postalCode'].to_s
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def country
|
|
40
|
+
@data['adminArea1']
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def country_code
|
|
44
|
+
country
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def address
|
|
48
|
+
[street, city, state, postal_code, country].reject{|s| s.length == 0 }.join(", ")
|
|
49
|
+
end
|
|
6
50
|
end
|
|
7
51
|
end
|
|
@@ -0,0 +1,135 @@
|
|
|
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
|
+
#
|
|
71
|
+
def service_name
|
|
72
|
+
# it would be much better to infer this from the length of the @data
|
|
73
|
+
# array, but MaxMind seems to send inconsistent and wide-ranging response
|
|
74
|
+
# lengths (see https://github.com/alexreisner/geocoder/issues/396)
|
|
75
|
+
Geocoder.config.maxmind[:service]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def field_names
|
|
79
|
+
self.class.field_names[service_name]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def data_hash
|
|
83
|
+
@data_hash ||= Hash[*field_names.zip(@data).flatten]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def coordinates
|
|
87
|
+
[data_hash[:latitude].to_f, data_hash[:longitude].to_f]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def address(format = :full)
|
|
91
|
+
s = state_code.to_s == "" ? "" : ", #{state_code}"
|
|
92
|
+
"#{city}#{s} #{postal_code}, #{country_code}".sub(/^[ ,]*/, "")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def city
|
|
96
|
+
data_hash[:city_name]
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def state # not given by MaxMind
|
|
100
|
+
data_hash[:region_name] || data_hash[:region_code]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def state_code
|
|
104
|
+
data_hash[:region_code]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def country #not given by MaxMind
|
|
108
|
+
data_hash[:country_name] || data_hash[:country_code]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def country_code
|
|
112
|
+
data_hash[:country_code]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def postal_code
|
|
116
|
+
data_hash[:postal_code]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def method_missing(method, *args, &block)
|
|
120
|
+
if field_names.include?(method)
|
|
121
|
+
data_hash[method]
|
|
122
|
+
else
|
|
123
|
+
super
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def respond_to?(method)
|
|
128
|
+
if field_names.include?(method)
|
|
129
|
+
true
|
|
130
|
+
else
|
|
131
|
+
super
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -83,16 +83,6 @@ module Geocoder::Result
|
|
|
83
83
|
polygonpoints display_name class type stadium]
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
-
def class
|
|
87
|
-
warn "DEPRECATION WARNING: The 'class' method of Geocoder::Result::Nominatim objects is deprecated and will be removed in Geocoder version 1.2.0. Please use 'place_class' instead."
|
|
88
|
-
@data['class']
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def type
|
|
92
|
-
warn "DEPRECATION WARNING: The 'type' method of Geocoder::Result::Nominatim objects is deprecated and will be removed in Geocoder version 1.2.0. Please use 'place_type' instead."
|
|
93
|
-
@data['type']
|
|
94
|
-
end
|
|
95
|
-
|
|
96
86
|
response_attributes.each do |a|
|
|
97
87
|
unless method_defined?(a)
|
|
98
88
|
define_method a do
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class Ovi < Base
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# A string in the given format.
|
|
8
|
+
#
|
|
9
|
+
def address(format = :full)
|
|
10
|
+
address_data['Label']
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# A two-element array: [lat, lon].
|
|
15
|
+
#
|
|
16
|
+
def coordinates
|
|
17
|
+
fail unless d = @data['Location']['DisplayPosition']
|
|
18
|
+
[d['Latitude'].to_f, d['Longitude'].to_f]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def state
|
|
22
|
+
address_data['County']
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def province
|
|
26
|
+
address_data['County']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def postal_code
|
|
30
|
+
address_data['PostalCode']
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def city
|
|
34
|
+
address_data['City']
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def state_code
|
|
38
|
+
address_data['State']
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def province_code
|
|
42
|
+
address_data['State']
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def country
|
|
46
|
+
fail unless d = address_data['AdditionalData']
|
|
47
|
+
if v = d.find{|ad| ad['key']=='CountryName'}
|
|
48
|
+
return v['value']
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def country_code
|
|
53
|
+
address_data['Country']
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private # ----------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
def address_data
|
|
59
|
+
@data['Location']['Address'] || fail
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -5,7 +5,8 @@ module Geocoder
|
|
|
5
5
|
class Test < Base
|
|
6
6
|
|
|
7
7
|
%w[latitude longitude city state state_code province
|
|
8
|
-
province_code postal_code country country_code address
|
|
8
|
+
province_code postal_code country country_code address
|
|
9
|
+
street_address street_number route].each do |attr|
|
|
9
10
|
define_method(attr) do
|
|
10
11
|
@data[attr.to_s] || @data[attr.to_sym]
|
|
11
12
|
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
|
|
@@ -16,8 +16,10 @@ module Geocoder::Result
|
|
|
16
16
|
address_details['Locality']['LocalityName']
|
|
17
17
|
elsif sub_state.empty?
|
|
18
18
|
address_details['AdministrativeArea']['Locality']['LocalityName']
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
elsif not sub_state_city.empty?
|
|
20
|
+
sub_state_city
|
|
21
|
+
else
|
|
22
|
+
""
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
|
|
@@ -66,5 +68,13 @@ module Geocoder::Result
|
|
|
66
68
|
def address_details
|
|
67
69
|
@data['GeoObject']['metaDataProperty']['GeocoderMetaData']['AddressDetails']['Country']
|
|
68
70
|
end
|
|
71
|
+
|
|
72
|
+
def sub_state_city
|
|
73
|
+
if sub_state && sub_state["Locality"]
|
|
74
|
+
sub_state['Locality']['LocalityName']
|
|
75
|
+
else
|
|
76
|
+
""
|
|
77
|
+
end
|
|
78
|
+
end
|
|
69
79
|
end
|
|
70
80
|
end
|
data/lib/geocoder/sql.rb
CHANGED
|
@@ -11,7 +11,8 @@ module Geocoder
|
|
|
11
11
|
# http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
|
|
12
12
|
#
|
|
13
13
|
def full_distance(latitude, longitude, lat_attr, lon_attr, options = {})
|
|
14
|
-
|
|
14
|
+
units = options[:units] || Geocoder.config.units
|
|
15
|
+
earth = Geocoder::Calculations.earth_radius(units)
|
|
15
16
|
|
|
16
17
|
"#{earth} * 2 * ASIN(SQRT(" +
|
|
17
18
|
"POWER(SIN((#{latitude.to_f} - #{lat_attr}) * PI() / 180 / 2), 2) + " +
|
|
@@ -31,8 +32,9 @@ module Geocoder
|
|
|
31
32
|
# are not intended for use in production!
|
|
32
33
|
#
|
|
33
34
|
def approx_distance(latitude, longitude, lat_attr, lon_attr, options = {})
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
units = options[:units] || Geocoder.config.units
|
|
36
|
+
dx = Geocoder::Calculations.longitude_degree_distance(30, units)
|
|
37
|
+
dy = Geocoder::Calculations.latitude_degree_distance(units)
|
|
36
38
|
|
|
37
39
|
# sin of 45 degrees = average x or y component of vector
|
|
38
40
|
factor = Math.sin(Math::PI / 4)
|
|
@@ -61,7 +63,7 @@ module Geocoder
|
|
|
61
63
|
# http://www.beginningspatial.com/calculating_bearing_one_point_another
|
|
62
64
|
#
|
|
63
65
|
def full_bearing(latitude, longitude, lat_attr, lon_attr, options = {})
|
|
64
|
-
case options[:bearing]
|
|
66
|
+
case options[:bearing] || Geocoder.config.distances
|
|
65
67
|
when :linear
|
|
66
68
|
"CAST(" +
|
|
67
69
|
"DEGREES(ATAN2( " +
|