fugit 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fugit might be problematic. Click here for more details.

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