fugit 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: db0fd5566944d325bda3692e5ca32819d7f0b8d8
4
- data.tar.gz: 226e4f9ad3e97a40c17619e9be38f2b2ff408c83
3
+ metadata.gz: a5457b3ed0c40bebd7f6725f5884ba0894f61c2c
4
+ data.tar.gz: c1daf99e24e3d241d3ccd4bd591e308b487ecc13
5
5
  SHA512:
6
- metadata.gz: 6af1fa57a2484c9c62a3a7f73a65be6d12b579501efdb3c479f8e1868d73afab2b8e544d9d7904834558bab5d6f93e2ce53588ba4a46e2c64868fe4255d77634
7
- data.tar.gz: b3be693935fd379a0e9270194600bcfe2210b2bf3b969596b2f476285632729bf3f0e320029c8e398d1f524c240432acc5f15899d6ad1365c0cddd63297fa82f
6
+ metadata.gz: 8ca834e48c23d1cabae7589ccf2292caf250bc0fc2e7fdaa8e4dd9a431ebf97d62aa08cbf2eacf178ae7cf97a816869b9caf023dfd0b24f0e30c55a56e232cf8
7
+ data.tar.gz: e16216f72f97619d86c47c1be9502ff854785751091fd99b9829820bc087a260fdd60a02aef1a27ed12f6d0d5439bad361a99847b96f1d6d15d08a8a5dde1d71
@@ -2,6 +2,11 @@
2
2
  # fugit CHANGELOG.md
3
3
 
4
4
 
5
+ ## fugit 0.9.4 released 2017-01-06
6
+
7
+ * Accept cron strings with seconds
8
+
9
+
5
10
  ## fugit 0.9.3 released 2017-01-05
6
11
 
7
12
  * First version of Fugit::Nat
@@ -25,7 +25,7 @@
25
25
 
26
26
  module Fugit
27
27
 
28
- VERSION = '0.9.3'
28
+ VERSION = '0.9.4'
29
29
  end
30
30
 
31
31
  require 'time'
@@ -51,12 +51,13 @@ module Fugit
51
51
 
52
52
  @cron_s ||=
53
53
  [
54
+ @seconds == [ 0 ] ? nil : (@seconds || [ '*' ]).join(','),
54
55
  (@minutes || [ '*' ]).join(','),
55
56
  (@hours || [ '*' ]).join(','),
56
57
  (@monthdays || [ '*' ]).join(','),
57
58
  (@months || [ '*' ]).join(','),
58
59
  (@weekdays || [ [ '*' ] ]).map { |d| d.compact.join('#') }.join(',')
59
- ].join(' ')
60
+ ].compact.join(' ')
60
61
  end
61
62
 
62
63
  def self.parse(s)
@@ -86,6 +87,7 @@ module Fugit
86
87
  end
87
88
 
88
89
  def time; @t; end
90
+ def to_i; @t.to_i; end
89
91
 
90
92
  %w[ year month day wday hour min sec ]
91
93
  .collect(&:to_sym).each { |k| define_method(k) { @t.send(k) } }
@@ -109,13 +111,25 @@ module Fugit
109
111
  def inc_hour; inc((60 - @t.min) * 60 - @t.sec); end
110
112
  def inc_min; inc(60 - @t.sec); end
111
113
 
114
+ def inc_sec(seconds)
115
+ if s = seconds.find { |s| s > @t.sec }
116
+ inc(s - @t.sec)
117
+ else
118
+ inc(60 - @t.sec + seconds.first)
119
+ end
120
+ end
121
+
112
122
  def dec_month
113
123
  dec(@t.day * 24 * 3600 + @t.hour * 3600 + @t.min * 60 + @t.sec + 1)
114
124
  end
115
125
  def dec_day; dec(@t.hour * 3600 + @t.min * 60 + @t.sec + 1); end
116
126
  def dec_hour; dec(@t.min * 60 + @t.sec + 1); end
117
127
  def dec_min; dec(@t.sec + 1); end
118
- def dec_sec; dec(@t.sec); end
128
+
129
+ def dec_sec(seconds)
130
+ target = seconds.reverse.find { |s| s < @t.sec } || seconds.last
131
+ inc(target - @t.sec)
132
+ end
119
133
 
120
134
  def count_weeks(inc)
121
135
  c = 0
@@ -135,11 +149,10 @@ module Fugit
135
149
  def month_match?(nt); ( ! @months) || @months.include?(nt.month); end
136
150
  def hour_match?(nt); ( ! @hours) || @hours.include?(nt.hour); end
137
151
  def min_match?(nt); ( ! @minutes) || @minutes.include?(nt.min); end
152
+ def sec_match?(nt); ( ! @seconds) || @seconds.include?(nt.sec); end
138
153
 
139
154
  def weekday_match?(nt)
140
155
 
141
- #p @weekdays
142
- #p [ nt.day, nt.wday ]
143
156
  return true if @weekdays.nil?
144
157
 
145
158
  wd, hsh = @weekdays.find { |wd, hsh| wd == nt.wday }
@@ -183,7 +196,8 @@ module Fugit
183
196
  t = Fugit.do_parse_at(t)
184
197
  t = NextTime.new(t)
185
198
 
186
- month_match?(t) && day_match?(t) && hour_match?(t) && min_match?(t)
199
+ month_match?(t) && day_match?(t) &&
200
+ hour_match?(t) && min_match?(t) && sec_match?(t)
187
201
  end
188
202
 
189
203
  def next_time(from=Time.now)
@@ -191,11 +205,13 @@ module Fugit
191
205
  nt = NextTime.new(from)
192
206
 
193
207
  loop do
194
- #p Fugit.time_to_s(nt.time)
208
+ #p [ :l, Fugit.time_to_s(nt.time) ]
209
+ (from.to_i == nt.to_i) && (nt.inc(1); next)
195
210
  month_match?(nt) || (nt.inc_month; next)
196
211
  day_match?(nt) || (nt.inc_day; next)
197
212
  hour_match?(nt) || (nt.inc_hour; next)
198
213
  min_match?(nt) || (nt.inc_min; next)
214
+ sec_match?(nt) || (nt.inc_sec(@seconds); next)
199
215
  break
200
216
  end
201
217
 
@@ -207,42 +223,58 @@ module Fugit
207
223
  nt = NextTime.new(from)
208
224
 
209
225
  loop do
210
- #p Fugit.time_to_s(nt.time)
226
+ #p [ :l, Fugit.time_to_s(nt.time) ]
227
+ (from.to_i == nt.to_i) && (nt.inc(-1); next)
211
228
  month_match?(nt) || (nt.dec_month; next)
212
229
  day_match?(nt) || (nt.dec_day; next)
213
230
  hour_match?(nt) || (nt.dec_hour; next)
214
231
  min_match?(nt) || (nt.dec_min; next)
215
- nt.dec_sec
232
+ sec_match?(nt) || (nt.dec_sec(@seconds); next)
216
233
  break
217
234
  end
218
235
 
219
236
  nt.time
220
237
  end
221
238
 
222
- # Returns [ min delta, max delta, occurence count ]
223
- # Computes for a non leap year (2017).
239
+ # Mostly used as a #next_time sanity check.
240
+ # Avoid for "business" use, it's slow.
241
+ #
242
+ # 2017 is non leap year (though it is preceded by a leap second)
243
+ #
244
+ # Nota bene: cron with seconds are not supported.
224
245
  #
225
246
  def brute_frequency(year=2017)
226
247
 
227
248
  FREQUENCY_CACHE["#{to_cron_s}|#{year}"] ||=
228
249
  begin
250
+
229
251
  deltas = []
230
252
 
253
+ t = Time.parse("#{year}-01-01") - 1
231
254
  t0 = nil
255
+ t1 = nil
232
256
  loop do
233
- t1 = next_time(t0 || Time.parse("#{year}-01-01"))
234
- deltas << (t1 - t0).to_i + 60 if t0
235
- break if t1.year > year
236
- t0 = t1 + 60
257
+ t1 = next_time(t)
258
+ deltas << (t1 - t).to_i if t0
259
+ t0 ||= t1
260
+ break if deltas.any? && t1.year > year
261
+ break if t1.year - t0.year > 7
262
+ t = t1
237
263
  end
238
264
 
239
- [ deltas.min, deltas.max, deltas.size ]
265
+ occurences = deltas.size
266
+ span = t1 - t0
267
+ span_years = span / (365 * 24 * 3600)
268
+ yearly_occurences = occurences.to_f / span_years
269
+
270
+ [ deltas.min, deltas.max, occurences,
271
+ span.to_i, span_years.to_i, yearly_occurences.to_i ]
240
272
  end
241
273
  end
242
274
 
243
275
  def to_a
244
276
 
245
- [ @minutes, @hours, @monthdays, @months, @weekdays ]
277
+ [ @seconds, @minutes, @hours, @monthdays, @months, @weekdays ]
246
278
  end
247
279
 
248
280
  def ==(o)
@@ -263,9 +295,9 @@ module Fugit
263
295
  def init(original, h)
264
296
 
265
297
  @original = original
298
+ @cron_s = nil # just to be sure
266
299
 
267
- h ||= {}
268
-
300
+ determine_seconds(h[:sec])
269
301
  determine_minutes(h[:min])
270
302
  determine_hours(h[:hou])
271
303
  determine_monthdays(h[:dom])
@@ -303,53 +335,53 @@ module Fugit
303
335
  arr.sort!
304
336
  end
305
337
 
306
- def determine_minutes(mins)
307
- return @minutes = nil unless mins
308
- @minutes = mins.inject([]) { |a, r| a.concat(expand(0, 59, r)) }
338
+ def determine_seconds(a)
339
+ @seconds = (a || [ 0 ]).inject([]) { |a, r| a.concat(expand(0, 59, r)) }
340
+ compact(:@seconds)
341
+ end
342
+
343
+ def determine_minutes(a)
344
+ @minutes = a.inject([]) { |a, r| a.concat(expand(0, 59, r)) }
309
345
  compact(:@minutes)
310
346
  end
311
347
 
312
- def determine_hours(hous)
313
- return @hours = nil unless hous
314
- @hours = hous.inject([]) { |a, r| a.concat(expand(0, 23, r)) }
348
+ def determine_hours(a)
349
+ @hours = a.inject([]) { |a, r| a.concat(expand(0, 23, r)) }
315
350
  @hours = @hours.collect { |h| h == 24 ? 0 : h }
316
351
  compact(:@hours)
317
352
  end
318
353
 
319
- def determine_monthdays(doms)
320
- return @monthdays = nil unless doms
321
- @monthdays = doms.inject([]) { |a, r| a.concat(expand(1, 31, r)) }
354
+ def determine_monthdays(a)
355
+ @monthdays = a.inject([]) { |a, r| a.concat(expand(1, 31, r)) }
322
356
  compact(:@monthdays)
323
357
  end
324
358
 
325
- def determine_months(mons)
326
- return @months = nil unless mons
327
- @months = mons.inject([]) { |a, r| a.concat(expand(1, 12, r)) }
359
+ def determine_months(a)
360
+ @months = a.inject([]) { |a, r| a.concat(expand(1, 12, r)) }
328
361
  compact(:@months)
329
362
  end
330
363
 
331
- def determine_weekdays(dows)
332
-
333
- return @weekdays = nil unless dows
334
-
335
- @weekdays = dows.inject([]) { |a, r|
336
- aa = expand(0, 7, r)
337
- if hsh = r[3]
338
- a.concat([ [ aa.first, hsh ] ])
339
- else
340
- a.concat(aa.collect { |i| [ i, nil ] })
364
+ def determine_weekdays(a)
365
+
366
+ @weekdays = []
367
+
368
+ a.each do |a, z, s, h| # a to z, slash and hash
369
+ if h
370
+ @weekdays << [ a, h ]
371
+ elsif s
372
+ ((a || 0)..(z || (a ? a : 6))).step(s < 1 ? 1 : s)
373
+ .each { |i| @weekdays << [ i ] }
374
+ elsif z
375
+ (a..z).each { |i| @weekdays << [ i ] }
376
+ elsif a
377
+ @weekdays << [ a ]
378
+ #else
341
379
  end
342
- }
380
+ end
343
381
 
344
- @weekdays =
345
- if @weekdays.include?([ nil, nil ])
346
- nil
347
- else
348
- @weekdays
349
- .collect { |d, h| [ d == 7 ? 0 : d, h ] }
350
- .uniq { |d| d.join('#') }
351
- .sort_by { |d| d.join('#') }
352
- end
382
+ @weekdays.each { |wd| wd[0] = 0 if wd[0] == 7 } # turn sun7 into sun0
383
+ @weekdays.uniq!
384
+ @weekdays = nil if @weekdays.empty?
353
385
  end
354
386
 
355
387
  module Parser include Raabro
@@ -361,14 +393,14 @@ module Fugit
361
393
 
362
394
  # piece parsers bottom to top
363
395
 
364
- def s(i); rex(:s, i, /[ \t]+/); end
365
- def star(i); str(:star, i, '*'); end
396
+ def s(i); rex(nil, i, /[ \t]+/); end
397
+ def star(i); str(nil, i, '*'); end
366
398
  def hyphen(i); str(nil, i, '-'); end
367
399
  def comma(i); str(nil, i, ','); end
368
400
 
369
401
  def slash(i); rex(:slash, i, /\/\d\d?/); end
370
402
 
371
- def core_min(i); rex(:min, i, /[0-5]?\d/); end
403
+ def core_mos(i); rex(:mos, i, /[0-5]?\d/); end # min or sec
372
404
  def core_hou(i); rex(:hou, i, /(2[0-4]|[01]?[0-9])/); end
373
405
  def core_dom(i); rex(:dom, i, /(-?(3[01]|[012]?[0-9])|last|l)/i); end
374
406
  def core_mon(i); rex(:mon, i, /(1[0-2]|0?[0-9]|#{MONTHS[1..-1].join('|')})/i); end
@@ -376,56 +408,67 @@ module Fugit
376
408
 
377
409
  def dow_hash(i); rex(:hash, i, /#(-?[1-5]|last|l)/i); end
378
410
 
379
- def min(i); core_min(i); end
411
+ def mos(i); core_mos(i); end
380
412
  def hou(i); core_hou(i); end
381
413
  def dom(i); core_dom(i); end
382
414
  def mon(i); core_mon(i); end
383
415
  def dow(i); core_dow(i); end
384
416
 
385
- def _min(i); seq(nil, i, :hyphen, :min); end
417
+ def _mos(i); seq(nil, i, :hyphen, :mos); end
386
418
  def _hou(i); seq(nil, i, :hyphen, :hou); end
387
419
  def _dom(i); seq(nil, i, :hyphen, :dom); end
388
420
  def _mon(i); seq(nil, i, :hyphen, :mon); end
389
421
  def _dow(i); seq(nil, i, :hyphen, :dow); end
390
422
 
391
423
  # r: range
392
- def r_min(i); seq(nil, i, :min, :_min, '?'); end
424
+ def r_mos(i); seq(nil, i, :mos, :_mos, '?'); end
393
425
  def r_hou(i); seq(nil, i, :hou, :_hou, '?'); end
394
426
  def r_dom(i); seq(nil, i, :dom, :_dom, '?'); end
395
427
  def r_mon(i); seq(nil, i, :mon, :_mon, '?'); end
396
428
  def r_dow(i); seq(nil, i, :dow, :_dow, '?'); end
397
429
 
398
430
  # sor: star or range
399
- def sor_min(i); alt(nil, i, :star, :r_min); end
431
+ def sor_mos(i); alt(nil, i, :star, :r_mos); end
400
432
  def sor_hou(i); alt(nil, i, :star, :r_hou); end
401
433
  def sor_dom(i); alt(nil, i, :star, :r_dom); end
402
434
  def sor_mon(i); alt(nil, i, :star, :r_mon); end
403
435
  def sor_dow(i); alt(nil, i, :star, :r_dow); end
404
436
 
405
437
  # sorws: star or range with[out] slash
406
- def sorws_min(i); seq(nil, i, :sor_min, :slash, '?'); end
407
- def sorws_hou(i); seq(nil, i, :sor_hou, :slash, '?'); end
408
- def sorws_dom(i); seq(nil, i, :sor_dom, :slash, '?'); end
409
- def sorws_mon(i); seq(nil, i, :sor_mon, :slash, '?'); end
410
- def sorws_dow(i); seq(nil, i, :sor_dow, :slash, '?'); end
438
+ def sorws_mos(i); seq(:elt, i, :sor_mos, :slash, '?'); end
439
+ def sorws_hou(i); seq(:elt, i, :sor_hou, :slash, '?'); end
440
+ def sorws_dom(i); seq(:elt, i, :sor_dom, :slash, '?'); end
441
+ def sorws_mon(i); seq(:elt, i, :sor_mon, :slash, '?'); end
442
+ def sorws_dow(i); seq(:elt, i, :sor_dow, :slash, '?'); end
411
443
 
412
- def h_dow(i); seq(nil, i, :core_dow, :dow_hash); end
444
+ def h_dow(i); seq(:elt, i, :core_dow, :dow_hash); end
413
445
 
414
446
  def _sorws_dow(i); alt(nil, i, :h_dow, :sorws_dow); end
415
447
 
416
- def list_min(i); jseq(:min, i, :sorws_min, :comma); end
448
+ def list_sec(i); jseq(:sec, i, :sorws_mos, :comma); end
449
+ def list_min(i); jseq(:min, i, :sorws_mos, :comma); end
417
450
  def list_hou(i); jseq(:hou, i, :sorws_hou, :comma); end
418
451
  def list_dom(i); jseq(:dom, i, :sorws_dom, :comma); end
419
452
  def list_mon(i); jseq(:mon, i, :sorws_mon, :comma); end
420
453
  def list_dow(i); jseq(:dow, i, :_sorws_dow, :comma); end
421
454
 
455
+ def lsec_(i); seq(nil, i, :list_sec, :s); end
422
456
  def lmin_(i); seq(nil, i, :list_min, :s); end
423
457
  def lhou_(i); seq(nil, i, :list_hou, :s); end
424
458
  def ldom_(i); seq(nil, i, :list_dom, :s); end
425
459
  def lmon_(i); seq(nil, i, :list_mon, :s); end
426
460
  alias ldow list_dow
427
461
 
428
- def cron(i); seq(:cron, i, :lmin_, :lhou_, :ldom_, :lmon_, :ldow); end
462
+ def classic_cron(i)
463
+ seq(:ccron, i, :lmin_, :lhou_, :ldom_, :lmon_, :ldow)
464
+ end
465
+ def second_cron(i)
466
+ seq(:scron, i, :lsec_, :lmin_, :lhou_, :ldom_, :lmon_, :ldow)
467
+ end
468
+
469
+ def cron(i)
470
+ alt(:cron, i, :second_cron, :classic_cron)
471
+ end
429
472
 
430
473
  # rewriting the parsed tree
431
474
 
@@ -435,40 +478,42 @@ module Fugit
435
478
 
436
479
  (k == :mon && MONTHS.index(s)) ||
437
480
  (k == :dow && WEEKDS.index(s)) ||
438
- (k == :dom && s[0, 1] == 'l' && -1) || # L, l, last
481
+ ((k == :dom) && s[0, 1] == 'l' && -1) || # L, l, last
439
482
  s.to_i
440
483
  end
441
484
 
442
- def rewrite_entry(t)
443
-
444
- k = t.name
485
+ def rewrite_elt(k, t)
445
486
 
446
- t.children.select { |ct| ct.children.any? }.inject([]) { |a, ct|
487
+ (a, z), others = t
488
+ .subgather(nil)
489
+ .partition { |tt| ![ :hash, :slash ].include?(tt.name) }
490
+ s = others.find { |tt| tt.name == :slash }
491
+ h = others.find { |tt| tt.name == :hash }
447
492
 
448
- xts = ct.gather(k)
449
- #xts.each { |xt| Raabro.pp(xt) }
450
- range = xts.any? ? xts.collect { |xt| to_i(k, xt) } : []
451
- while range.size < 2; range << nil; end
493
+ h = h ? h.string[1..-1] : nil
494
+ h = -1 if h && h.upcase[0, 1] == 'L'
495
+ h = h.to_i if h
452
496
 
453
- st = ct.lookup(:slash)
454
- range << (st ? st.string[1..-1].to_i : nil)
497
+ a = a ? to_i(k, a) : nil
498
+ z = z ? to_i(k, z) : nil
499
+ a, z = z, a if a && z && a > z
455
500
 
456
- if k == :dow && ht = ct.lookup(:hash)
457
- hs = ht.string.downcase
458
- range << ((hs[1, 1] == 'l') ? -1 : hs[1..-1].to_i)
459
- end
501
+ [ a, z, s ? s.string[1..-1].to_i : nil, h ]
502
+ end
460
503
 
461
- a << range
504
+ def rewrite_entry(t)
462
505
 
463
- a
464
- }
506
+ t
507
+ .subgather(:elt)
508
+ .collect { |et| rewrite_elt(t.name, et) }
465
509
  end
466
510
 
467
- SYMS = %w[ min hou dom mon dow ].collect(&:to_sym)
468
-
469
511
  def rewrite_cron(t)
470
512
 
471
- SYMS.inject({}) { |h, k| h[k] = rewrite_entry(t.lookup(k)); h }
513
+ t
514
+ .sublookup(nil) # go to :ccron or :scron
515
+ .subgather(nil) # list min, hou, mon, ...
516
+ .inject({}) { |h, tt| h[tt.name] = rewrite_entry(tt); h }
472
517
  end
473
518
  end
474
519
  end
@@ -146,7 +146,7 @@ module Fugit
146
146
 
147
147
  id = inflate
148
148
  h = id.h.dup
149
- s = h.delete(:sec)
149
+ s = h.delete(:sec) || 0
150
150
 
151
151
  INFLA_KEYS.each do |k, v|
152
152
 
@@ -45,12 +45,12 @@ module Fugit
45
45
 
46
46
  def self.time_to_plain_s(t=Time.now)
47
47
 
48
- s = StringIO.new
48
+ t.strftime('%Y-%m-%d %H:%M:%S') + (t.utc? ? ' Z' : '')
49
+ end
49
50
 
50
- s << t.strftime('%Y-%m-%d %H:%M:%S')
51
- s << ' Z' if t.utc?
51
+ def self.time_to_zone_s(t=Time.now)
52
52
 
53
- s.string
53
+ t.strftime('%Y-%m-%d %H:%M:%S %Z %z')
54
54
  end
55
55
  end
56
56
 
@@ -47,23 +47,24 @@ module Fugit
47
47
 
48
48
  def self.parse_cron(a)
49
49
 
50
- h = { min: nil, hou: nil, dom: nil, mon: nil, dow: nil }
50
+ h = { min: nil, hou: [], dom: [ nil ], mon: [ nil ], dow: [ nil ] }
51
51
 
52
52
  a.each do |key, val|
53
53
  if key == :biz_day
54
- h[:dow] = (1..5).to_a.collect { |wd| [ wd ] }
54
+ h[:dow] = [ [ 1, 5 ] ]
55
55
  elsif key == :simple_hour || key == :numeral_hour
56
- (h[:hou] ||= []) << val
56
+ (h[:hou] ||= []) << [ val ]
57
57
  elsif key == :digital_hour
58
- h[:hou] = val[0, 1]
59
- h[:min] = val[1, 1]
58
+ h[:hou] = [ val[0, 1] ]
59
+ h[:min] = [ val[1, 1] ]
60
60
  elsif key == :name_day
61
61
  (h[:dow] ||= []) << [ val ]
62
62
  elsif key == :flag && val == 'pm' && h[:hou]
63
- h[:hou][-1] = h[:hou][-1] + 12
63
+ h[:hou][-1] = [ h[:hou][-1].first + 12 ]
64
64
  end
65
65
  end
66
66
  h[:min] ||= [ 0 ]
67
+ h[:dow].sort_by! { |a, z| a || 0 }
67
68
 
68
69
  Fugit::Cron.allocate.send(:init, nil, h)
69
70
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fugit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-04 00:00:00.000000000 Z
11
+ date: 2017-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: raabro