geocoder 1.6.1 → 1.6.2
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.
- 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
|