geocoder 1.5.1 → 1.8.5

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 (100) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +107 -0
  3. data/LICENSE +1 -1
  4. data/README.md +364 -243
  5. data/bin/console +13 -0
  6. data/examples/app_defined_lookup_services.rb +22 -0
  7. data/lib/easting_northing.rb +171 -0
  8. data/lib/generators/geocoder/config/templates/initializer.rb +6 -1
  9. data/lib/geocoder/cache.rb +16 -33
  10. data/lib/geocoder/cache_stores/base.rb +40 -0
  11. data/lib/geocoder/cache_stores/generic.rb +35 -0
  12. data/lib/geocoder/cache_stores/redis.rb +34 -0
  13. data/lib/geocoder/configuration.rb +19 -5
  14. data/lib/geocoder/configuration_hash.rb +4 -4
  15. data/lib/geocoder/ip_address.rb +11 -1
  16. data/lib/geocoder/lookup.rb +42 -6
  17. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  18. data/lib/geocoder/lookups/amap.rb +2 -2
  19. data/lib/geocoder/lookups/amazon_location_service.rb +58 -0
  20. data/lib/geocoder/lookups/azure.rb +56 -0
  21. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +15 -2
  22. data/lib/geocoder/lookups/base.rb +4 -1
  23. data/lib/geocoder/lookups/bing.rb +2 -2
  24. data/lib/geocoder/lookups/esri.rb +24 -5
  25. data/lib/geocoder/lookups/freegeoip.rb +12 -10
  26. data/lib/geocoder/lookups/geoapify.rb +78 -0
  27. data/lib/geocoder/lookups/geocodio.rb +1 -1
  28. data/lib/geocoder/lookups/geoip2.rb +4 -0
  29. data/lib/geocoder/lookups/geoportail_lu.rb +1 -1
  30. data/lib/geocoder/lookups/google.rb +7 -2
  31. data/lib/geocoder/lookups/google_places_details.rb +26 -12
  32. data/lib/geocoder/lookups/google_places_search.rb +44 -2
  33. data/lib/geocoder/lookups/google_premier.rb +4 -0
  34. data/lib/geocoder/lookups/here.rb +27 -31
  35. data/lib/geocoder/lookups/ip2location.rb +10 -14
  36. data/lib/geocoder/lookups/ip2location_io.rb +62 -0
  37. data/lib/geocoder/lookups/ip2location_lite.rb +40 -0
  38. data/lib/geocoder/lookups/ipbase.rb +49 -0
  39. data/lib/geocoder/lookups/ipdata_co.rb +1 -1
  40. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  41. data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
  42. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  43. data/lib/geocoder/lookups/latlon.rb +1 -2
  44. data/lib/geocoder/lookups/location_iq.rb +5 -1
  45. data/lib/geocoder/lookups/mapbox.rb +3 -3
  46. data/lib/geocoder/lookups/maxmind_local.rb +7 -1
  47. data/lib/geocoder/lookups/melissa_street.rb +41 -0
  48. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  49. data/lib/geocoder/lookups/osmnames.rb +57 -0
  50. data/lib/geocoder/lookups/pc_miler.rb +85 -0
  51. data/lib/geocoder/lookups/pdok_nl.rb +43 -0
  52. data/lib/geocoder/lookups/photon.rb +89 -0
  53. data/lib/geocoder/lookups/pickpoint.rb +1 -1
  54. data/lib/geocoder/lookups/smarty_streets.rb +6 -1
  55. data/lib/geocoder/lookups/telize.rb +1 -1
  56. data/lib/geocoder/lookups/tencent.rb +9 -9
  57. data/lib/geocoder/lookups/test.rb +5 -0
  58. data/lib/geocoder/lookups/twogis.rb +58 -0
  59. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  60. data/lib/geocoder/lookups/yandex.rb +6 -7
  61. data/lib/geocoder/query.rb +1 -1
  62. data/lib/geocoder/results/abstract_api.rb +146 -0
  63. data/lib/geocoder/results/amazon_location_service.rb +62 -0
  64. data/lib/geocoder/results/azure.rb +65 -0
  65. data/lib/geocoder/results/baidu.rb +0 -4
  66. data/lib/geocoder/results/ban_data_gouv_fr.rb +28 -3
  67. data/lib/geocoder/results/db_ip_com.rb +1 -1
  68. data/lib/geocoder/results/esri.rb +5 -2
  69. data/lib/geocoder/results/geoapify.rb +179 -0
  70. data/lib/geocoder/results/here.rb +20 -22
  71. data/lib/geocoder/results/ip2location_io.rb +21 -0
  72. data/lib/geocoder/results/ip2location_lite.rb +47 -0
  73. data/lib/geocoder/results/ipbase.rb +40 -0
  74. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  75. data/lib/geocoder/results/ipqualityscore.rb +54 -0
  76. data/lib/geocoder/results/ipregistry.rb +304 -0
  77. data/lib/geocoder/results/mapbox.rb +34 -10
  78. data/lib/geocoder/results/melissa_street.rb +46 -0
  79. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  80. data/lib/geocoder/results/nominatim.rb +27 -15
  81. data/lib/geocoder/results/osmnames.rb +56 -0
  82. data/lib/geocoder/results/pc_miler.rb +98 -0
  83. data/lib/geocoder/results/pdok_nl.rb +62 -0
  84. data/lib/geocoder/results/photon.rb +119 -0
  85. data/lib/geocoder/results/twogis.rb +76 -0
  86. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  87. data/lib/geocoder/results/yandex.rb +217 -59
  88. data/lib/geocoder/sql.rb +4 -4
  89. data/lib/geocoder/util.rb +29 -0
  90. data/lib/geocoder/version.rb +1 -1
  91. data/lib/maxmind_database.rb +12 -12
  92. data/lib/tasks/maxmind.rake +1 -1
  93. metadata +81 -23
  94. data/examples/autoexpire_cache_dalli.rb +0 -62
  95. data/examples/autoexpire_cache_redis.rb +0 -28
  96. data/lib/geocoder/lookups/dstk.rb +0 -22
  97. data/lib/geocoder/lookups/geocoder_us.rb +0 -51
  98. data/lib/geocoder/results/dstk.rb +0 -6
  99. data/lib/geocoder/results/geocoder_us.rb +0 -39
  100. data/lib/hash_recursive_merge.rb +0 -74
data/bin/console ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'geocoder'
5
+
6
+ if File.exist?("api_keys.yml")
7
+ require 'yaml'
8
+ @api_keys = YAML.load(File.read("api_keys.yml"), symbolize_names: true)
9
+ Geocoder.configure(@api_keys)
10
+ end
11
+
12
+ require 'irb'
13
+ IRB.start
@@ -0,0 +1,22 @@
1
+ # To extend the Geocoder with additional lookups that come from the application,
2
+ # not shipped with the gem, define a "child" lookup in your application, based on existing one.
3
+ # This is required because the Geocoder::Configuration is a Singleton and stores one api key per lookup.
4
+
5
+ # in app/libs/geocoder/lookup/my_preciousss.rb
6
+ module Geocoder::Lookup
7
+ class MyPreciousss < Google
8
+ end
9
+ end
10
+
11
+ # Update Geocoder's street_services on initialize:
12
+ # config/initializers/geocoder.rb
13
+ Geocoder::Lookup.street_services << :my_preciousss
14
+
15
+ # Override the configuration when necessary (e.g. provide separate Google API key for the account):
16
+ Geocoder.configure(my_preciousss: { api_key: 'abcdef' })
17
+
18
+ # Lastly, search using your custom lookup service/api keys
19
+ Geocoder.search("Paris", lookup: :my_preciousss)
20
+
21
+ # This is useful when we have groups of users in the application who use Google paid services
22
+ # and we want to properly separate them and allow using individual API KEYS or timeouts.
@@ -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
@@ -9,7 +9,6 @@ Geocoder.configure(
9
9
  # https_proxy: nil, # HTTPS proxy server (user:pass@host:port)
10
10
  # api_key: nil, # API key for geocoding service
11
11
  # cache: nil, # cache object (must respond to #[], #[]=, and #del)
12
- # cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys
13
12
 
14
13
  # Exceptions that should not be rescued by default
15
14
  # (if you want to implement custom error handling);
@@ -19,4 +18,10 @@ Geocoder.configure(
19
18
  # Calculation options
20
19
  # units: :mi, # :km for kilometers or :mi for miles
21
20
  # distances: :linear # :spherical or :linear
21
+
22
+ # Cache configuration
23
+ # cache_options: {
24
+ # expiration: 2.days,
25
+ # prefix: 'geocoder:'
26
+ # }
22
27
  )
@@ -1,37 +1,29 @@
1
+ Dir["#{__dir__}/cache_stores/*.rb"].each {|file| require file }
2
+
1
3
  module Geocoder
2
4
  class Cache
3
5
 
4
- def initialize(store, prefix)
5
- @store = store
6
- @prefix = prefix
6
+ def initialize(store, config)
7
+ @class = (Geocoder::CacheStore.const_get("#{store.class}", false) rescue Geocoder::CacheStore::Generic)
8
+ @store_service = @class.new(store, config)
7
9
  end
8
10
 
9
11
  ##
10
12
  # Read from the Cache.
11
13
  #
12
14
  def [](url)
13
- interpret case
14
- when store.respond_to?(:[])
15
- store[key_for(url)]
16
- when store.respond_to?(:get)
17
- store.get key_for(url)
18
- when store.respond_to?(:read)
19
- store.read key_for(url)
20
- end
15
+ interpret store_service.read(url)
16
+ rescue => e
17
+ Geocoder.log(:warn, "Geocoder cache read error: #{e}")
21
18
  end
22
19
 
23
20
  ##
24
21
  # Write to the Cache.
25
22
  #
26
23
  def []=(url, value)
27
- case
28
- when store.respond_to?(:[]=)
29
- store[key_for(url)] = value
30
- when store.respond_to?(:set)
31
- store.set key_for(url), value
32
- when store.respond_to?(:write)
33
- store.write key_for(url), value
34
- end
24
+ store_service.write(url, value)
25
+ rescue => e
26
+ Geocoder.log(:warn, "Geocoder cache write error: #{e}")
35
27
  end
36
28
 
37
29
  ##
@@ -40,7 +32,7 @@ module Geocoder
40
32
  #
41
33
  def expire(url)
42
34
  if url == :all
43
- if store.respond_to?(:keys)
35
+ if store_service.respond_to?(:keys)
44
36
  urls.each{ |u| expire(u) }
45
37
  else
46
38
  raise(NoMethodError, "The Geocoder cache store must implement `#keys` for `expire(:all)` to work")
@@ -53,29 +45,21 @@ module Geocoder
53
45
 
54
46
  private # ----------------------------------------------------------------
55
47
 
56
- def prefix; @prefix; end
57
- def store; @store; end
58
-
59
- ##
60
- # Cache key for a given URL.
61
- #
62
- def key_for(url)
63
- [prefix, url].join
64
- end
48
+ def store_service; @store_service; end
65
49
 
66
50
  ##
67
51
  # Array of keys with the currently configured prefix
68
52
  # that have non-nil values.
69
53
  #
70
54
  def keys
71
- store.keys.select{ |k| k.match(/^#{prefix}/) and self[k] }
55
+ store_service.keys
72
56
  end
73
57
 
74
58
  ##
75
59
  # Array of cached URLs.
76
60
  #
77
61
  def urls
78
- keys.map{ |k| k[/^#{prefix}(.*)/, 1] }
62
+ store_service.urls
79
63
  end
80
64
 
81
65
  ##
@@ -87,8 +71,7 @@ module Geocoder
87
71
  end
88
72
 
89
73
  def expire_single_url(url)
90
- key = key_for(url)
91
- store.respond_to?(:del) ? store.del(key) : store.delete(key)
74
+ store_service.remove(url)
92
75
  end
93
76
  end
94
77
  end
@@ -0,0 +1,40 @@
1
+ module Geocoder::CacheStore
2
+ class Base
3
+ def initialize(store, options)
4
+ @store = store
5
+ @config = options
6
+ @prefix = config[:prefix]
7
+ end
8
+
9
+ ##
10
+ # Array of keys with the currently configured prefix
11
+ # that have non-nil values.
12
+ def keys
13
+ store.keys.select { |k| k.match(/^#{prefix}/) and self[k] }
14
+ end
15
+
16
+ ##
17
+ # Array of cached URLs.
18
+ #
19
+ def urls
20
+ keys
21
+ end
22
+
23
+ protected # ----------------------------------------------------------------
24
+
25
+ def prefix; @prefix; end
26
+ def store; @store; end
27
+ def config; @config; end
28
+
29
+ ##
30
+ # Cache key for a given URL.
31
+ #
32
+ def key_for(url)
33
+ if url.match(/^#{prefix}/)
34
+ url
35
+ else
36
+ [prefix, url].join
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ require 'geocoder/cache_stores/base'
2
+
3
+ module Geocoder::CacheStore
4
+ class Generic < Base
5
+ def write(url, value)
6
+ case
7
+ when store.respond_to?(:[]=)
8
+ store[key_for(url)] = value
9
+ when store.respond_to?(:set)
10
+ store.set key_for(url), value
11
+ when store.respond_to?(:write)
12
+ store.write key_for(url), value
13
+ end
14
+ end
15
+
16
+ def read(url)
17
+ case
18
+ when store.respond_to?(:[])
19
+ store[key_for(url)]
20
+ when store.respond_to?(:get)
21
+ store.get key_for(url)
22
+ when store.respond_to?(:read)
23
+ store.read key_for(url)
24
+ end
25
+ end
26
+
27
+ def keys
28
+ store.keys
29
+ end
30
+
31
+ def remove(key)
32
+ store.delete(key)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ require 'geocoder/cache_stores/base'
2
+
3
+ module Geocoder::CacheStore
4
+ class Redis < Base
5
+ def initialize(store, options)
6
+ super
7
+ @expiration = options[:expiration]
8
+ end
9
+
10
+ def write(url, value, expire = @expiration)
11
+ if expire.present?
12
+ store.set key_for(url), value, ex: expire
13
+ else
14
+ store.set key_for(url), value
15
+ end
16
+ end
17
+
18
+ def read(url)
19
+ store.get key_for(url)
20
+ end
21
+
22
+ def keys
23
+ store.keys("#{prefix}*")
24
+ end
25
+
26
+ def remove(key)
27
+ store.del(key)
28
+ end
29
+
30
+ private # ----------------------------------------------------------------
31
+
32
+ def expire; @expiration; end
33
+ end
34
+ end
@@ -1,5 +1,6 @@
1
1
  require 'singleton'
2
2
  require 'geocoder/configuration_hash'
3
+ require 'geocoder/util'
3
4
 
4
5
  module Geocoder
5
6
 
@@ -54,19 +55,20 @@ module Geocoder
54
55
  :lookup,
55
56
  :ip_lookup,
56
57
  :language,
58
+ :host,
57
59
  :http_headers,
58
60
  :use_https,
59
61
  :http_proxy,
60
62
  :https_proxy,
61
63
  :api_key,
62
64
  :cache,
63
- :cache_prefix,
64
65
  :always_raise,
65
66
  :units,
66
67
  :distances,
67
68
  :basic_auth,
68
69
  :logger,
69
- :kernel_logger_level
70
+ :kernel_logger_level,
71
+ :cache_options
70
72
  ]
71
73
 
72
74
  attr_accessor :data
@@ -75,6 +77,10 @@ module Geocoder
75
77
  instance.set_defaults
76
78
  end
77
79
 
80
+ def self.initialize
81
+ instance.send(:initialize)
82
+ end
83
+
78
84
  OPTIONS.each do |o|
79
85
  define_method o do
80
86
  @data[o]
@@ -85,7 +91,7 @@ module Geocoder
85
91
  end
86
92
 
87
93
  def configure(options)
88
- @data.rmerge!(options)
94
+ Util.recursive_hash_merge(@data, options)
89
95
  end
90
96
 
91
97
  def initialize # :nodoc
@@ -105,8 +111,6 @@ module Geocoder
105
111
  @data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
106
112
  @data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
107
113
  @data[:api_key] = nil # API key for geocoding service
108
- @data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
109
- @data[:cache_prefix] = "geocoder:" # prefix (string) to use for all cache keys
110
114
  @data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
111
115
  @data[:logger] = :kernel # :kernel or Logger instance
112
116
  @data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
@@ -119,6 +123,16 @@ module Geocoder
119
123
  # calculation options
120
124
  @data[:units] = :mi # :mi or :km
121
125
  @data[:distances] = :linear # :linear or :spherical
126
+
127
+ # Set the default values for the caching mechanism
128
+ # By default, the cache keys will not expire as IP addresses and phyiscal
129
+ # addresses will rarely change.
130
+ @data[:cache] = nil # cache object (must respond to #[], #[]=, and optionally #keys)
131
+ @data[:cache_prefix] = nil # - DEPRECATED - prefix (string) to use for all cache keys
132
+ @data[:cache_options] = {
133
+ prefix: 'geocoder:',
134
+ expiration: nil
135
+ }
122
136
  end
123
137
 
124
138
  instance_eval(OPTIONS.map do |option|
@@ -1,11 +1,11 @@
1
- require 'hash_recursive_merge'
2
-
3
1
  module Geocoder
4
2
  class ConfigurationHash < Hash
5
- include HashRecursiveMerge
6
-
7
3
  def method_missing(meth, *args, &block)
8
4
  has_key?(meth) ? self[meth] : super
9
5
  end
6
+
7
+ def respond_to_missing?(meth, include_private = false)
8
+ has_key?(meth) || super
9
+ end
10
10
  end
11
11
  end
@@ -7,6 +7,15 @@ module Geocoder
7
7
  '192.168.0.0/16',
8
8
  ].map { |ip| IPAddr.new(ip) }.freeze
9
9
 
10
+ def initialize(ip)
11
+ ip = ip.to_string if ip.is_a?(IPAddr)
12
+ if ip.is_a?(Hash)
13
+ super(**ip)
14
+ else
15
+ super(ip)
16
+ end
17
+ end
18
+
10
19
  def internal?
11
20
  loopback? || private?
12
21
  end
@@ -20,7 +29,8 @@ module Geocoder
20
29
  end
21
30
 
22
31
  def valid?
23
- !!((self =~ Resolv::IPv4::Regex) || (self =~ Resolv::IPv6::Regex))
32
+ ip = self[/(?<=\[)(.*?)(?=\])/] || self
33
+ !!((ip =~ Resolv::IPv4::Regex) || (ip =~ Resolv::IPv6::Regex))
24
34
  end
25
35
  end
26
36
  end
@@ -18,13 +18,21 @@ module Geocoder
18
18
  all_services - [:test]
19
19
  end
20
20
 
21
+ ##
22
+ # Array of valid Lookup service names, excluding any that do not build their own HTTP requests.
23
+ # For example, Amazon Location Service uses the AWS gem, not HTTP REST requests, to fetch data.
24
+ #
25
+ def all_services_with_http_requests
26
+ all_services_except_test - [:amazon_location_service, :maxmind_local, :geoip2, :ip2location_lite]
27
+ end
28
+
21
29
  ##
22
30
  # All street address lookup services, default first.
23
31
  #
24
32
  def street_services
25
33
  @street_services ||= [
26
34
  :location_iq,
27
- :dstk,
35
+ :azure,
28
36
  :esri,
29
37
  :google,
30
38
  :google_premier,
@@ -32,13 +40,15 @@ module Geocoder
32
40
  :google_places_search,
33
41
  :bing,
34
42
  :geocoder_ca,
35
- :geocoder_us,
36
43
  :yandex,
44
+ :nationaal_georegister_nl,
37
45
  :nominatim,
38
46
  :mapbox,
39
47
  :mapquest,
48
+ :uk_ordnance_survey_names,
40
49
  :opencagedata,
41
50
  :pelias,
51
+ :pdok_nl,
42
52
  :pickpoint,
43
53
  :here,
44
54
  :baidu,
@@ -51,7 +61,14 @@ module Geocoder
51
61
  :ban_data_gouv_fr,
52
62
  :test,
53
63
  :latlon,
54
- :amap
64
+ :amap,
65
+ :osmnames,
66
+ :melissa_street,
67
+ :amazon_location_service,
68
+ :geoapify,
69
+ :photon,
70
+ :twogis,
71
+ :pc_miler
55
72
  ]
56
73
  end
57
74
 
@@ -61,6 +78,7 @@ module Geocoder
61
78
  def ip_services
62
79
  @ip_services ||= [
63
80
  :baidu_ip,
81
+ :abstract_api,
64
82
  :freegeoip,
65
83
  :geoip2,
66
84
  :maxmind,
@@ -69,11 +87,17 @@ module Geocoder
69
87
  :pointpin,
70
88
  :maxmind_geoip2,
71
89
  :ipinfo_io,
90
+ :ipregistry,
72
91
  :ipapi_com,
73
92
  :ipdata_co,
74
93
  :db_ip_com,
75
94
  :ipstack,
76
- :ip2location
95
+ :ip2location,
96
+ :ipgeolocation,
97
+ :ipqualityscore,
98
+ :ipbase,
99
+ :ip2location_io,
100
+ :ip2location_lite
77
101
  ]
78
102
  end
79
103
 
@@ -99,8 +123,7 @@ module Geocoder
99
123
  def spawn(name)
100
124
  if all_services.include?(name)
101
125
  name = name.to_s
102
- require "geocoder/lookups/#{name}"
103
- Geocoder::Lookup.const_get(classify_name(name)).new
126
+ instantiate_lookup(name)
104
127
  else
105
128
  valids = all_services.map(&:inspect).join(", ")
106
129
  raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
@@ -114,5 +137,18 @@ module Geocoder
114
137
  def classify_name(filename)
115
138
  filename.to_s.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
116
139
  end
140
+
141
+ ##
142
+ # Safely instantiate Lookup
143
+ #
144
+ def instantiate_lookup(name)
145
+ class_name = classify_name(name)
146
+ begin
147
+ Geocoder::Lookup.const_get(class_name, inherit=false)
148
+ rescue NameError
149
+ require "geocoder/lookups/#{name}"
150
+ end
151
+ Geocoder::Lookup.const_get(class_name).new
152
+ end
117
153
  end
118
154
  end