geocoder 1.6.1 → 1.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/bin/console +7 -0
- data/lib/easting_northing.rb +171 -0
- data/lib/geocoder/lookup.rb +2 -0
- data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
- data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
- data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
- data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
- data/lib/geocoder/results/yandex.rb +217 -59
- data/lib/geocoder/version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90c4756998f02d1ff8f3f8ca4323d47e3d726547f8ce42c79fc21beeecd88b90
|
4
|
+
data.tar.gz: f2dc1c26391cd757001f2e973f4136e97c52da6f2153e9f3db29cae336555bdd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43144700ad9a0a7fcec1dd0f363348b049984bda7fbefd57285c86a03ae7a16afc1302fd9dea656bc7b65142248d6cec06446f98dee80f9b5577b7ba4ee1b175
|
7
|
+
data.tar.gz: d4fcd8d3a6ed87234cdb9f411d7f58fd92d126f7ff23fef0c53e470ed78a76003f095a7b291c33748dd3e8282b2f237cf5c73e155863bb1d34b7e5f148e32677
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,12 @@ Changelog
|
|
3
3
|
|
4
4
|
Major changes to Geocoder for each release. Please see the Git log for complete list of changes.
|
5
5
|
|
6
|
+
1.6.2 (2020 Mar 16)
|
7
|
+
-------------------
|
8
|
+
* Add support for :nationaal_georegister_nl lookup (thanks github.com/opensourceame).
|
9
|
+
* Add support for :uk_ordnance_survey_names lookup (thanks github.com/pezholio).
|
10
|
+
* Refactor and fix bugs in Yandex lookup (thanks github.com/iarie and stereodenis).
|
11
|
+
|
6
12
|
1.6.1 (2020 Jan 23)
|
7
13
|
-------------------
|
8
14
|
* Sanitize lat/lon values passed to within_bounding_box to prevent SQL injection.
|
data/bin/console
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
module Geocoder
|
2
|
+
class EastingNorthing
|
3
|
+
attr_reader :easting, :northing, :lat_lng
|
4
|
+
|
5
|
+
def initialize(opts)
|
6
|
+
@easting = opts[:easting]
|
7
|
+
@northing = opts[:northing]
|
8
|
+
|
9
|
+
@lat_lng = to_WGS84(to_osgb_36)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def to_osgb_36
|
15
|
+
osgb_fo = 0.9996012717
|
16
|
+
northing0 = -100_000.0
|
17
|
+
easting0 = 400_000.0
|
18
|
+
phi0 = deg_to_rad(49.0)
|
19
|
+
lambda0 = deg_to_rad(-2.0)
|
20
|
+
a = 6_377_563.396
|
21
|
+
b = 6_356_256.909
|
22
|
+
eSquared = ((a * a) - (b * b)) / (a * a)
|
23
|
+
phi = 0.0
|
24
|
+
lambda = 0.0
|
25
|
+
n = (a - b) / (a + b)
|
26
|
+
m = 0.0
|
27
|
+
phiPrime = ((northing - northing0) / (a * osgb_fo)) + phi0
|
28
|
+
|
29
|
+
while (northing - northing0 - m) >= 0.001
|
30
|
+
m =
|
31
|
+
(b * osgb_fo)\
|
32
|
+
* (((1 + n + ((5.0 / 4.0) * n * n) + ((5.0 / 4.0) * n * n * n))\
|
33
|
+
* (phiPrime - phi0))\
|
34
|
+
- (((3 * n) + (3 * n * n) + ((21.0 / 8.0) * n * n * n))\
|
35
|
+
* Math.sin(phiPrime - phi0)\
|
36
|
+
* Math.cos(phiPrime + phi0))\
|
37
|
+
+ ((((15.0 / 8.0) * n * n) + ((15.0 / 8.0) * n * n * n))\
|
38
|
+
* Math.sin(2.0 * (phiPrime - phi0))\
|
39
|
+
* Math.cos(2.0 * (phiPrime + phi0)))\
|
40
|
+
- (((35.0 / 24.0) * n * n * n)\
|
41
|
+
* Math.sin(3.0 * (phiPrime - phi0))\
|
42
|
+
* Math.cos(3.0 * (phiPrime + phi0))))
|
43
|
+
|
44
|
+
phiPrime += (northing - northing0 - m) / (a * osgb_fo)
|
45
|
+
end
|
46
|
+
|
47
|
+
v = a * osgb_fo * ((1.0 - eSquared * sin_pow_2(phiPrime))**-0.5)
|
48
|
+
rho =
|
49
|
+
a\
|
50
|
+
* osgb_fo\
|
51
|
+
* (1.0 - eSquared)\
|
52
|
+
* ((1.0 - eSquared * sin_pow_2(phiPrime))**-1.5)
|
53
|
+
etaSquared = (v / rho) - 1.0
|
54
|
+
vii = Math.tan(phiPrime) / (2 * rho * v)
|
55
|
+
viii =
|
56
|
+
(Math.tan(phiPrime) / (24.0 * rho * (v**3.0)))\
|
57
|
+
* (5.0\
|
58
|
+
+ (3.0 * tan_pow_2(phiPrime))\
|
59
|
+
+ etaSquared\
|
60
|
+
- (9.0 * tan_pow_2(phiPrime) * etaSquared))
|
61
|
+
ix =
|
62
|
+
(Math.tan(phiPrime) / (720.0 * rho * (v**5.0)))\
|
63
|
+
* (61.0\
|
64
|
+
+ (90.0 * tan_pow_2(phiPrime))\
|
65
|
+
+ (45.0 * tan_pow_2(phiPrime) * tan_pow_2(phiPrime)))
|
66
|
+
x = sec(phiPrime) / v
|
67
|
+
xi =
|
68
|
+
(sec(phiPrime) / (6.0 * v * v * v))\
|
69
|
+
* ((v / rho) + (2 * tan_pow_2(phiPrime)))
|
70
|
+
xiii =
|
71
|
+
(sec(phiPrime) / (120.0 * (v**5.0)))\
|
72
|
+
* (5.0\
|
73
|
+
+ (28.0 * tan_pow_2(phiPrime))\
|
74
|
+
+ (24.0 * tan_pow_2(phiPrime) * tan_pow_2(phiPrime)))
|
75
|
+
xiia =
|
76
|
+
(sec(phiPrime) / (5040.0 * (v**7.0)))\
|
77
|
+
* (61.0\
|
78
|
+
+ (662.0 * tan_pow_2(phiPrime))\
|
79
|
+
+ (1320.0 * tan_pow_2(phiPrime) * tan_pow_2(phiPrime))\
|
80
|
+
+ (720.0\
|
81
|
+
* tan_pow_2(phiPrime)\
|
82
|
+
* tan_pow_2(phiPrime)\
|
83
|
+
* tan_pow_2(phiPrime)))
|
84
|
+
phi =
|
85
|
+
phiPrime\
|
86
|
+
- (vii * ((easting - easting0)**2.0))\
|
87
|
+
+ (viii * ((easting - easting0)**4.0))\
|
88
|
+
- (ix * ((easting - easting0)**6.0))
|
89
|
+
lambda =
|
90
|
+
lambda0\
|
91
|
+
+ (x * (easting - easting0))\
|
92
|
+
- (xi * ((easting - easting0)**3.0))\
|
93
|
+
+ (xiii * ((easting - easting0)**5.0))\
|
94
|
+
- (xiia * ((easting - easting0)**7.0))
|
95
|
+
|
96
|
+
[rad_to_deg(phi), rad_to_deg(lambda)]
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_WGS84(latlng)
|
100
|
+
latitude = latlng[0]
|
101
|
+
longitude = latlng[1]
|
102
|
+
|
103
|
+
a = 6_377_563.396
|
104
|
+
b = 6_356_256.909
|
105
|
+
eSquared = ((a * a) - (b * b)) / (a * a)
|
106
|
+
|
107
|
+
phi = deg_to_rad(latitude)
|
108
|
+
lambda = deg_to_rad(longitude)
|
109
|
+
v = a / Math.sqrt(1 - eSquared * sin_pow_2(phi))
|
110
|
+
h = 0
|
111
|
+
x = (v + h) * Math.cos(phi) * Math.cos(lambda)
|
112
|
+
y = (v + h) * Math.cos(phi) * Math.sin(lambda)
|
113
|
+
z = ((1 - eSquared) * v + h) * Math.sin(phi)
|
114
|
+
|
115
|
+
tx = 446.448
|
116
|
+
ty = -124.157
|
117
|
+
tz = 542.060
|
118
|
+
|
119
|
+
s = -0.0000204894
|
120
|
+
rx = deg_to_rad(0.00004172222)
|
121
|
+
ry = deg_to_rad(0.00006861111)
|
122
|
+
rz = deg_to_rad(0.00023391666)
|
123
|
+
|
124
|
+
xB = tx + (x * (1 + s)) + (-rx * y) + (ry * z)
|
125
|
+
yB = ty + (rz * x) + (y * (1 + s)) + (-rx * z)
|
126
|
+
zB = tz + (-ry * x) + (rx * y) + (z * (1 + s))
|
127
|
+
|
128
|
+
a = 6_378_137.000
|
129
|
+
b = 6_356_752.3141
|
130
|
+
eSquared = ((a * a) - (b * b)) / (a * a)
|
131
|
+
|
132
|
+
lambdaB = rad_to_deg(Math.atan(yB / xB))
|
133
|
+
p = Math.sqrt((xB * xB) + (yB * yB))
|
134
|
+
phiN = Math.atan(zB / (p * (1 - eSquared)))
|
135
|
+
|
136
|
+
(1..10).each do |_i|
|
137
|
+
v = a / Math.sqrt(1 - eSquared * sin_pow_2(phiN))
|
138
|
+
phiN1 = Math.atan((zB + (eSquared * v * Math.sin(phiN))) / p)
|
139
|
+
phiN = phiN1
|
140
|
+
end
|
141
|
+
|
142
|
+
phiB = rad_to_deg(phiN)
|
143
|
+
|
144
|
+
[phiB, lambdaB]
|
145
|
+
end
|
146
|
+
|
147
|
+
def deg_to_rad(degrees)
|
148
|
+
degrees / 180.0 * Math::PI
|
149
|
+
end
|
150
|
+
|
151
|
+
def rad_to_deg(r)
|
152
|
+
(r / Math::PI) * 180
|
153
|
+
end
|
154
|
+
|
155
|
+
def sin_pow_2(x)
|
156
|
+
Math.sin(x) * Math.sin(x)
|
157
|
+
end
|
158
|
+
|
159
|
+
def cos_pow_2(x)
|
160
|
+
Math.cos(x) * Math.cos(x)
|
161
|
+
end
|
162
|
+
|
163
|
+
def tan_pow_2(x)
|
164
|
+
Math.tan(x) * Math.tan(x)
|
165
|
+
end
|
166
|
+
|
167
|
+
def sec(x)
|
168
|
+
1.0 / Math.cos(x)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
data/lib/geocoder/lookup.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require "geocoder/results/nationaal_georegister_nl"
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class NationaalGeoregisterNl < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
'Nationaal Georegister Nederland'
|
9
|
+
end
|
10
|
+
|
11
|
+
private # ---------------------------------------------------------------
|
12
|
+
|
13
|
+
def cache_key(query)
|
14
|
+
base_query_url(query) + hash_to_query(query_url_params(query))
|
15
|
+
end
|
16
|
+
|
17
|
+
def base_query_url(query)
|
18
|
+
"#{protocol}://geodata.nationaalgeoregister.nl/locatieserver/v3/free?"
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid_response?(response)
|
22
|
+
json = parse_json(response.body)
|
23
|
+
super(response) if json
|
24
|
+
end
|
25
|
+
|
26
|
+
def results(query)
|
27
|
+
return [] unless doc = fetch_data(query)
|
28
|
+
return doc['response']['docs']
|
29
|
+
end
|
30
|
+
|
31
|
+
def query_url_params(query)
|
32
|
+
{
|
33
|
+
fl: '*',
|
34
|
+
q: query.text
|
35
|
+
}.merge(super)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/uk_ordnance_survey_names'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class UkOrdnanceSurveyNames < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
'Ordance Survey Names'
|
9
|
+
end
|
10
|
+
|
11
|
+
def supported_protocols
|
12
|
+
[:https]
|
13
|
+
end
|
14
|
+
|
15
|
+
def base_query_url(query)
|
16
|
+
"#{protocol}://api.ordnancesurvey.co.uk/opennames/v1/find?"
|
17
|
+
end
|
18
|
+
|
19
|
+
def required_api_key_parts
|
20
|
+
["key"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def query_url(query)
|
24
|
+
base_query_url(query) + url_query_string(query)
|
25
|
+
end
|
26
|
+
|
27
|
+
private # -------------------------------------------------------------
|
28
|
+
|
29
|
+
def results(query)
|
30
|
+
return [] unless doc = fetch_data(query)
|
31
|
+
return [] if doc['header']['totalresults'].zero?
|
32
|
+
return doc['results'].map { |r| r['GAZETTEER_ENTRY'] }
|
33
|
+
end
|
34
|
+
|
35
|
+
def query_url_params(query)
|
36
|
+
{
|
37
|
+
query: query.sanitized_text,
|
38
|
+
key: configuration.api_key,
|
39
|
+
fq: filter
|
40
|
+
}.merge(super)
|
41
|
+
end
|
42
|
+
|
43
|
+
def local_types
|
44
|
+
%w[
|
45
|
+
City
|
46
|
+
Hamlet
|
47
|
+
Other_Settlement
|
48
|
+
Town
|
49
|
+
Village
|
50
|
+
Postcode
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
def filter
|
55
|
+
local_types.map { |t| "local_type:#{t}" }.join(' ')
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder::Result
|
4
|
+
class NationaalGeoregisterNl < Base
|
5
|
+
|
6
|
+
def response_attributes
|
7
|
+
@data
|
8
|
+
end
|
9
|
+
|
10
|
+
def coordinates
|
11
|
+
@data['centroide_ll'][6..-2].split(' ').map(&:to_f)
|
12
|
+
end
|
13
|
+
|
14
|
+
def formatted_address
|
15
|
+
@data['weergavenaam']
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :address, :formatted_address
|
19
|
+
|
20
|
+
def province
|
21
|
+
@data['provincienaam']
|
22
|
+
end
|
23
|
+
|
24
|
+
alias_method :state, :province
|
25
|
+
|
26
|
+
def city
|
27
|
+
@data['woonplaatsnaam']
|
28
|
+
end
|
29
|
+
|
30
|
+
def district
|
31
|
+
@data['gemeentenaam']
|
32
|
+
end
|
33
|
+
|
34
|
+
def street
|
35
|
+
@data['straatnaam']
|
36
|
+
end
|
37
|
+
|
38
|
+
def street_number
|
39
|
+
@data['huis_nlt']
|
40
|
+
end
|
41
|
+
|
42
|
+
def address_components
|
43
|
+
@data
|
44
|
+
end
|
45
|
+
|
46
|
+
def state_code
|
47
|
+
@data['provinciecode']
|
48
|
+
end
|
49
|
+
|
50
|
+
def postal_code
|
51
|
+
@data['postcode']
|
52
|
+
end
|
53
|
+
|
54
|
+
def country
|
55
|
+
"Netherlands"
|
56
|
+
end
|
57
|
+
|
58
|
+
def country_code
|
59
|
+
"NL"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
require 'easting_northing'
|
3
|
+
|
4
|
+
module Geocoder::Result
|
5
|
+
class UkOrdnanceSurveyNames < Base
|
6
|
+
|
7
|
+
def coordinates
|
8
|
+
@coordinates ||= Geocoder::EastingNorthing.new(
|
9
|
+
easting: data['GEOMETRY_X'],
|
10
|
+
northing: data['GEOMETRY_Y'],
|
11
|
+
).lat_lng
|
12
|
+
end
|
13
|
+
|
14
|
+
def city
|
15
|
+
is_postcode? ? data['DISTRICT_BOROUGH'] : data['NAME1']
|
16
|
+
end
|
17
|
+
|
18
|
+
def county
|
19
|
+
data['COUNTY_UNITARY']
|
20
|
+
end
|
21
|
+
alias state county
|
22
|
+
|
23
|
+
def county_code
|
24
|
+
code_from_uri data['COUNTY_UNITARY_URI']
|
25
|
+
end
|
26
|
+
alias state_code county_code
|
27
|
+
|
28
|
+
def province
|
29
|
+
data['REGION']
|
30
|
+
end
|
31
|
+
|
32
|
+
def province_code
|
33
|
+
code_from_uri data['REGION_URI']
|
34
|
+
end
|
35
|
+
|
36
|
+
def postal_code
|
37
|
+
is_postcode? ? data['NAME1'] : ''
|
38
|
+
end
|
39
|
+
|
40
|
+
def country
|
41
|
+
'United Kingdom'
|
42
|
+
end
|
43
|
+
|
44
|
+
def country_code
|
45
|
+
'UK'
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def is_postcode?
|
51
|
+
data['LOCAL_TYPE'] == 'Postcode'
|
52
|
+
end
|
53
|
+
|
54
|
+
def code_from_uri(uri)
|
55
|
+
return '' if uri.nil?
|
56
|
+
uri.split('/').last
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -2,78 +2,223 @@ require 'geocoder/results/base'
|
|
2
2
|
|
3
3
|
module Geocoder::Result
|
4
4
|
class Yandex < Base
|
5
|
+
# Yandex result has difficult tree structure,
|
6
|
+
# and presence of some nodes depends on exact search case.
|
7
|
+
|
8
|
+
# Also Yandex lacks documentation about it.
|
9
|
+
# See https://tech.yandex.com/maps/doc/geocoder/desc/concepts/response_structure-docpage/
|
10
|
+
|
11
|
+
# Ultimatly, we need to find Locality and/or Thoroughfare data.
|
12
|
+
|
13
|
+
# It may resides on the top (ADDRESS_DETAILS) level.
|
14
|
+
# example: 'Baltic Sea'
|
15
|
+
# "AddressDetails": {
|
16
|
+
# "Locality": {
|
17
|
+
# "Premise": {
|
18
|
+
# "PremiseName": "Baltic Sea"
|
19
|
+
# }
|
20
|
+
# }
|
21
|
+
# }
|
22
|
+
|
23
|
+
ADDRESS_DETAILS = %w[
|
24
|
+
GeoObject metaDataProperty GeocoderMetaData
|
25
|
+
AddressDetails
|
26
|
+
].freeze
|
27
|
+
|
28
|
+
# On COUNTRY_LEVEL.
|
29
|
+
# example: 'Potomak'
|
30
|
+
# "AddressDetails": {
|
31
|
+
# "Country": {
|
32
|
+
# "AddressLine": "reka Potomak",
|
33
|
+
# "CountryNameCode": "US",
|
34
|
+
# "CountryName": "United States of America",
|
35
|
+
# "Locality": {
|
36
|
+
# "Premise": {
|
37
|
+
# "PremiseName": "reka Potomak"
|
38
|
+
# }
|
39
|
+
# }
|
40
|
+
# }
|
41
|
+
# }
|
42
|
+
|
43
|
+
COUNTRY_LEVEL = %w[
|
44
|
+
GeoObject metaDataProperty GeocoderMetaData
|
45
|
+
AddressDetails Country
|
46
|
+
].freeze
|
47
|
+
|
48
|
+
# On ADMIN_LEVEL (usually state or city)
|
49
|
+
# example: 'Moscow, Tverskaya'
|
50
|
+
# "AddressDetails": {
|
51
|
+
# "Country": {
|
52
|
+
# "AddressLine": "Moscow, Tverskaya Street",
|
53
|
+
# "CountryNameCode": "RU",
|
54
|
+
# "CountryName": "Russia",
|
55
|
+
# "AdministrativeArea": {
|
56
|
+
# "AdministrativeAreaName": "Moscow",
|
57
|
+
# "Locality": {
|
58
|
+
# "LocalityName": "Moscow",
|
59
|
+
# "Thoroughfare": {
|
60
|
+
# "ThoroughfareName": "Tverskaya Street"
|
61
|
+
# }
|
62
|
+
# }
|
63
|
+
# }
|
64
|
+
# }
|
65
|
+
# }
|
66
|
+
|
67
|
+
ADMIN_LEVEL = %w[
|
68
|
+
GeoObject metaDataProperty GeocoderMetaData
|
69
|
+
AddressDetails Country
|
70
|
+
AdministrativeArea
|
71
|
+
].freeze
|
72
|
+
|
73
|
+
# On SUBADMIN_LEVEL (may refer to urban district)
|
74
|
+
# example: 'Moscow Region, Krasnogorsk'
|
75
|
+
# "AddressDetails": {
|
76
|
+
# "Country": {
|
77
|
+
# "AddressLine": "Moscow Region, Krasnogorsk",
|
78
|
+
# "CountryNameCode": "RU",
|
79
|
+
# "CountryName": "Russia",
|
80
|
+
# "AdministrativeArea": {
|
81
|
+
# "AdministrativeAreaName": "Moscow Region",
|
82
|
+
# "SubAdministrativeArea": {
|
83
|
+
# "SubAdministrativeAreaName": "gorodskoy okrug Krasnogorsk",
|
84
|
+
# "Locality": {
|
85
|
+
# "LocalityName": "Krasnogorsk"
|
86
|
+
# }
|
87
|
+
# }
|
88
|
+
# }
|
89
|
+
# }
|
90
|
+
# }
|
91
|
+
|
92
|
+
SUBADMIN_LEVEL = %w[
|
93
|
+
GeoObject metaDataProperty GeocoderMetaData
|
94
|
+
AddressDetails Country
|
95
|
+
AdministrativeArea
|
96
|
+
SubAdministrativeArea
|
97
|
+
].freeze
|
98
|
+
|
99
|
+
# On DEPENDENT_LOCALITY_1 (may refer to district of city)
|
100
|
+
# example: 'Paris, Etienne Marcel'
|
101
|
+
# "AddressDetails": {
|
102
|
+
# "Country": {
|
103
|
+
# "AddressLine": "Île-de-France, Paris, 1er Arrondissement, Rue Étienne Marcel",
|
104
|
+
# "CountryNameCode": "FR",
|
105
|
+
# "CountryName": "France",
|
106
|
+
# "AdministrativeArea": {
|
107
|
+
# "AdministrativeAreaName": "Île-de-France",
|
108
|
+
# "Locality": {
|
109
|
+
# "LocalityName": "Paris",
|
110
|
+
# "DependentLocality": {
|
111
|
+
# "DependentLocalityName": "1er Arrondissement",
|
112
|
+
# "Thoroughfare": {
|
113
|
+
# "ThoroughfareName": "Rue Étienne Marcel"
|
114
|
+
# }
|
115
|
+
# }
|
116
|
+
# }
|
117
|
+
# }
|
118
|
+
# }
|
119
|
+
# }
|
120
|
+
|
121
|
+
DEPENDENT_LOCALITY_1 = %w[
|
122
|
+
GeoObject metaDataProperty GeocoderMetaData
|
123
|
+
AddressDetails Country
|
124
|
+
AdministrativeArea Locality
|
125
|
+
DependentLocality
|
126
|
+
].freeze
|
127
|
+
|
128
|
+
# On DEPENDENT_LOCALITY_2 (for special cases like turkish "mahalle")
|
129
|
+
# https://en.wikipedia.org/wiki/Mahalle
|
130
|
+
# example: 'Istanbul Mabeyinci Yokuşu 17'
|
131
|
+
|
132
|
+
# "AddressDetails": {
|
133
|
+
# "Country": {
|
134
|
+
# "AddressLine": "İstanbul, Fatih, Saraç İshak Mah., Mabeyinci Yokuşu, 17",
|
135
|
+
# "CountryNameCode": "TR",
|
136
|
+
# "CountryName": "Turkey",
|
137
|
+
# "AdministrativeArea": {
|
138
|
+
# "AdministrativeAreaName": "İstanbul",
|
139
|
+
# "SubAdministrativeArea": {
|
140
|
+
# "SubAdministrativeAreaName": "Fatih",
|
141
|
+
# "Locality": {
|
142
|
+
# "DependentLocality": {
|
143
|
+
# "DependentLocalityName": "Saraç İshak Mah.",
|
144
|
+
# "Thoroughfare": {
|
145
|
+
# "ThoroughfareName": "Mabeyinci Yokuşu",
|
146
|
+
# "Premise": {
|
147
|
+
# "PremiseNumber": "17"
|
148
|
+
# }
|
149
|
+
# }
|
150
|
+
# }
|
151
|
+
# }
|
152
|
+
# }
|
153
|
+
# }
|
154
|
+
# }
|
155
|
+
# }
|
156
|
+
|
157
|
+
DEPENDENT_LOCALITY_2 = %w[
|
158
|
+
GeoObject metaDataProperty GeocoderMetaData
|
159
|
+
AddressDetails Country
|
160
|
+
AdministrativeArea
|
161
|
+
SubAdministrativeArea Locality
|
162
|
+
DependentLocality
|
163
|
+
].freeze
|
5
164
|
|
6
165
|
def coordinates
|
7
166
|
@data['GeoObject']['Point']['pos'].split(' ').reverse.map(&:to_f)
|
8
167
|
end
|
9
168
|
|
10
|
-
def address(
|
169
|
+
def address(_format = :full)
|
11
170
|
@data['GeoObject']['metaDataProperty']['GeocoderMetaData']['text']
|
12
171
|
end
|
13
172
|
|
14
173
|
def city
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
174
|
+
result =
|
175
|
+
if state.empty?
|
176
|
+
find_in_hash(@data, *COUNTRY_LEVEL, 'Locality', 'LocalityName')
|
177
|
+
elsif sub_state.empty?
|
178
|
+
find_in_hash(@data, *ADMIN_LEVEL, 'Locality', 'LocalityName')
|
179
|
+
else
|
180
|
+
find_in_hash(@data, *SUBADMIN_LEVEL, 'Locality', 'LocalityName')
|
181
|
+
end
|
182
|
+
|
183
|
+
result || ""
|
25
184
|
end
|
26
185
|
|
27
186
|
def country
|
28
|
-
|
29
|
-
address_details['CountryName']
|
30
|
-
else
|
31
|
-
""
|
32
|
-
end
|
187
|
+
find_in_hash(@data, *COUNTRY_LEVEL, 'CountryName') || ""
|
33
188
|
end
|
34
189
|
|
35
190
|
def country_code
|
36
|
-
|
37
|
-
address_details['CountryNameCode']
|
38
|
-
else
|
39
|
-
""
|
40
|
-
end
|
191
|
+
find_in_hash(@data, *COUNTRY_LEVEL, 'CountryNameCode') || ""
|
41
192
|
end
|
42
193
|
|
43
194
|
def state
|
44
|
-
|
45
|
-
address_details['AdministrativeArea']['AdministrativeAreaName']
|
46
|
-
else
|
47
|
-
""
|
48
|
-
end
|
195
|
+
find_in_hash(@data, *ADMIN_LEVEL, 'AdministrativeAreaName') || ""
|
49
196
|
end
|
50
197
|
|
51
198
|
def sub_state
|
52
|
-
if
|
53
|
-
|
54
|
-
else
|
55
|
-
""
|
56
|
-
end
|
199
|
+
return "" if state.empty?
|
200
|
+
find_in_hash(@data, *SUBADMIN_LEVEL, 'SubAdministrativeAreaName') || ""
|
57
201
|
end
|
58
202
|
|
59
203
|
def state_code
|
60
204
|
""
|
61
205
|
end
|
62
206
|
|
63
|
-
def
|
64
|
-
""
|
207
|
+
def street
|
208
|
+
thoroughfare_data.is_a?(Hash) ? thoroughfare_data['ThoroughfareName'] : ""
|
65
209
|
end
|
66
210
|
|
67
|
-
def
|
68
|
-
|
211
|
+
def street_number
|
212
|
+
premise.is_a?(Hash) ? premise.fetch('PremiseNumber', "") : ""
|
69
213
|
end
|
70
214
|
|
71
|
-
def
|
72
|
-
|
215
|
+
def premise_name
|
216
|
+
premise.is_a?(Hash) ? premise.fetch('PremiseName', "") : ""
|
73
217
|
end
|
74
218
|
|
75
|
-
def
|
76
|
-
|
219
|
+
def postal_code
|
220
|
+
return "" unless premise.is_a?(Hash)
|
221
|
+
find_in_hash(premise, 'PostalCode', 'PostalCodeNumber') || ""
|
77
222
|
end
|
78
223
|
|
79
224
|
def kind
|
@@ -93,42 +238,55 @@ module Geocoder::Result
|
|
93
238
|
|
94
239
|
private # ----------------------------------------------------------------
|
95
240
|
|
96
|
-
def
|
97
|
-
|
241
|
+
def top_level_locality
|
242
|
+
find_in_hash(@data, *ADDRESS_DETAILS, 'Locality')
|
98
243
|
end
|
99
244
|
|
100
|
-
def
|
101
|
-
|
245
|
+
def country_level_locality
|
246
|
+
find_in_hash(@data, *COUNTRY_LEVEL, 'Locality')
|
102
247
|
end
|
103
248
|
|
104
249
|
def admin_locality
|
105
|
-
|
106
|
-
address_details['AdministrativeArea']['Locality']
|
250
|
+
find_in_hash(@data, *ADMIN_LEVEL, 'Locality')
|
107
251
|
end
|
108
252
|
|
109
253
|
def subadmin_locality
|
110
|
-
|
111
|
-
address_details['AdministrativeArea']['SubAdministrativeArea'] &&
|
112
|
-
address_details['AdministrativeArea']['SubAdministrativeArea']['Locality']
|
254
|
+
find_in_hash(@data, *SUBADMIN_LEVEL, 'Locality')
|
113
255
|
end
|
114
256
|
|
115
257
|
def dependent_locality
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
258
|
+
find_in_hash(@data, *DEPENDENT_LOCALITY_1) ||
|
259
|
+
find_in_hash(@data, *DEPENDENT_LOCALITY_2)
|
260
|
+
end
|
261
|
+
|
262
|
+
def locality_data
|
263
|
+
dependent_locality || subadmin_locality || admin_locality ||
|
264
|
+
country_level_locality || top_level_locality
|
265
|
+
end
|
266
|
+
|
267
|
+
def thoroughfare_data
|
268
|
+
locality_data['Thoroughfare'] if locality_data.is_a?(Hash)
|
120
269
|
end
|
121
270
|
|
122
|
-
def
|
123
|
-
|
271
|
+
def premise
|
272
|
+
if thoroughfare_data.is_a?(Hash)
|
273
|
+
thoroughfare_data['Premise']
|
274
|
+
elsif locality_data.is_a?(Hash)
|
275
|
+
locality_data['Premise']
|
276
|
+
end
|
124
277
|
end
|
125
278
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
279
|
+
def find_in_hash(source, *keys)
|
280
|
+
key = keys.shift
|
281
|
+
result = source[key]
|
282
|
+
|
283
|
+
if keys.empty?
|
284
|
+
return result
|
285
|
+
elsif !result.is_a?(Hash)
|
286
|
+
return nil
|
131
287
|
end
|
288
|
+
|
289
|
+
find_in_hash(result, *keys)
|
132
290
|
end
|
133
291
|
end
|
134
292
|
end
|
data/lib/geocoder/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geocoder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.6.
|
4
|
+
version: 1.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Reisner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Provides object geocoding (by street or IP address), reverse geocoding
|
14
14
|
(coordinates to street address), distance queries for ActiveRecord and Mongoid,
|
@@ -24,11 +24,13 @@ files:
|
|
24
24
|
- CHANGELOG.md
|
25
25
|
- LICENSE
|
26
26
|
- README.md
|
27
|
+
- bin/console
|
27
28
|
- bin/geocode
|
28
29
|
- examples/autoexpire_cache_dalli.rb
|
29
30
|
- examples/autoexpire_cache_redis.rb
|
30
31
|
- examples/cache_bypass.rb
|
31
32
|
- examples/reverse_geocode_job.rb
|
33
|
+
- lib/easting_northing.rb
|
32
34
|
- lib/generators/geocoder/config/config_generator.rb
|
33
35
|
- lib/generators/geocoder/config/templates/initializer.rb
|
34
36
|
- lib/generators/geocoder/maxmind/geolite_city_generator.rb
|
@@ -81,6 +83,7 @@ files:
|
|
81
83
|
- lib/geocoder/lookups/maxmind.rb
|
82
84
|
- lib/geocoder/lookups/maxmind_geoip2.rb
|
83
85
|
- lib/geocoder/lookups/maxmind_local.rb
|
86
|
+
- lib/geocoder/lookups/nationaal_georegister_nl.rb
|
84
87
|
- lib/geocoder/lookups/nominatim.rb
|
85
88
|
- lib/geocoder/lookups/opencagedata.rb
|
86
89
|
- lib/geocoder/lookups/osmnames.rb
|
@@ -93,6 +96,7 @@ files:
|
|
93
96
|
- lib/geocoder/lookups/telize.rb
|
94
97
|
- lib/geocoder/lookups/tencent.rb
|
95
98
|
- lib/geocoder/lookups/test.rb
|
99
|
+
- lib/geocoder/lookups/uk_ordnance_survey_names.rb
|
96
100
|
- lib/geocoder/lookups/yandex.rb
|
97
101
|
- lib/geocoder/models/active_record.rb
|
98
102
|
- lib/geocoder/models/base.rb
|
@@ -135,6 +139,7 @@ files:
|
|
135
139
|
- lib/geocoder/results/maxmind.rb
|
136
140
|
- lib/geocoder/results/maxmind_geoip2.rb
|
137
141
|
- lib/geocoder/results/maxmind_local.rb
|
142
|
+
- lib/geocoder/results/nationaal_georegister_nl.rb
|
138
143
|
- lib/geocoder/results/nominatim.rb
|
139
144
|
- lib/geocoder/results/opencagedata.rb
|
140
145
|
- lib/geocoder/results/osmnames.rb
|
@@ -147,6 +152,7 @@ files:
|
|
147
152
|
- lib/geocoder/results/telize.rb
|
148
153
|
- lib/geocoder/results/tencent.rb
|
149
154
|
- lib/geocoder/results/test.rb
|
155
|
+
- lib/geocoder/results/uk_ordnance_survey_names.rb
|
150
156
|
- lib/geocoder/results/yandex.rb
|
151
157
|
- lib/geocoder/sql.rb
|
152
158
|
- lib/geocoder/stores/active_record.rb
|