timezone 0.6.0 → 0.99.0
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/.gitignore +1 -0
- data/.rubocop.yml +99 -1
- data/.travis.yml +6 -3
- data/CHANGES.markdown +10 -0
- data/Gemfile +1 -1
- data/README.markdown +129 -89
- data/Rakefile +7 -4
- data/benchmark.rb +13 -13
- data/lib/timezone/active_support.rb +147 -134
- data/lib/timezone/configure.rb +131 -110
- data/lib/timezone/deprecate.rb +32 -0
- data/lib/timezone/error.rb +16 -5
- data/lib/timezone/loader.rb +19 -16
- data/lib/timezone/lookup/basic.rb +24 -2
- data/lib/timezone/lookup/geonames.rb +9 -5
- data/lib/timezone/lookup/google.rb +24 -15
- data/lib/timezone/lookup/test.rb +8 -8
- data/lib/timezone/lookup.rb +68 -0
- data/lib/timezone/net_http_client.rb +23 -9
- data/lib/timezone/nil_zone.rb +32 -0
- data/lib/timezone/parser.rb +10 -5
- data/lib/timezone/version.rb +2 -1
- data/lib/timezone/zone.rb +230 -99
- data/lib/timezone.rb +75 -1
- data/test/basic_lookup_test.rb +2 -2
- data/test/geonames_lookup_test.rb +13 -6
- data/test/google_lookup_test.rb +34 -24
- data/test/http_test_client.rb +7 -6
- data/test/test_lookup_test.rb +3 -1
- data/test/test_timezone.rb +59 -0
- data/test/timezone/lookup/test_geonames.rb +59 -0
- data/test/timezone/lookup/test_google.rb +94 -0
- data/test/timezone/lookup/test_test.rb +24 -0
- data/test/timezone/test_deprecate.rb +20 -0
- data/test/timezone/test_loader.rb +32 -0
- data/test/timezone/test_lookup.rb +53 -0
- data/test/timezone/test_nil_zone.rb +26 -0
- data/test/timezone/test_zone.rb +49 -0
- data/test/timezone_test.rb +64 -63
- data/timezone.gemspec +16 -15
- metadata +39 -38
- data/.rubocop_todo.yml +0 -235
data/lib/timezone/configure.rb
CHANGED
@@ -1,235 +1,256 @@
|
|
1
1
|
require 'timezone/net_http_client'
|
2
2
|
require 'timezone/lookup'
|
3
|
+
require 'timezone/deprecate'
|
3
4
|
|
4
5
|
module Timezone
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# You'll want to sign up for a geonames username at
|
8
|
-
# {http://www.geonames.org/login Geonames}. Use the username to
|
9
|
-
# configure your application for latitude and longitude based
|
10
|
-
# timezone searches.
|
11
|
-
# Alternatively, you'll want to sign up for a Google api key at
|
12
|
-
# {https://code.google.com/apis/console/ Google}. Use the api key to
|
13
|
-
# configure your application for latitude and longitude based
|
14
|
-
# timezone searches.
|
15
|
-
#
|
16
|
-
# If you aren't going to initialize timezone objects based on lat,lng
|
17
|
-
# then this configuration is not necessary.
|
18
|
-
#
|
19
|
-
# @example
|
20
|
-
# Timezone::Configure.begin do |c|
|
21
|
-
# c.geonames_url = 'api.geonames.org'
|
22
|
-
# c.username = 'foo-bar'
|
23
|
-
# c.google_api_key = 'abc123'
|
24
|
-
# end
|
6
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
7
|
+
# of the `timezone gem. Use `Timezone::Lookup::config` instead.
|
25
8
|
#
|
9
|
+
# The old way to configure this gem.
|
10
|
+
# rubocop:disable Style/ClassVars
|
26
11
|
class Configure
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
12
|
+
DEPRECATE = '[DEPRECATED] `Timezone::Configure` will be removed ' \
|
13
|
+
'in the release of the `timezone gem. Use `Timezone::Lookup` ' \
|
14
|
+
'instead.'.freeze
|
15
|
+
|
16
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
17
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
31
18
|
def self.google_api_key
|
32
|
-
|
19
|
+
@@google_api_key ||= nil
|
33
20
|
end
|
34
21
|
|
35
|
-
#
|
36
|
-
#
|
37
|
-
# @param [String] api_key
|
38
|
-
# the Google API key
|
22
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
23
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
39
24
|
def self.google_api_key=(api_key)
|
40
|
-
|
25
|
+
@@google_api_key = api_key
|
41
26
|
end
|
42
27
|
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# @return [String]
|
46
|
-
# the Google Client ('abc123')
|
28
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
29
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
47
30
|
def self.google_client_id
|
48
|
-
|
31
|
+
@@google_client_id ||= nil
|
49
32
|
end
|
50
33
|
|
51
|
-
#
|
52
|
-
#
|
53
|
-
# @param [String] client
|
54
|
-
# the Google Client
|
34
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
35
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
55
36
|
def self.google_client_id=(client)
|
56
|
-
|
37
|
+
@@google_client_id = client
|
57
38
|
end
|
58
39
|
|
59
|
-
#
|
60
|
-
#
|
61
|
-
# @return [Boolean]
|
40
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
41
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
62
42
|
def self.use_google?
|
63
|
-
|
43
|
+
!google_api_key.nil?
|
64
44
|
end
|
65
45
|
|
66
|
-
#
|
67
|
-
#
|
68
|
-
# @return [Boolean]
|
46
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
47
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
69
48
|
def self.use_google_enterprise?
|
70
|
-
use_google? &&
|
49
|
+
use_google? && !google_client_id.nil?
|
71
50
|
end
|
72
51
|
|
52
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
53
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
73
54
|
def self.lookup=(lookup)
|
74
55
|
@lookup = lookup && lookup.new(self)
|
75
56
|
end
|
76
57
|
|
58
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
59
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
77
60
|
def self.lookup
|
78
61
|
return @lookup if @lookup
|
79
62
|
|
80
63
|
use_google? ? google_lookup : geonames_lookup
|
81
64
|
end
|
82
65
|
|
66
|
+
# Responsible for mapping old configuration options to new
|
67
|
+
# configuration style for forwards-compatability with the
|
68
|
+
# updated Google lookup.
|
69
|
+
class GoogleConfigMapper
|
70
|
+
def initialize(config)
|
71
|
+
@config = config
|
72
|
+
end
|
73
|
+
|
74
|
+
def protocol; @config.protocol; end
|
75
|
+
|
76
|
+
def url; @config.url; end
|
77
|
+
|
78
|
+
def http_client; @config.http_client; end
|
79
|
+
|
80
|
+
def api_key; @config.google_api_key; end
|
81
|
+
|
82
|
+
def client_id; @config.google_client_id; end
|
83
|
+
|
84
|
+
def request_handler; nil; end
|
85
|
+
end
|
86
|
+
|
87
|
+
private_constant :GoogleConfigMapper
|
88
|
+
|
89
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
90
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
83
91
|
def self.google_lookup
|
84
|
-
@google_lookup ||=
|
92
|
+
@google_lookup ||=
|
93
|
+
Timezone::Lookup::Google.new(GoogleConfigMapper.new(self))
|
94
|
+
end
|
95
|
+
|
96
|
+
# Responsible for mapping old configuration options to new
|
97
|
+
# configuration style for forwards-compatability with the
|
98
|
+
# updated Geonames lookup.
|
99
|
+
class GeonamesConfigMapper
|
100
|
+
def initialize(config)
|
101
|
+
@config = config
|
102
|
+
end
|
103
|
+
|
104
|
+
def protocol; @config.protocol; end
|
105
|
+
|
106
|
+
def url; @config.url; end
|
107
|
+
|
108
|
+
def username; @config.username; end
|
109
|
+
|
110
|
+
def http_client; @config.http_client; end
|
111
|
+
|
112
|
+
def request_handler; nil; end
|
85
113
|
end
|
86
114
|
|
115
|
+
private_constant :GeonamesConfigMapper
|
116
|
+
|
117
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
118
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
87
119
|
def self.geonames_lookup
|
88
|
-
@geonames_lookup ||=
|
120
|
+
@geonames_lookup ||=
|
121
|
+
Timezone::Lookup::Geonames.new(GeonamesConfigMapper.new(self))
|
89
122
|
end
|
90
123
|
|
91
|
-
#
|
92
|
-
#
|
93
|
-
# @return [String]
|
94
|
-
# the Geonames API URL ('api.geonames.org')
|
124
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
125
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
95
126
|
def self.geonames_url
|
96
127
|
@@geonames_url ||= 'api.geonames.org'
|
97
128
|
end
|
98
129
|
|
99
|
-
#
|
100
|
-
#
|
101
|
-
# @param [String] url
|
102
|
-
# the Geonames API URL
|
130
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
131
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
103
132
|
def self.geonames_url=(url)
|
104
133
|
@@geonames_url = url
|
105
134
|
end
|
106
135
|
|
107
|
-
|
108
|
-
|
136
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
137
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
138
|
+
def self.url=(url)
|
139
|
+
self.geonames_url = url
|
109
140
|
end
|
110
141
|
|
111
|
-
#
|
112
|
-
#
|
113
|
-
# @return [String]
|
114
|
-
# the Google API URL ('maps.googleapis.com')
|
142
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
143
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
115
144
|
def self.google_url
|
116
145
|
@@google_url ||= 'maps.googleapis.com'
|
117
146
|
end
|
118
147
|
|
119
|
-
#
|
120
|
-
#
|
121
|
-
# @param [String] url
|
122
|
-
# the Google API URL
|
148
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
149
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
123
150
|
def self.google_url=(url)
|
124
151
|
@@google_url = url
|
125
152
|
end
|
126
153
|
|
127
|
-
#
|
128
|
-
#
|
129
|
-
# @return [String]
|
130
|
-
# the Google or Geonames API URL
|
154
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
155
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
131
156
|
def self.url
|
132
157
|
use_google? ? google_url : geonames_url
|
133
158
|
end
|
134
159
|
|
135
|
-
#
|
136
|
-
#
|
137
|
-
# @param [String] protocol
|
138
|
-
# the Geonames API HTTP procotol
|
160
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
161
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
139
162
|
def self.geonames_protocol=(protocol)
|
140
163
|
@@geonames_protocol = protocol
|
141
164
|
end
|
142
165
|
|
143
|
-
#
|
144
|
-
#
|
145
|
-
# @return [String]
|
146
|
-
# the Geonames API HTTP protocol ('http')
|
166
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
167
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
147
168
|
def self.geonames_protocol
|
148
169
|
@@geonames_protocol ||= 'http'
|
149
170
|
end
|
150
171
|
|
151
|
-
#
|
152
|
-
#
|
153
|
-
# @param [String] protocol
|
154
|
-
# the Google API HTTP procotol
|
172
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
173
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
155
174
|
def self.google_protocol=(protocol)
|
156
175
|
@@google_protocol = protocol
|
157
176
|
end
|
158
177
|
|
159
|
-
#
|
160
|
-
#
|
161
|
-
# @return [String]
|
162
|
-
# the Google API HTTP protocol ('https')
|
178
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
179
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
163
180
|
def self.google_protocol
|
164
181
|
@@google_protocol ||= 'https'
|
165
182
|
end
|
166
183
|
|
167
|
-
#
|
168
|
-
#
|
169
|
-
# @return [String]
|
170
|
-
# the Google or Geonames API protocol
|
184
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
185
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
171
186
|
def self.protocol
|
172
187
|
use_google? ? google_protocol : geonames_protocol
|
173
188
|
end
|
174
189
|
|
175
|
-
#
|
176
|
-
#
|
177
|
-
# @return [Object]
|
178
|
-
# the HTTP client ({Timezone::NetHTTPClient Timezone::NetHTTPClient})
|
190
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
191
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
179
192
|
def self.http_client
|
180
193
|
@@http_client ||= Timezone::NetHTTPClient
|
181
194
|
end
|
182
195
|
|
183
|
-
#
|
184
|
-
#
|
185
|
-
# @param [Object] client
|
186
|
-
# the HTTP client that handles requests to Geonames and Google
|
187
|
-
#
|
196
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
197
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
188
198
|
def self.http_client=(client)
|
189
199
|
@@http_client = client
|
190
200
|
end
|
191
201
|
|
192
|
-
#
|
193
|
-
#
|
194
|
-
# @return [String]
|
195
|
-
# the Geonames API username ('foo-bar')
|
202
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
203
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
196
204
|
def self.username
|
197
205
|
@@username ||= nil
|
198
206
|
end
|
199
207
|
|
200
|
-
#
|
201
|
-
#
|
202
|
-
# @param [String] username
|
203
|
-
# the Geonames API username
|
208
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
209
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
204
210
|
def self.username=(username)
|
205
211
|
@@username = username
|
206
212
|
end
|
207
213
|
|
214
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
215
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
208
216
|
def self.begin
|
217
|
+
Deprecate.call(self, :begin, DEPRECATE)
|
209
218
|
yield self
|
210
219
|
end
|
211
220
|
|
212
|
-
|
221
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
222
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
223
|
+
def self.replace(what, with = {})
|
213
224
|
replacements # instantiate @@replacements
|
214
225
|
@@replacements[what] = with[:with]
|
215
226
|
end
|
216
227
|
|
228
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
229
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
217
230
|
def self.replacements
|
218
231
|
@@replacements ||= {}
|
219
232
|
end
|
220
233
|
|
234
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
235
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
221
236
|
def self.default_for_list
|
222
237
|
@@default_list ||= nil
|
223
238
|
end
|
224
239
|
|
240
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
241
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
225
242
|
def self.default_for_list=(*list)
|
226
243
|
@@default_list = list.flatten!
|
227
244
|
end
|
228
245
|
|
246
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
247
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
229
248
|
def self.order_list_by
|
230
249
|
@@order_by ||= :utc_offset
|
231
250
|
end
|
232
251
|
|
252
|
+
# @deprecated `Timezone::Configure` will be removed in the release
|
253
|
+
# of the `timezone gem. Use `Timezone::Lookup instead.
|
233
254
|
def self.order_list_by=(order)
|
234
255
|
@@order_by = order
|
235
256
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Timezone
|
2
|
+
# This class provides a way to set a custom hook for deprecations.
|
3
|
+
module Deprecate
|
4
|
+
class << self
|
5
|
+
# Set the custom deprecation callback. By default this
|
6
|
+
# issues a deprecation warning.
|
7
|
+
#
|
8
|
+
# @param callback [#call] the custom callback
|
9
|
+
#
|
10
|
+
# @example Send a message to StatsD
|
11
|
+
# Timezone::Deprecate.callback = lambda do |klass, method, _|
|
12
|
+
# StatsD.increment(sanitize(klass, method))
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# @example Send a message to a custom logger
|
16
|
+
# Timezone::Deprecate.callback = lambda do |klass, method, msg|
|
17
|
+
# MyLogger.log("[#{klass} : #{method}] #{msg}")
|
18
|
+
# end
|
19
|
+
attr_writer :callback
|
20
|
+
|
21
|
+
# @!visibility private
|
22
|
+
def callback
|
23
|
+
@callback || -> (_, _, message) { warn(message) }
|
24
|
+
end
|
25
|
+
|
26
|
+
# @!visibility private
|
27
|
+
def call(klass, method, message)
|
28
|
+
callback && callback.call(klass, method, message)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/timezone/error.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module Timezone
|
2
|
-
# Error messages that can be raised by this gem. To catch any
|
2
|
+
# Error messages that can be raised by this gem. To catch any
|
3
|
+
# related error message, use Error::Base.
|
3
4
|
#
|
4
5
|
# begin
|
5
6
|
# ...
|
@@ -7,13 +8,23 @@ module Timezone
|
|
7
8
|
# puts "Timezone Error: #{e.message}"
|
8
9
|
# end
|
9
10
|
module Error
|
11
|
+
# Top-level error. All other timezone errors subclass this one.
|
10
12
|
class Base < StandardError; end
|
13
|
+
# Indicates an invalid timezone name.
|
11
14
|
class InvalidZone < Base; end
|
15
|
+
# @deprecated this class will be removed in the next release of the gem.
|
12
16
|
class NilZone < Base; end
|
13
|
-
|
14
|
-
class
|
17
|
+
# Indicates a lookup failure.
|
18
|
+
class Lookup < Base; end
|
19
|
+
# Indicates an error during lookup using the geonames API.
|
20
|
+
class GeoNames < Lookup; end
|
21
|
+
# Indicates an error during lookup using the google API.
|
22
|
+
class Google < Lookup; end
|
23
|
+
# @deprecated this class will be removed in the next release of the gem.
|
15
24
|
class ParseTime < Base; end
|
16
|
-
|
17
|
-
class
|
25
|
+
# Indicates a missing stub during a test lookup.
|
26
|
+
class Test < Lookup; end
|
27
|
+
# Indicates an invalid configuration.
|
28
|
+
class InvalidConfig < Base; end
|
18
29
|
end
|
19
30
|
end
|
data/lib/timezone/loader.rb
CHANGED
@@ -1,27 +1,34 @@
|
|
1
1
|
require 'timezone/error'
|
2
2
|
|
3
|
-
module Timezone
|
3
|
+
module Timezone # rubocop:disable Style/Documentation
|
4
|
+
# Responsible for loading and parsing timezone data from files.
|
4
5
|
module Loader
|
5
|
-
ZONE_FILE_PATH = File.expand_path(File.dirname(__FILE__)+'/../../data')
|
6
|
+
ZONE_FILE_PATH = File.expand_path(File.dirname(__FILE__) + '/../../data')
|
6
7
|
SOURCE_BIT = 0
|
7
8
|
|
8
9
|
class << self
|
9
|
-
def load(
|
10
|
+
def load(name)
|
11
|
+
raise ::Timezone::Error::InvalidZone unless valid?(name)
|
12
|
+
|
10
13
|
@rules ||= {}
|
11
|
-
@rules[
|
14
|
+
@rules[name] ||= parse_zone_data(get_zone_data(name))
|
12
15
|
end
|
13
16
|
|
14
17
|
def names
|
15
|
-
|
18
|
+
@names ||= parse_zone_names
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?(name)
|
22
|
+
names.include?(name)
|
16
23
|
end
|
17
24
|
|
18
25
|
private
|
19
26
|
|
20
27
|
def parse_zone_names
|
21
|
-
files = Dir[File.join(ZONE_FILE_PATH,
|
28
|
+
files = Dir[File.join(ZONE_FILE_PATH, '**/*')].map do |file|
|
22
29
|
next if File.directory?(file)
|
23
30
|
|
24
|
-
file.
|
31
|
+
file.sub("#{ZONE_FILE_PATH}/", '')
|
25
32
|
end
|
26
33
|
|
27
34
|
files.compact
|
@@ -35,7 +42,7 @@ module Timezone
|
|
35
42
|
source = source.to_i
|
36
43
|
dst = dst == '1'
|
37
44
|
offset = offset.to_i
|
38
|
-
source = rules.last[SOURCE_BIT]+source if rules.last
|
45
|
+
source = rules.last[SOURCE_BIT] + source if rules.last
|
39
46
|
rules << [source, name, dst, offset]
|
40
47
|
end
|
41
48
|
|
@@ -43,15 +50,11 @@ module Timezone
|
|
43
50
|
end
|
44
51
|
|
45
52
|
# Retrieve the data from a particular time zone
|
46
|
-
def get_zone_data(
|
47
|
-
|
48
|
-
|
49
|
-
if !File.exists?(file)
|
50
|
-
raise Timezone::Error::InvalidZone, "'#{zone}' is not a valid zone."
|
51
|
-
end
|
52
|
-
|
53
|
-
File.read(file)
|
53
|
+
def get_zone_data(name)
|
54
|
+
File.read(File.join(ZONE_FILE_PATH, name))
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
58
|
+
|
59
|
+
private_constant :Loader
|
57
60
|
end
|
@@ -2,9 +2,13 @@ require 'timezone/error'
|
|
2
2
|
|
3
3
|
module Timezone
|
4
4
|
module Lookup
|
5
|
+
# @abstract Subclass and override {#lookup} to implement
|
6
|
+
# a custom Lookup class.
|
5
7
|
class Basic
|
6
8
|
attr_reader :config
|
7
9
|
|
10
|
+
# @param config [#protocol, #url, #request_handler] a configuration
|
11
|
+
# object
|
8
12
|
def initialize(config)
|
9
13
|
if config.protocol.nil?
|
10
14
|
raise(::Timezone::Error::InvalidConfig, 'missing protocol')
|
@@ -17,11 +21,29 @@ module Timezone
|
|
17
21
|
@config = config
|
18
22
|
end
|
19
23
|
|
24
|
+
# Returns an instance of the request handler.
|
25
|
+
#
|
26
|
+
# @return [#get] an instance of a request handler
|
20
27
|
def client
|
21
|
-
|
28
|
+
# TODO: Remove http_client once on 1.0.0
|
29
|
+
@client ||=
|
30
|
+
if !config.request_handler.nil?
|
31
|
+
config.request_handler.new(config)
|
32
|
+
else
|
33
|
+
config.http_client.new(config.protocol, config.url)
|
34
|
+
end
|
22
35
|
end
|
23
36
|
|
24
|
-
|
37
|
+
# Returns a timezone name for a given lat, long pair.
|
38
|
+
#
|
39
|
+
# @param lat [Double] latitude coordinate
|
40
|
+
# @param long [Double] longitude coordinate
|
41
|
+
# @return [String] the timezone name
|
42
|
+
# @return [nil] if the lat, long pair does not resolve to an
|
43
|
+
# actual timezone
|
44
|
+
# @raise [Timezone::Error::Base] if an error occurred while
|
45
|
+
# while performing the lookup
|
46
|
+
def lookup(_lat, _long)
|
25
47
|
raise NoMethodError, 'lookup is not implemented'
|
26
48
|
end
|
27
49
|
end
|
@@ -5,17 +5,21 @@ require 'uri'
|
|
5
5
|
|
6
6
|
module Timezone
|
7
7
|
module Lookup
|
8
|
+
# @!visibility private
|
8
9
|
class Geonames < ::Timezone::Lookup::Basic
|
9
10
|
def initialize(config)
|
10
11
|
if config.username.nil?
|
11
|
-
raise(::Timezone::Error::InvalidConfig, 'missing username')
|
12
|
+
raise(::Timezone::Error::InvalidConfig, 'missing username'.freeze)
|
12
13
|
end
|
13
14
|
|
15
|
+
config.protocol ||= 'http'.freeze
|
16
|
+
config.url ||= 'api.geonames.org'.freeze
|
17
|
+
|
14
18
|
super
|
15
19
|
end
|
16
20
|
|
17
|
-
def lookup(lat,
|
18
|
-
response = client.get(url(lat,
|
21
|
+
def lookup(lat, long)
|
22
|
+
response = client.get(url(lat, long))
|
19
23
|
|
20
24
|
return unless response.code =~ /^2\d\d$/
|
21
25
|
|
@@ -32,10 +36,10 @@ module Timezone
|
|
32
36
|
|
33
37
|
private
|
34
38
|
|
35
|
-
def url(lat,
|
39
|
+
def url(lat, long)
|
36
40
|
query = URI.encode_www_form(
|
37
41
|
'lat' => lat,
|
38
|
-
'lng' =>
|
42
|
+
'lng' => long,
|
39
43
|
'username' => config.username)
|
40
44
|
"/timezoneJSON?#{query}"
|
41
45
|
end
|
@@ -8,53 +8,62 @@ require 'cgi'
|
|
8
8
|
|
9
9
|
module Timezone
|
10
10
|
module Lookup
|
11
|
+
# @!visibility private
|
11
12
|
class Google < ::Timezone::Lookup::Basic
|
12
13
|
def initialize(config)
|
13
|
-
if config.
|
14
|
-
raise(::Timezone::Error::InvalidConfig, 'missing api key')
|
14
|
+
if config.api_key.nil?
|
15
|
+
raise(::Timezone::Error::InvalidConfig, 'missing api key'.freeze)
|
15
16
|
end
|
17
|
+
|
18
|
+
config.protocol ||= 'https'.freeze
|
19
|
+
config.url ||= 'maps.googleapis.com'.freeze
|
20
|
+
|
16
21
|
super
|
17
22
|
end
|
18
23
|
|
19
|
-
def lookup(lat,
|
20
|
-
response = client.get(url(lat,
|
24
|
+
def lookup(lat, long)
|
25
|
+
response = client.get(url(lat, long))
|
21
26
|
|
22
|
-
if response.code == '403'
|
23
|
-
raise(Timezone::Error::Google, '403 Forbidden')
|
27
|
+
if response.code == '403'.freeze
|
28
|
+
raise(Timezone::Error::Google, '403 Forbidden'.freeze)
|
24
29
|
end
|
25
30
|
|
26
31
|
return unless response.code =~ /^2\d\d$/
|
27
32
|
data = JSON.parse(response.body)
|
28
33
|
|
29
|
-
if data['status'] != 'OK'
|
34
|
+
if data['status'.freeze] != 'OK'.freeze
|
30
35
|
raise(Timezone::Error::Google, data['errorMessage'])
|
31
36
|
end
|
32
37
|
|
33
|
-
data['timeZoneId']
|
38
|
+
data['timeZoneId'.freeze]
|
34
39
|
rescue => e
|
35
40
|
raise(Timezone::Error::Google, e.message)
|
36
41
|
end
|
37
42
|
|
38
43
|
private
|
39
44
|
|
45
|
+
def use_google_enterprise?
|
46
|
+
!config.client_id.nil?
|
47
|
+
end
|
48
|
+
|
40
49
|
def authorize(url)
|
41
|
-
if
|
42
|
-
url += "&client=#{CGI.escape(config.
|
50
|
+
if use_google_enterprise?
|
51
|
+
url += "&client=#{CGI.escape(config.client_id)}"
|
43
52
|
|
44
53
|
sha1 = OpenSSL::Digest.new('sha1')
|
45
|
-
binary_key = Base64.decode64(config.
|
54
|
+
binary_key = Base64.decode64(config.api_key.tr('-_', '+/'))
|
46
55
|
binary_signature = OpenSSL::HMAC.digest(sha1, binary_key, url)
|
47
|
-
signature = Base64.encode64(binary_signature).tr('+/','-_').strip
|
56
|
+
signature = Base64.encode64(binary_signature).tr('+/', '-_').strip
|
48
57
|
|
49
58
|
url + "&signature=#{signature}"
|
50
59
|
else
|
51
|
-
url + "&key=#{config.
|
60
|
+
url + "&key=#{config.api_key}"
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
55
|
-
def url(lat,
|
64
|
+
def url(lat, long)
|
56
65
|
query = URI.encode_www_form(
|
57
|
-
'location' => "#{lat},#{
|
66
|
+
'location' => "#{lat},#{long}",
|
58
67
|
'timestamp' => Time.now.to_i)
|
59
68
|
|
60
69
|
authorize("/maps/api/timezone/json?#{query}")
|