geocoder 1.5.2 → 1.6.4

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/LICENSE +1 -1
  4. data/README.md +8 -10
  5. data/bin/console +13 -0
  6. data/examples/autoexpire_cache_redis.rb +2 -0
  7. data/lib/easting_northing.rb +171 -0
  8. data/lib/geocoder/configuration.rb +2 -1
  9. data/lib/geocoder/configuration_hash.rb +4 -4
  10. data/lib/geocoder/ip_address.rb +2 -1
  11. data/lib/geocoder/lookup.rb +6 -3
  12. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +14 -1
  13. data/lib/geocoder/lookups/esri.rb +6 -0
  14. data/lib/geocoder/lookups/geocodio.rb +1 -1
  15. data/lib/geocoder/lookups/google.rb +7 -2
  16. data/lib/geocoder/lookups/google_places_details.rb +8 -14
  17. data/lib/geocoder/lookups/google_places_search.rb +28 -2
  18. data/lib/geocoder/lookups/google_premier.rb +4 -0
  19. data/lib/geocoder/lookups/here.rb +7 -16
  20. data/lib/geocoder/lookups/ip2location.rb +5 -13
  21. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  22. data/lib/geocoder/lookups/latlon.rb +1 -2
  23. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  24. data/lib/geocoder/lookups/osmnames.rb +57 -0
  25. data/lib/geocoder/lookups/pickpoint.rb +1 -1
  26. data/lib/geocoder/lookups/smarty_streets.rb +6 -1
  27. data/lib/geocoder/lookups/telize.rb +1 -1
  28. data/lib/geocoder/lookups/tencent.rb +9 -9
  29. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  30. data/lib/geocoder/lookups/yandex.rb +1 -2
  31. data/lib/geocoder/results/baidu.rb +0 -4
  32. data/lib/geocoder/results/ban_data_gouv_fr.rb +1 -1
  33. data/lib/geocoder/results/db_ip_com.rb +1 -1
  34. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  35. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  36. data/lib/geocoder/results/nominatim.rb +4 -0
  37. data/lib/geocoder/results/osmnames.rb +56 -0
  38. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  39. data/lib/geocoder/results/yandex.rb +217 -59
  40. data/lib/geocoder/sql.rb +4 -4
  41. data/lib/geocoder/util.rb +29 -0
  42. data/lib/geocoder/version.rb +1 -1
  43. data/lib/maxmind_database.rb +3 -3
  44. metadata +17 -11
  45. data/lib/geocoder/lookups/geocoder_us.rb +0 -51
  46. data/lib/geocoder/results/geocoder_us.rb +0 -39
  47. data/lib/hash_recursive_merge.rb +0 -74
@@ -22,21 +22,15 @@ module Geocoder
22
22
  "#{protocol}://maps.googleapis.com/maps/api/place/details/json?"
23
23
  end
24
24
 
25
+ def result_root_attr
26
+ 'result'
27
+ end
28
+
25
29
  def results(query)
26
- return [] unless doc = fetch_data(query)
27
-
28
- case doc["status"]
29
- when "OK"
30
- return [doc["result"]]
31
- when "OVER_QUERY_LIMIT"
32
- raise_error(Geocoder::OverQueryLimitError) || Geocoder.log(:warn, "Google Places Details API error: over query limit.")
33
- when "REQUEST_DENIED"
34
- raise_error(Geocoder::RequestDenied) || Geocoder.log(:warn, "Google Places Details API error: request denied.")
35
- when "INVALID_REQUEST"
36
- raise_error(Geocoder::InvalidRequest) || Geocoder.log(:warn, "Google Places Details API error: invalid request.")
37
- end
38
-
39
- []
30
+ result = super(query)
31
+ return [result] unless result.is_a? Array
32
+
33
+ result
40
34
  end
41
35
 
42
36
  def query_url_google_params(query)
@@ -18,16 +18,42 @@ module Geocoder
18
18
 
19
19
  private
20
20
 
21
+ def result_root_attr
22
+ 'candidates'
23
+ end
24
+
21
25
  def base_query_url(query)
22
- "#{protocol}://maps.googleapis.com/maps/api/place/textsearch/json?"
26
+ "#{protocol}://maps.googleapis.com/maps/api/place/findplacefromtext/json?"
23
27
  end
24
28
 
25
29
  def query_url_google_params(query)
26
30
  {
27
- query: query.text,
31
+ input: query.text,
32
+ inputtype: 'textquery',
33
+ fields: fields(query),
28
34
  language: query.language || configuration.language
29
35
  }
30
36
  end
37
+
38
+ def fields(query)
39
+ query_fields = query.options[:fields]
40
+ return format_fields(query_fields) if query_fields
41
+
42
+ default_fields
43
+ end
44
+
45
+ def default_fields
46
+ legacy = %w[id reference]
47
+ basic = %w[business_status formatted_address geometry icon name
48
+ photos place_id plus_code types]
49
+ contact = %w[opening_hours]
50
+ atmosphere = %W[price_level rating user_ratings_total]
51
+ format_fields(legacy, basic, contact, atmosphere)
52
+ end
53
+
54
+ def format_fields(*fields)
55
+ fields.flatten.join(',')
56
+ end
31
57
  end
32
58
  end
33
59
  end
@@ -21,6 +21,10 @@ module Geocoder::Lookup
21
21
 
22
22
  private # ---------------------------------------------------------------
23
23
 
24
+ def result_root_attr
25
+ 'results'
26
+ end
27
+
24
28
  def cache_key(query)
25
29
  "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + hash_to_query(cache_key_params(query))
26
30
  end
@@ -9,13 +9,17 @@ module Geocoder::Lookup
9
9
  end
10
10
 
11
11
  def required_api_key_parts
12
- ["app_id", "app_code"]
12
+ ['api_key']
13
+ end
14
+
15
+ def supported_protocols
16
+ [:https]
13
17
  end
14
18
 
15
19
  private # ---------------------------------------------------------------
16
20
 
17
21
  def base_query_url(query)
18
- "#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.api.here.com/6.2/#{if query.reverse_geocode? then 'reverse' end}geocode.json?"
22
+ "#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.ls.hereapi.com/6.2/#{if query.reverse_geocode? then 'reverse' end}geocode.json?"
19
23
  end
20
24
 
21
25
  def results(query)
@@ -31,8 +35,7 @@ module Geocoder::Lookup
31
35
  def query_url_here_options(query, reverse_geocode)
32
36
  options = {
33
37
  gen: 9,
34
- app_id: api_key,
35
- app_code: api_code,
38
+ apikey: configuration.api_key,
36
39
  language: (query.language || configuration.language)
37
40
  }
38
41
  if reverse_geocode
@@ -61,17 +64,5 @@ module Geocoder::Lookup
61
64
  )
62
65
  end
63
66
  end
64
-
65
- def api_key
66
- if (a = configuration.api_key)
67
- return a.first if a.is_a?(Array)
68
- end
69
- end
70
-
71
- def api_code
72
- if (a = configuration.api_key)
73
- return a.last if a.is_a?(Array)
74
- end
75
- end
76
67
  end
77
68
  end
@@ -19,11 +19,11 @@ module Geocoder::Lookup
19
19
  end
20
20
 
21
21
  def query_url_params(query)
22
- {
23
- key: configuration.api_key ? configuration.api_key : "demo",
24
- format: "json",
25
- ip: query.sanitized_text
26
- }.merge(super)
22
+ params = super
23
+ if configuration.has_key?(:package)
24
+ params.merge!(package: configuration[:package])
25
+ end
26
+ params
27
27
  end
28
28
 
29
29
  def results(query)
@@ -63,13 +63,5 @@ module Geocoder::Lookup
63
63
  }
64
64
  end
65
65
 
66
- def query_url_params(query)
67
- params = super
68
- if configuration.has_key?(:package)
69
- params.merge!(package: configuration[:package])
70
- end
71
- params
72
- end
73
-
74
66
  end
75
67
  end
@@ -0,0 +1,51 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipgeolocation'
3
+
4
+
5
+ module Geocoder::Lookup
6
+ class Ipgeolocation < Base
7
+
8
+ ERROR_CODES = {
9
+ 400 => Geocoder::RequestDenied, # subscription is paused
10
+ 401 => Geocoder::InvalidApiKey, # missing/invalid API key
11
+ 403 => Geocoder::InvalidRequest, # invalid IP address
12
+ 404 => Geocoder::InvalidRequest, # not found
13
+ 423 => Geocoder::InvalidRequest # bogon/reserved IP address
14
+ }
15
+ ERROR_CODES.default = Geocoder::Error
16
+
17
+ def name
18
+ "Ipgeolocation"
19
+ end
20
+
21
+ def supported_protocols
22
+ [:https]
23
+ end
24
+
25
+ private # ----------------------------------------------------------------
26
+
27
+ def base_query_url(query)
28
+ "#{protocol}://api.ipgeolocation.io/ipgeo?"
29
+ end
30
+ def query_url_params(query)
31
+ {
32
+ ip: query.sanitized_text,
33
+ apiKey: configuration.api_key
34
+ }.merge(super)
35
+ end
36
+
37
+ def results(query)
38
+ # don't look up a loopback or private address, just return the stored result
39
+ return [reserved_result(query.text)] if query.internal_ip_address?
40
+ [fetch_data(query)]
41
+ end
42
+
43
+ def reserved_result(ip)
44
+ {
45
+ "ip" => ip,
46
+ "country_name" => "Reserved",
47
+ "country_code2" => "RD"
48
+ }
49
+ end
50
+ end
51
+ end
@@ -25,8 +25,7 @@ module Geocoder::Lookup
25
25
  # The API returned a 404 response, which indicates no results found
26
26
  elsif doc['error']['type'] == 'api_error'
27
27
  []
28
- elsif
29
- doc['error']['type'] == 'authentication_error'
28
+ elsif doc['error']['type'] == 'authentication_error'
30
29
  raise_error(Geocoder::InvalidApiKey) ||
31
30
  Geocoder.log(:warn, "LatLon.io service error: invalid API key.")
32
31
  else
@@ -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,57 @@
1
+ require 'cgi'
2
+ require 'geocoder/lookups/base'
3
+ require 'geocoder/results/osmnames'
4
+
5
+ module Geocoder::Lookup
6
+ class Osmnames < Base
7
+
8
+ def name
9
+ 'OSM Names'
10
+ end
11
+
12
+ def required_api_key_parts
13
+ configuration[:host] ? [] : ['key']
14
+ end
15
+
16
+ def supported_protocols
17
+ [:https]
18
+ end
19
+
20
+ private
21
+
22
+ def base_query_url(query)
23
+ "#{base_url(query)}/#{params_url(query)}.js?"
24
+ end
25
+
26
+ def base_url(query)
27
+ host = configuration[:host] || 'geocoder.tilehosting.com'
28
+ "#{protocol}://#{host}"
29
+ end
30
+
31
+ def params_url(query)
32
+ method, args = 'q', CGI.escape(query.sanitized_text)
33
+ method, args = 'r', query.coordinates.join('/') if query.reverse_geocode?
34
+ "#{country_limited(query)}#{method}/#{args}"
35
+ end
36
+
37
+ def results(query)
38
+ return [] unless doc = fetch_data(query)
39
+ if (error = doc['message'])
40
+ raise_error(Geocoder::InvalidRequest, error) ||
41
+ Geocoder.log(:warn, "OSMNames Geocoding API error: #{error}")
42
+ else
43
+ return doc['results']
44
+ end
45
+ end
46
+
47
+ def query_url_params(query)
48
+ {
49
+ key: configuration.api_key
50
+ }.merge(super)
51
+ end
52
+
53
+ def country_limited(query)
54
+ "#{query.options[:country_code].downcase}/" if query.options[:country_code] && !query.reverse_geocode?
55
+ end
56
+ end
57
+ end
@@ -23,7 +23,7 @@ module Geocoder::Lookup
23
23
  end
24
24
 
25
25
  def query_url_params(query)
26
- params = {
26
+ {
27
27
  key: configuration.api_key
28
28
  }.merge(super)
29
29
  end
@@ -57,7 +57,12 @@ module Geocoder::Lookup
57
57
  end
58
58
 
59
59
  def results(query)
60
- fetch_data(query) || []
60
+ doc = fetch_data(query) || []
61
+ if doc.is_a?(Hash) and doc.key?('status') # implies there's an error
62
+ return []
63
+ else
64
+ return doc
65
+ end
61
66
  end
62
67
  end
63
68
  end
@@ -16,7 +16,7 @@ module Geocoder::Lookup
16
16
  if configuration[:host]
17
17
  "#{protocol}://#{configuration[:host]}/location/#{query.sanitized_text}"
18
18
  else
19
- "#{protocol}://telize-v1.p.mashape.com/location/#{query.sanitized_text}?mashape-key=#{api_key}"
19
+ "#{protocol}://telize-v1.p.rapidapi.com/location/#{query.sanitized_text}?rapidapi-key=#{api_key}"
20
20
  end
21
21
  end
22
22
 
@@ -31,18 +31,18 @@ module Geocoder::Lookup
31
31
  case doc['status']
32
32
  when 0
33
33
  return [doc[content_key]]
34
- when 199
35
- raise error(Geocoder::InvalidApiKey, "invalid api key") ||
36
- Geocoder.log(:warn, "#{name} Geocoding API error: key is not enabled for web service usage.")
37
- when 311
38
- raise_error(Geocoder::RequestDenied, "request denied") ||
39
- Geocoder.log(:warn, "#{name} Geocoding API error: request denied.")
40
- when 310, 306
41
- raise_error(Geocoder::InvalidRequest, "invalid request.") ||
42
- Geocoder.log(:warn, "#{name} Geocoding API error: invalid request.")
43
34
  when 311
44
35
  raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
45
36
  Geocoder.log(:warn, "#{name} Geocoding API error: invalid api key.")
37
+ when 310
38
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
39
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request, invalid parameters.")
40
+ when 306
41
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
42
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request, check response for more info.")
43
+ when 110
44
+ raise_error(Geocoder::RequestDenied, "request denied.") ||
45
+ Geocoder.log(:warn, "#{name} Geocoding API error: request source is not authorized.")
46
46
  end
47
47
  return []
48
48
  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