uv-rays 2.3.0 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,308 +1,307 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # Copyright (c) 2006-2013, John Mettraux, jmettraux@gmail.com
5
- #
6
- # Permission is hereby granted, free of charge, to any person obtaining a copy
7
- # of this software and associated documentation files (the "Software"), to deal
8
- # in the Software without restriction, including without limitation the rights
9
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- # copies of the Software, and to permit persons to whom the Software is
11
- # furnished to do so, subject to the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be included in
14
- # all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- # THE SOFTWARE.
23
- #
24
- # Made in Japan.
25
- #++
26
-
27
- require 'parse-cron'
28
-
29
-
30
- module UV
31
- class Scheduler
32
-
33
- # Thread safe timezone time class for use with parse-cron
34
- class TimeInZone
35
- def initialize(timezone)
36
- @timezone = timezone
37
- end
38
-
39
- def now
40
- time = nil
41
- Time.use_zone(@timezone) do
42
- time = Time.now
43
- end
44
- time
45
- end
46
-
47
- def local(*args)
48
- result = nil
49
- Time.use_zone(@timezone) do
50
- result = Time.local(*args)
51
- end
52
- result
53
- end
54
- end
55
-
56
-
57
- def self.parse_in(o, quiet = false)
58
- # if o is an integer we are looking at ms
59
- o.is_a?(String) ? parse_duration(o, quiet) : o
60
- end
61
-
62
- TZ_REGEX = /\b((?:[a-zA-Z][a-zA-z0-9\-+]+)(?:\/[a-zA-Z0-9\-+]+)?)\b/
63
-
64
- def self.parse_at(o, quiet = false)
65
- return (o.to_f * 1000).to_i if o.is_a?(Time)
66
-
67
- tz = nil
68
- s = o.to_s.gsub(TZ_REGEX) { |m|
69
- t = TZInfo::Timezone.get(m) rescue nil
70
- tz ||= t
71
- t ? '' : m
72
- }
73
-
74
- begin
75
- DateTime.parse(o)
76
- rescue
77
- raise ArgumentError, "no time information in #{o.inspect}"
78
- end if RUBY_VERSION < '1.9.0'
79
-
80
- t = Time.parse(s)
81
- t = tz.local_to_utc(t) if tz
82
- (t.to_f * 1000).to_i # Convert to milliseconds
83
-
84
- rescue StandardError => se
85
- return nil if quiet
86
- raise se
87
- end
88
-
89
- def self.parse_cron(o, quiet = false, timezone: nil)
90
- if timezone
91
- tz = TimeInZone.new(timezone)
92
- CronParser.new(o, tz)
93
- else
94
- CronParser.new(o)
95
- end
96
-
97
- rescue ArgumentError => ae
98
- return nil if quiet
99
- raise ae
100
- end
101
-
102
- def self.parse_to_time(o)
103
- t = o
104
- t = parse(t) if t.is_a?(String)
105
- t = Time.now + t if t.is_a?(Numeric)
106
-
107
- raise ArgumentError.new(
108
- "cannot turn #{o.inspect} to a point in time, doesn't make sense"
109
- ) unless t.is_a?(Time)
110
-
111
- t
112
- end
113
-
114
- DURATIONS2M = [
115
- [ 'y', 365 * 24 * 3600 * 1000 ],
116
- [ 'M', 30 * 24 * 3600 * 1000 ],
117
- [ 'w', 7 * 24 * 3600 * 1000 ],
118
- [ 'd', 24 * 3600 * 1000 ],
119
- [ 'h', 3600 * 1000 ],
120
- [ 'm', 60 * 1000 ],
121
- [ 's', 1000 ]
122
- ]
123
- DURATIONS2 = DURATIONS2M.dup
124
- DURATIONS2.delete_at(1)
125
-
126
- DURATIONS = DURATIONS2M.inject({}) { |r, (k, v)| r[k] = v; r }
127
- DURATION_LETTERS = DURATIONS.keys.join
128
-
129
- DU_KEYS = DURATIONS2M.collect { |k, v| k.to_sym }
130
-
131
- # Turns a string like '1m10s' into a float like '70.0', more formally,
132
- # turns a time duration expressed as a string into a Float instance
133
- # (millisecond count).
134
- #
135
- # w -> week
136
- # d -> day
137
- # h -> hour
138
- # m -> minute
139
- # s -> second
140
- # M -> month
141
- # y -> year
142
- # 'nada' -> millisecond
143
- #
144
- # Some examples:
145
- #
146
- # Rufus::Scheduler.parse_duration "0.5" # => 0.5
147
- # Rufus::Scheduler.parse_duration "500" # => 0.5
148
- # Rufus::Scheduler.parse_duration "1000" # => 1.0
149
- # Rufus::Scheduler.parse_duration "1h" # => 3600.0
150
- # Rufus::Scheduler.parse_duration "1h10s" # => 3610.0
151
- # Rufus::Scheduler.parse_duration "1w2d" # => 777600.0
152
- #
153
- # Negative time strings are OK (Thanks Danny Fullerton):
154
- #
155
- # Rufus::Scheduler.parse_duration "-0.5" # => -0.5
156
- # Rufus::Scheduler.parse_duration "-1h" # => -3600.0
157
- #
158
- def self.parse_duration(string, quiet = false)
159
- string = string.to_s
160
-
161
- return 0 if string == ''
162
-
163
- m = string.match(/^(-?)([\d\.#{DURATION_LETTERS}]+)$/)
164
-
165
- return nil if m.nil? && quiet
166
- raise ArgumentError.new("cannot parse '#{string}'") if m.nil?
167
-
168
- mod = m[1] == '-' ? -1.0 : 1.0
169
- val = 0.0
170
-
171
- s = m[2]
172
-
173
- while s.length > 0
174
- m = nil
175
- if m = s.match(/^(\d+|\d+\.\d*|\d*\.\d+)([#{DURATION_LETTERS}])(.*)$/)
176
- val += m[1].to_f * DURATIONS[m[2]]
177
- elsif s.match(/^\d+$/)
178
- val += s.to_i
179
- elsif s.match(/^\d*\.\d*$/)
180
- val += s.to_f
181
- elsif quiet
182
- return nil
183
- else
184
- raise ArgumentError.new(
185
- "cannot parse '#{string}' (unexpected '#{s}')"
186
- )
187
- end
188
- break unless m && m[3]
189
- s = m[3]
190
- end
191
-
192
- res = mod * val
193
- res.to_i
194
- end
195
-
196
-
197
- # Turns a number of seconds into a a time string
198
- #
199
- # Rufus.to_duration 0 # => '0s'
200
- # Rufus.to_duration 60 # => '1m'
201
- # Rufus.to_duration 3661 # => '1h1m1s'
202
- # Rufus.to_duration 7 * 24 * 3600 # => '1w'
203
- # Rufus.to_duration 30 * 24 * 3600 + 1 # => "4w2d1s"
204
- #
205
- # It goes from seconds to the year. Months are not counted (as they
206
- # are of variable length). Weeks are counted.
207
- #
208
- # For 30 days months to be counted, the second parameter of this
209
- # method can be set to true.
210
- #
211
- # Rufus.to_duration 30 * 24 * 3600 + 1, true # => "1M1s"
212
- #
213
- # If a Float value is passed, milliseconds will be displayed without
214
- # 'marker'
215
- #
216
- # Rufus.to_duration 0.051 # => "51"
217
- # Rufus.to_duration 7.051 # => "7s51"
218
- # Rufus.to_duration 0.120 + 30 * 24 * 3600 + 1 # => "4w2d1s120"
219
- #
220
- # (this behaviour mirrors the one found for parse_time_string()).
221
- #
222
- # Options are :
223
- #
224
- # * :months, if set to true, months (M) of 30 days will be taken into
225
- # account when building up the result
226
- # * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
227
- # from the result
228
- #
229
- def self.to_duration(seconds, options = {})
230
- h = to_duration_hash(seconds, options)
231
-
232
- return (options[:drop_seconds] ? '0m' : '0s') if h.empty?
233
-
234
- s = DU_KEYS.inject(String.new) { |r, key|
235
- count = h[key]
236
- count = nil if count == 0
237
- r << "#{count}#{key}" if count
238
- r
239
- }
240
-
241
- ms = h[:ms]
242
- s << ms.to_s if ms
243
- s
244
- end
245
-
246
- # Turns a number of seconds (integer or Float) into a hash like in :
247
- #
248
- # Rufus.to_duration_hash 0.051
249
- # # => { :ms => "51" }
250
- # Rufus.to_duration_hash 7.051
251
- # # => { :s => 7, :ms => "51" }
252
- # Rufus.to_duration_hash 0.120 + 30 * 24 * 3600 + 1
253
- # # => { :w => 4, :d => 2, :s => 1, :ms => "120" }
254
- #
255
- # This method is used by to_duration behind the scenes.
256
- #
257
- # Options are :
258
- #
259
- # * :months, if set to true, months (M) of 30 days will be taken into
260
- # account when building up the result
261
- # * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
262
- # from the result
263
- #
264
- def self.to_duration_hash(seconds, options = {})
265
- h = {}
266
-
267
- if (seconds % 1000) > 0
268
- h[:ms] = (seconds % 1000).to_i
269
- seconds = (seconds / 1000).to_i * 1000
270
- end
271
-
272
- if options[:drop_seconds]
273
- h.delete(:ms)
274
- seconds = (seconds - seconds % 60000)
275
- end
276
-
277
- durations = options[:months] ? DURATIONS2M : DURATIONS2
278
-
279
- durations.each do |key, duration|
280
- count = seconds / duration
281
- seconds = seconds % duration
282
-
283
- h[key.to_sym] = count if count > 0
284
- end
285
-
286
- h
287
- end
288
-
289
- #--
290
- # misc
291
- #++
292
-
293
- # Produces the UTC string representation of a Time instance
294
- #
295
- # like "2009/11/23 11:11:50.947109 UTC"
296
- #
297
- def self.utc_to_s(t=Time.now)
298
- "#{t.utc.strftime('%Y-%m-%d %H:%M:%S')}.#{sprintf('%06d', t.usec)} UTC"
299
- end
300
-
301
- # Produces a hour/min/sec/milli string representation of Time instance
302
- #
303
- def self.h_to_s(t=Time.now)
304
- "#{t.strftime('%H:%M:%S')}.#{sprintf('%06d', t.usec)}"
305
- end
306
- end
307
- end
308
-
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Copyright (c) 2006-2013, John Mettraux, jmettraux@gmail.com
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ # THE SOFTWARE.
23
+ #
24
+ # Made in Japan.
25
+ #++
26
+
27
+ require 'parse-cron'
28
+
29
+
30
+ module UV
31
+ class Scheduler
32
+
33
+ # Thread safe timezone time class for use with parse-cron
34
+ class TimeInZone
35
+ def initialize(timezone)
36
+ @timezone = timezone
37
+ end
38
+
39
+ def now
40
+ time = nil
41
+ Time.use_zone(@timezone) do
42
+ time = Time.now
43
+ end
44
+ time
45
+ end
46
+
47
+ def local(*args)
48
+ result = nil
49
+ Time.use_zone(@timezone) do
50
+ result = Time.local(*args)
51
+ end
52
+ result
53
+ end
54
+ end
55
+
56
+
57
+ def self.parse_in(o, quiet = false)
58
+ # if o is an integer we are looking at ms
59
+ o.is_a?(String) ? parse_duration(o, quiet) : o
60
+ end
61
+
62
+ TZ_REGEX = /\b((?:[a-zA-Z][a-zA-z0-9\-+]+)(?:\/[a-zA-Z0-9\-+]+)?)\b/
63
+
64
+ def self.parse_at(o, quiet = false)
65
+ return (o.to_f * 1000).to_i if o.is_a?(Time)
66
+
67
+ tz = nil
68
+ s = o.to_s.gsub(TZ_REGEX) { |m|
69
+ t = TZInfo::Timezone.get(m) rescue nil
70
+ tz ||= t
71
+ t ? '' : m
72
+ }
73
+
74
+ begin
75
+ DateTime.parse(o)
76
+ rescue
77
+ raise ArgumentError, "no time information in #{o.inspect}"
78
+ end if RUBY_VERSION < '1.9.0'
79
+
80
+ t = Time.parse(s)
81
+ t = tz.local_to_utc(t) if tz
82
+ (t.to_f * 1000).to_i # Convert to milliseconds
83
+
84
+ rescue StandardError => se
85
+ return nil if quiet
86
+ raise se
87
+ end
88
+
89
+ def self.parse_cron(o, quiet = false, timezone: nil)
90
+ if timezone
91
+ tz = TimeInZone.new(timezone)
92
+ CronParser.new(o, tz)
93
+ else
94
+ CronParser.new(o)
95
+ end
96
+
97
+ rescue ArgumentError => ae
98
+ return nil if quiet
99
+ raise ae
100
+ end
101
+
102
+ def self.parse_to_time(o)
103
+ t = o
104
+ t = parse(t) if t.is_a?(String)
105
+ t = Time.now + t if t.is_a?(Numeric)
106
+
107
+ raise ArgumentError.new(
108
+ "cannot turn #{o.inspect} to a point in time, doesn't make sense"
109
+ ) unless t.is_a?(Time)
110
+
111
+ t
112
+ end
113
+
114
+ DURATIONS2M = [
115
+ [ 'y', 365 * 24 * 3600 * 1000 ],
116
+ [ 'M', 30 * 24 * 3600 * 1000 ],
117
+ [ 'w', 7 * 24 * 3600 * 1000 ],
118
+ [ 'd', 24 * 3600 * 1000 ],
119
+ [ 'h', 3600 * 1000 ],
120
+ [ 'm', 60 * 1000 ],
121
+ [ 's', 1000 ]
122
+ ]
123
+ DURATIONS2 = DURATIONS2M.dup
124
+ DURATIONS2.delete_at(1)
125
+
126
+ DURATIONS = DURATIONS2M.inject({}) { |r, (k, v)| r[k] = v; r }
127
+ DURATION_LETTERS = DURATIONS.keys.join
128
+
129
+ DU_KEYS = DURATIONS2M.collect { |k, v| k.to_sym }
130
+
131
+ # Turns a string like '1m10s' into a float like '70.0', more formally,
132
+ # turns a time duration expressed as a string into a Float instance
133
+ # (millisecond count).
134
+ #
135
+ # w -> week
136
+ # d -> day
137
+ # h -> hour
138
+ # m -> minute
139
+ # s -> second
140
+ # M -> month
141
+ # y -> year
142
+ # 'nada' -> millisecond
143
+ #
144
+ # Some examples:
145
+ #
146
+ # Rufus::Scheduler.parse_duration "0.5" # => 0.5
147
+ # Rufus::Scheduler.parse_duration "500" # => 0.5
148
+ # Rufus::Scheduler.parse_duration "1000" # => 1.0
149
+ # Rufus::Scheduler.parse_duration "1h" # => 3600.0
150
+ # Rufus::Scheduler.parse_duration "1h10s" # => 3610.0
151
+ # Rufus::Scheduler.parse_duration "1w2d" # => 777600.0
152
+ #
153
+ # Negative time strings are OK (Thanks Danny Fullerton):
154
+ #
155
+ # Rufus::Scheduler.parse_duration "-0.5" # => -0.5
156
+ # Rufus::Scheduler.parse_duration "-1h" # => -3600.0
157
+ #
158
+ def self.parse_duration(string, quiet = false)
159
+ string = string.to_s
160
+
161
+ return 0 if string == ''
162
+
163
+ m = string.match(/^(-?)([\d\.#{DURATION_LETTERS}]+)$/)
164
+
165
+ return nil if m.nil? && quiet
166
+ raise ArgumentError.new("cannot parse '#{string}'") if m.nil?
167
+
168
+ mod = m[1] == '-' ? -1.0 : 1.0
169
+ val = 0.0
170
+
171
+ s = m[2]
172
+
173
+ while s.length > 0
174
+ m = nil
175
+ if m = s.match(/^(\d+|\d+\.\d*|\d*\.\d+)([#{DURATION_LETTERS}])(.*)$/)
176
+ val += m[1].to_f * DURATIONS[m[2]]
177
+ elsif s.match(/^\d+$/)
178
+ val += s.to_i
179
+ elsif s.match(/^\d*\.\d*$/)
180
+ val += s.to_f
181
+ elsif quiet
182
+ return nil
183
+ else
184
+ raise ArgumentError.new(
185
+ "cannot parse '#{string}' (unexpected '#{s}')"
186
+ )
187
+ end
188
+ break unless m && m[3]
189
+ s = m[3]
190
+ end
191
+
192
+ res = mod * val
193
+ res.to_i
194
+ end
195
+
196
+
197
+ # Turns a number of seconds into a a time string
198
+ #
199
+ # Rufus.to_duration 0 # => '0s'
200
+ # Rufus.to_duration 60 # => '1m'
201
+ # Rufus.to_duration 3661 # => '1h1m1s'
202
+ # Rufus.to_duration 7 * 24 * 3600 # => '1w'
203
+ # Rufus.to_duration 30 * 24 * 3600 + 1 # => "4w2d1s"
204
+ #
205
+ # It goes from seconds to the year. Months are not counted (as they
206
+ # are of variable length). Weeks are counted.
207
+ #
208
+ # For 30 days months to be counted, the second parameter of this
209
+ # method can be set to true.
210
+ #
211
+ # Rufus.to_duration 30 * 24 * 3600 + 1, true # => "1M1s"
212
+ #
213
+ # If a Float value is passed, milliseconds will be displayed without
214
+ # 'marker'
215
+ #
216
+ # Rufus.to_duration 0.051 # => "51"
217
+ # Rufus.to_duration 7.051 # => "7s51"
218
+ # Rufus.to_duration 0.120 + 30 * 24 * 3600 + 1 # => "4w2d1s120"
219
+ #
220
+ # (this behaviour mirrors the one found for parse_time_string()).
221
+ #
222
+ # Options are :
223
+ #
224
+ # * :months, if set to true, months (M) of 30 days will be taken into
225
+ # account when building up the result
226
+ # * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
227
+ # from the result
228
+ #
229
+ def self.to_duration(seconds, options = {})
230
+ h = to_duration_hash(seconds, options)
231
+
232
+ return (options[:drop_seconds] ? '0m' : '0s') if h.empty?
233
+
234
+ s = DU_KEYS.inject(String.new) { |r, key|
235
+ count = h[key]
236
+ count = nil if count == 0
237
+ r << "#{count}#{key}" if count
238
+ r
239
+ }
240
+
241
+ ms = h[:ms]
242
+ s << ms.to_s if ms
243
+ s
244
+ end
245
+
246
+ # Turns a number of seconds (integer or Float) into a hash like in :
247
+ #
248
+ # Rufus.to_duration_hash 0.051
249
+ # # => { :ms => "51" }
250
+ # Rufus.to_duration_hash 7.051
251
+ # # => { :s => 7, :ms => "51" }
252
+ # Rufus.to_duration_hash 0.120 + 30 * 24 * 3600 + 1
253
+ # # => { :w => 4, :d => 2, :s => 1, :ms => "120" }
254
+ #
255
+ # This method is used by to_duration behind the scenes.
256
+ #
257
+ # Options are :
258
+ #
259
+ # * :months, if set to true, months (M) of 30 days will be taken into
260
+ # account when building up the result
261
+ # * :drop_seconds, if set to true, seconds and milliseconds will be trimmed
262
+ # from the result
263
+ #
264
+ def self.to_duration_hash(seconds, options = {})
265
+ h = {}
266
+
267
+ if (seconds % 1000) > 0
268
+ h[:ms] = (seconds % 1000).to_i
269
+ seconds = (seconds / 1000).to_i * 1000
270
+ end
271
+
272
+ if options[:drop_seconds]
273
+ h.delete(:ms)
274
+ seconds = (seconds - seconds % 60000)
275
+ end
276
+
277
+ durations = options[:months] ? DURATIONS2M : DURATIONS2
278
+
279
+ durations.each do |key, duration|
280
+ count = seconds / duration
281
+ seconds = seconds % duration
282
+
283
+ h[key.to_sym] = count if count > 0
284
+ end
285
+
286
+ h
287
+ end
288
+
289
+ #--
290
+ # misc
291
+ #++
292
+
293
+ # Produces the UTC string representation of a Time instance
294
+ #
295
+ # like "2009/11/23 11:11:50.947109 UTC"
296
+ #
297
+ def self.utc_to_s(t=Time.now)
298
+ "#{t.utc.strftime('%Y-%m-%d %H:%M:%S')}.#{sprintf('%06d', t.usec)} UTC"
299
+ end
300
+
301
+ # Produces a hour/min/sec/milli string representation of Time instance
302
+ #
303
+ def self.h_to_s(t=Time.now)
304
+ "#{t.strftime('%H:%M:%S')}.#{sprintf('%06d', t.usec)}"
305
+ end
306
+ end
307
+ end