uv-rays 2.3.0 → 2.3.1

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.
@@ -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