fugit 1.12.3 → 1.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f588451db0cf7643afd0ecd89313863b4ca89913872547f0dd8342343fec1b57
4
- data.tar.gz: a0832d2aecbe4b158a3deef01ac7c230cd8de3ff2c3dc5a1da4e871a516d27c6
3
+ metadata.gz: 11380138d493b9ed80a43bffc6a61f74de5a2c52132ae2b9746c8097b3f8015a
4
+ data.tar.gz: 40ec86bcc48074cc6d3a5bc02b7c2ae84ba3f9fc505104373fc83c7c984ec04b
5
5
  SHA512:
6
- metadata.gz: 5fca6043aef60a7c895b991f364714f1d26f3ef0922d477fc624a4f4cdc51dc948542fca4638567e2416fa4ff4c75e267f03991d7624f2515745d8e8be203314
7
- data.tar.gz: 8ddb37f7d0f961dc341757fff83ef1cf844df7a7ffc7aaedc1eed0dca6fea4be217029e2a266cb8ce774303e174f4e27713854b4058cf6f12b3c2aa6eb78d1ca
6
+ metadata.gz: dbd303863f53f7fbf39544fe914e48226952ff4e5983769e7bf932d8a92fdae67514460363f0a1921c77d9dfd7431539935ea18383e3187e103770f46eeeba78
7
+ data.tar.gz: b558ec5b070e2119d5ed0b21f840afd375f2b1eed95ef4542bd78d17dc026402d17c890163f8f9b3e08f8899d01ff08f2d4d3b1baece4d0c5af0e56d72e6d3d9
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
  # CHANGELOG.md
3
3
 
4
4
 
5
+ ## fugit 1.14.0 released 2026-09-14
6
+
7
+ * Reject input when length > 256
8
+
9
+
10
+ ## fugit 1.13.0 released 2026-07-10
11
+
12
+ * Random values support in cron string `"10 ~ * * *"` gh-121 Nicols Bachschmidt
13
+
14
+
5
15
  ## fugit 1.12.3 released 2026-07-01
6
16
 
7
17
  * Wrap-around for weekday ranges with step value, gh-119 Nicolas Bachschmidt
data/CREDITS.md CHANGED
@@ -1,6 +1,7 @@
1
1
 
2
2
  # fugit credits
3
3
 
4
+ * Yaroslav Kurbatov https://github.com/viralpraxis input max length
4
5
  * Nicolas Bachschmidt https://github.com/baarde gh-120 weekday wrap fix
5
6
  * JebeenLee https://github.com/JebeenLee gh-117 divide by zero
6
7
  * Eric Claerhout https://github.com/swebra gh-114 rweek readme clarity
@@ -8,7 +9,7 @@
8
9
  * Mark R. James, https://github.com/mrj, AM vs America/Los_Angeles, gh-113
9
10
  * Tejas Bubane, https://github.com/tejasbubane, r3.4 in test matrix, gh-109
10
11
  * Luis Castillo, https://github.com/lekastillo, nice_hash gh-108
11
- * Geremia Taglialatela, https://github.com/tagliala, gh-105 gh-107
12
+ * Geremia Taglialatela, https://github.com/tagliala, gh-105 gh-107 gh-122
12
13
  * https://github.com/personnumber3377, gh-104 Fugit.parse choke on long input
13
14
  * Michael Scrivo, https://github.com/mscrivo, gh-103
14
15
  * Benjamin Darcet, https://github.com/bdarcet gh-95 gh-96 et-orbi #rweek
@@ -34,7 +35,7 @@
34
35
  * Niklas https://github.com/gr8bit gh-49, Fugit::Cron.parse('')
35
36
  * Matsuda Akira https://github.com/amatsuda gh-46, warning suppression
36
37
  * Honglooker https://github.com/honglooker gh-43, New York cron skip
37
- * Jérôme Dalbert https://github.com/jeromedalbert gh-41, gh-42
38
+ * Jérôme Dalbert https://github.com/jeromedalbert gh-41, gh-42, gh-123
38
39
  * Danny Ben Shitrit https://github.com/DannyBen nat variants, gh-38
39
40
  * Dominik Sander https://github.com/dsander #rough_frequency 0, gh-36
40
41
  * Milovan Zogovic https://github.com/assembler Cron#match? vs TZ, gh-31
data/README.md CHANGED
@@ -486,6 +486,29 @@ Here's the output:
486
486
  ```
487
487
 
488
488
 
489
+ ### the random extension
490
+
491
+ Fugit accepts the `~` character to specify a range from which a random value is picked. Either or both the start and the end of the range may be omitted.
492
+
493
+ ```ruby
494
+ '~ * * * *' # every hour on a random minute
495
+ '~29 * * * *' # every hour on a random minute between 0 and 29
496
+ '30~ * * * *' # every hour on a random minute between 30 and 59
497
+ '~/10 * * * *' # every 10 minutes starting on a random minute between 0 and 9
498
+ '0 12 * * 1~5' # every week at noon on a random workday
499
+ ```
500
+
501
+ You may customize how random values are generated by adding the `:random` option with a boolean or an object that implements the `#rand` method.
502
+
503
+ ```ruby
504
+ Fugit.parse('~ * * * *', random: false) # on a non-random minute ==> '0 * * * *'
505
+ Fugit.parse('~ * * * *', random: true) # on a random minute (default)
506
+ Fugit.parse('~ * * * *', random: SecureRandom) # on a cryptographically secure random minute
507
+ ```
508
+
509
+ Please note that the random values are determined at parse time. So `"~29 * * * *"` at parse time could become `"17 * * * *"` for example and go on triggering every hour at minute 17, until a new parsing occurs and another (or the same) minute is picked. This aligns with the OpenBSD [`man 5 crontab`](https://man.openbsd.org/crontab.5), OpenBSD `crond` rolling the dice at load time.
510
+
511
+
489
512
  ### the second extension
490
513
 
491
514
  Fugit accepts cron strings with five elements, `minute hour day-of-month month day-of-week`, the standard cron format or six elements `second minute hour day-of-month month day-of-week`.
data/fugit.gemspec CHANGED
@@ -43,8 +43,11 @@ Time tools for flor and the floraison project. Cron parsing and occurrence compu
43
43
  s.add_runtime_dependency 'raabro', '~> 1.4'
44
44
  s.add_runtime_dependency 'et-orbi', '~> 1.4'
45
45
 
46
- s.add_development_dependency 'rspec', '~> 3.8'
46
+ #s.add_development_dependency 'rspec', '~> 3.8'
47
+ s.add_development_dependency 'probatio', '~> 1.6'
48
+
47
49
  s.add_development_dependency 'chronic', '~> 0.10'
50
+ s.add_development_dependency 'ostruct'
48
51
 
49
52
  s.require_path = 'lib'
50
53
  end
data/lib/fugit/cron.rb CHANGED
@@ -29,7 +29,7 @@ module Fugit
29
29
  parse(original)
30
30
  end
31
31
 
32
- def parse(s)
32
+ def parse(s, opts={})
33
33
 
34
34
  return s if s.is_a?(self)
35
35
  return nil unless s.is_a?(String)
@@ -37,6 +37,16 @@ module Fugit
37
37
  s0 = s
38
38
  s = s.strip
39
39
 
40
+ if s.length > ::Fugit::MAX_INPUT_LENGTH
41
+
42
+ fail ArgumentError.new(
43
+ 'input too long for a cron string, ' +
44
+ "#{s.length} > #{MAX_INPUT_LENGTH}"
45
+ ) if opts[:do_parse]
46
+
47
+ return nil
48
+ end
49
+
40
50
  s =
41
51
  if s[0, 1] == '@'
42
52
  ss = s.split(/\s+/, 2)
@@ -48,12 +58,12 @@ module Fugit
48
58
  #p s; Raabro.pp(Parser.parse(s, debug: 3), colors: true)
49
59
  h = Parser.parse(s)
50
60
 
51
- self.allocate.send(:init, s0, h)
61
+ self.allocate.send(:init, s0, h, opts)
52
62
  end
53
63
 
54
- def do_parse(s)
64
+ def do_parse(s, opts={})
55
65
 
56
- parse(s) ||
66
+ parse(s, opts.merge(do_parse: true)) ||
57
67
  fail(ArgumentError.new("invalid cron string #{trunc(s)}"))
58
68
  end
59
69
 
@@ -559,7 +569,7 @@ module Fugit
559
569
 
560
570
  FREQUENCY_CACHE = {}
561
571
 
562
- def init(original, h)
572
+ def init(original, h, opts)
563
573
 
564
574
  return nil unless h
565
575
 
@@ -568,12 +578,12 @@ module Fugit
568
578
  @day_and = h[:&]
569
579
 
570
580
  valid =
571
- determine_seconds(h[:sec]) &&
572
- determine_minutes(h[:min]) &&
573
- determine_hours(h[:hou]) &&
574
- determine_monthdays(h[:dom]) &&
575
- determine_months(h[:mon]) &&
576
- determine_weekdays(h[:dow]) &&
581
+ determine_seconds(h[:sec], opts) &&
582
+ determine_minutes(h[:min], opts) &&
583
+ determine_hours(h[:hou], opts) &&
584
+ determine_monthdays(h[:dom], opts) &&
585
+ determine_months(h[:mon], opts) &&
586
+ determine_weekdays(h[:dow], opts) &&
577
587
  determine_timezone(h[:tz])
578
588
 
579
589
  return nil unless valid
@@ -582,9 +592,9 @@ module Fugit
582
592
  self
583
593
  end
584
594
 
585
- def expand(min, max, r)
595
+ def expand(min, max, opts, r)
586
596
 
587
- sta, edn, sla = r
597
+ sta, edn, sep, sla = r
588
598
 
589
599
  #return false if sla && sla > max
590
600
  #
@@ -593,6 +603,11 @@ module Fugit
593
603
 
594
604
  return false if sla && sla < 1
595
605
 
606
+ if sep == :tilde
607
+ sta = random(min, max, sta, edn, sla, opts)
608
+ edn = nil unless sla
609
+ end
610
+
596
611
  edn = max if sla && edn.nil?
597
612
 
598
613
  return nil if sta.nil? && edn.nil? && sla.nil?
@@ -605,6 +620,24 @@ module Fugit
605
620
  range(min, max, sta, edn, sla)
606
621
  end
607
622
 
623
+ def random(min, max, sta, edn, sla, opts)
624
+
625
+ sta = min if sta.nil?
626
+ edn = max if edn.nil?
627
+
628
+ random = opts.fetch(:random, true)
629
+ random = Random if random == true
630
+ return sta unless random
631
+
632
+ n = edn - sta + 1
633
+ n = max - min + 1 + n if n <= 0
634
+ n = sla if sla && sla < n
635
+
636
+ r = sta + random.rand(n)
637
+ r = r + min - max - 1 if r > max
638
+ r
639
+ end
640
+
608
641
  def range(min, max, sta, edn, sla)
609
642
 
610
643
  return [ nil ] if sta == min && edn == max && sla == 1
@@ -647,13 +680,13 @@ module Fugit
647
680
  .uniq
648
681
  end
649
682
 
650
- def do_determine(key, arr, min, max)
683
+ def do_determine(key, arr, min, max, opts)
651
684
 
652
685
  null = false
653
686
 
654
687
  r = arr
655
688
  .collect { |v|
656
- expand(min, max, v) }
689
+ expand(min, max, opts, v) }
657
690
  .flatten(1)
658
691
  .collect { |e|
659
692
  return false if e == false
@@ -664,31 +697,36 @@ module Fugit
664
697
  r.uniq.sort
665
698
  end
666
699
 
667
- def determine_seconds(arr)
668
- (@seconds = do_determine(:seconds, arr || [ 0 ], 0, 59)) != false
700
+ def determine_seconds(arr, opts)
701
+ (@seconds = do_determine(:seconds, arr || [ 0 ], 0, 59, opts)) != false
669
702
  end
670
703
 
671
- def determine_minutes(arr)
672
- (@minutes = do_determine(:minutes, arr, 0, 59)) != false
704
+ def determine_minutes(arr, opts)
705
+ (@minutes = do_determine(:minutes, arr, 0, 59, opts)) != false
673
706
  end
674
707
 
675
- def determine_hours(arr)
676
- (@hours = do_determine(:hours, arr, 0, 23)) != false
708
+ def determine_hours(arr, opts)
709
+ (@hours = do_determine(:hours, arr, 0, 23, opts)) != false
677
710
  end
678
711
 
679
- def determine_monthdays(arr)
680
- (@monthdays = do_determine(:monthdays, arr, 1, 31)) != false
712
+ def determine_monthdays(arr, opts)
713
+ (@monthdays = do_determine(:monthdays, arr, 1, 31, opts)) != false
681
714
  end
682
715
 
683
- def determine_months(arr)
684
- (@months = do_determine(:months, arr, 1, 12)) != false
716
+ def determine_months(arr, opts)
717
+ (@months = do_determine(:months, arr, 1, 12, opts)) != false
685
718
  end
686
719
 
687
- def determine_weekdays(arr)
720
+ def determine_weekdays(arr, opts)
688
721
 
689
722
  @weekdays = []
690
723
 
691
- arr.each do |a, z, sl, ha, mo| # a to z, slash, hash, and mod
724
+ arr.each do |a, z, sp, sl, ha, mo| # a to z, seperator, slash, hash, and mod
725
+ if sp == :tilde
726
+ a = random(0, 6, a, z, sl, opts)
727
+ z = nil unless sl
728
+ end
729
+
692
730
  if ha || mo
693
731
  @weekdays << [ a, ha || mo ]
694
732
  elsif sl
@@ -759,7 +797,8 @@ module Fugit
759
797
 
760
798
  def s(i); rex(nil, i, /[ \t]+/); end
761
799
  def star(i); str(nil, i, '*'); end
762
- def hyphen(i); str(nil, i, '-'); end
800
+ def hyphen(i); str(:hyphen, i, '-'); end
801
+ def tilde(i); str(:tilde, i, '~'); end
763
802
  def comma(i); rex(nil, i, /,([ \t]*,)*/); end
764
803
  def comma?(i); rex(nil, i, /([ \t]*,)*/); end
765
804
  def and?(i); rex(nil, i, /&?/); end
@@ -787,12 +826,19 @@ module Fugit
787
826
  def r_mon(i); seq(nil, i, :mon, :_mon, '?'); end
788
827
  def r_dow(i); seq(nil, i, :dow, :_dow, '?'); end
789
828
 
829
+ # t: tilde range
830
+ def t_mos(i); seq(nil, i, :mos, '?', :tilde, :mos, '?'); end
831
+ def t_hou(i); seq(nil, i, :hou, '?', :tilde, :hou, '?'); end
832
+ def t_dom(i); seq(nil, i, :dom, '?', :tilde, :dom, '?'); end
833
+ def t_mon(i); seq(nil, i, :mon, '?', :tilde, :mon, '?'); end
834
+ def t_dow(i); seq(nil, i, :dow, '?', :tilde, :dow, '?'); end
835
+
790
836
  # sor: star or range
791
- def sor_mos(i); alt(nil, i, :star, :r_mos); end
792
- def sor_hou(i); alt(nil, i, :star, :r_hou); end
793
- def sor_dom(i); alt(nil, i, :star, :r_dom); end
794
- def sor_mon(i); alt(nil, i, :star, :r_mon); end
795
- def sor_dow(i); alt(nil, i, :star, :r_dow); end
837
+ def sor_mos(i); alt(nil, i, :star, :t_mos, :r_mos); end
838
+ def sor_hou(i); alt(nil, i, :star, :t_hou, :r_hou); end
839
+ def sor_dom(i); alt(nil, i, :star, :t_dom, :r_dom); end
840
+ def sor_mon(i); alt(nil, i, :star, :t_mon, :r_mon); end
841
+ def sor_dow(i); alt(nil, i, :star, :t_dow, :r_dow); end
796
842
 
797
843
  # sorws: star or range with[out] slash
798
844
  def sorws_mos(i); seq(nil, i, :sor_mos, :slash, '?'); end
@@ -872,12 +918,16 @@ module Fugit
872
918
 
873
919
  def rewrite_elt(k, t)
874
920
 
875
- at, zt, slt, hat, mot = nil; t.subgather(nil).each do |tt|
921
+ at, zt, spt, slt, hat, mot = nil
922
+
923
+ t.subgather(nil).each do |tt|
876
924
  case tt.name
877
925
  when :slash then slt = tt
878
926
  when :hash then hat = tt
879
927
  when :mod then mot = tt
880
- else if at; zt ||= tt; else; at = tt; end
928
+ when :hyphen then spt = tt
929
+ when :tilde then spt = tt
930
+ else if spt; zt ||= tt; else; at = tt; end
881
931
  end
882
932
  end
883
933
 
@@ -891,11 +941,12 @@ module Fugit
891
941
 
892
942
  a = at ? rewrite_bound(k, at) : nil
893
943
  z = zt ? rewrite_bound(k, zt) : nil
944
+ sp = spt ? spt.name : nil
894
945
 
895
946
  #a, z = z, a if a && z && a > z
896
947
  # handled downstream since gh-27
897
948
 
898
- [ a, z, sl, ha, mo ]
949
+ [ a, z, sp, sl, ha, mo ]
899
950
  end
900
951
 
901
952
  def rewrite_entry(t)
@@ -26,6 +26,16 @@ module Fugit
26
26
  s = s.strip
27
27
  #p [ original, s ]; Raabro.pp(Parser.parse(s, debug: 3), colours: true)
28
28
 
29
+ if s.length > ::Fugit::MAX_INPUT_LENGTH
30
+
31
+ fail ArgumentError.new(
32
+ 'input too long for a duration string, ' +
33
+ "#{s.length} > #{MAX_INPUT_LENGTH}"
34
+ ) if opts[:do_parse]
35
+
36
+ return nil
37
+ end
38
+
29
39
  h =
30
40
  if opts[:iso]
31
41
  IsoParser.parse(opts[:stricter] ? s : s.upcase)
@@ -40,7 +50,7 @@ module Fugit
40
50
 
41
51
  def do_parse(s, opts={})
42
52
 
43
- parse(s, opts) ||
53
+ parse(s, opts.merge(do_parse: true)) ||
44
54
  fail(ArgumentError.new("not a duration #{s.inspect}"))
45
55
  end
46
56
 
data/lib/fugit/misc.rb CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Fugit
4
4
 
5
- DAY_S = (24 * 3600).freeze
6
- YEAR_S = (365 * DAY_S).freeze
5
+ DAY_S = 24 * 3600
6
+ YEAR_S = 365 * DAY_S
7
7
 
8
8
  class << self
9
9
 
data/lib/fugit/nat.rb CHANGED
@@ -7,8 +7,6 @@ module Fugit
7
7
  #
8
8
  module Nat
9
9
 
10
- MAX_INPUT_LENGTH = 256
11
-
12
10
  class << self
13
11
 
14
12
  def parse(s, opts={})
@@ -19,10 +17,10 @@ module Fugit
19
17
 
20
18
  s = s.strip
21
19
 
22
- if s.length > MAX_INPUT_LENGTH
20
+ if s.length > ::Fugit::MAX_INPUT_LENGTH
23
21
 
24
22
  fail ArgumentError.new(
25
- "input too long for a nat string, " +
23
+ 'input too long for a nat string, ' +
26
24
  "#{s.length} > #{MAX_INPUT_LENGTH}"
27
25
  ) if opts[:do_parse]
28
26
 
@@ -278,10 +276,27 @@ module Fugit
278
276
  rex(:interval, i, INTERVAL_REX)
279
277
  end
280
278
 
279
+ def _starting_at(i)
280
+ rex(nil, i, /[ \t]*(starting[ \t]+at|from)[ \t]+/i)
281
+ end
282
+ def _offset_unit(i)
283
+ rex(nil, i, /(second|minute|hour|day|month)s?[ \t]+/i)
284
+ end
285
+ def offset_count(i)
286
+ rex(:offset_count, i, /\d+/)
287
+ end
288
+
289
+ # starting at minute 1
290
+ # from minute 1
291
+ def offset(i)
292
+ seq(:offset, i, :_starting_at, :_offset_unit, :offset_count)
293
+ end
294
+
281
295
  # every day
282
296
  # every 1 minute
297
+ # every minute starting at minute 10
283
298
  def every_interval(i)
284
- seq(:every_interval, i, :count, '?', :interval)
299
+ seq(:every_interval, i, :count, '?', :interval, :offset, '?')
285
300
  end
286
301
 
287
302
  def every_single_interval(i)
@@ -380,6 +395,7 @@ module Fugit
380
395
  end
381
396
 
382
397
  def rewrite_on_minutes(t)
398
+
383
399
  #Raabro.pp(t, colours: true)
384
400
  mins = t.subgather(:dmin).collect(&:strinp)
385
401
  #slot(:m, mins.join(','))
@@ -387,6 +403,7 @@ module Fugit
387
403
  end
388
404
 
389
405
  def rewrite_on_thex(t)
406
+
390
407
  case s = t.string
391
408
  #when /hour/i then slot(:h, 0)
392
409
  #else slot(:m, '*')
@@ -415,10 +432,12 @@ module Fugit
415
432
  end
416
433
 
417
434
  def rewrite_at_p(t)
435
+
418
436
  pt = t.sublookup(:point).strinpd
419
437
  pt = pt.start_with?('mon') ? 'M' : pt[0, 1]
420
438
  pts = t.subgather(:count).collect { |e| e.string.to_i }
421
439
  #p [ pt, pts ]
440
+
422
441
  case pt
423
442
  #when 'm' then slot(:m, pts)
424
443
  when 'm' then slot(:hm, '*', pts, strong: 1)
@@ -428,6 +447,7 @@ module Fugit
428
447
  end
429
448
 
430
449
  def rewrite_every_single_interval(t)
450
+
431
451
  case t.string
432
452
  when /year/i then [ slot(:month, 1, :weak), slot(:monthday, 1, :weak) ]
433
453
  #when /week/i then xxx...
@@ -438,11 +458,19 @@ module Fugit
438
458
  def rewrite_every_interval(t)
439
459
 
440
460
  #Raabro.pp(t, colours: true)
441
- ci = t.subgather(nil).collect(&:string)
442
- i = ci.pop.strip[0, 3]
443
- c = (ci.pop || '1').strip
461
+ ct = t.sublookup(:count)
462
+ it = t.sublookup(:interval)
463
+ ot = t.sublookup(:offset)
464
+
465
+ c = (ct ? ct.string : '1').strip
466
+ i = it.string.strip[0, 3]
444
467
  i = (i == 'M' || i.downcase == 'mon') ? 'M' : i[0, 1].downcase
445
- cc = c == '1' ? '*' : "*/#{c}"
468
+ off = ot ? ot.sublookup(:offset_count).string.to_i : nil
469
+ cc =
470
+ if off then "#{off}/#{c}"
471
+ elsif c == '1' then '*'
472
+ else "*/#{c}"
473
+ end
446
474
 
447
475
  case i
448
476
  when 'M' then slot(:month, cc)
@@ -465,17 +493,14 @@ module Fugit
465
493
  end
466
494
 
467
495
  def rewrite_tz(t)
468
-
469
496
  slot(:tz, t.string)
470
497
  end
471
498
 
472
499
  def rewrite_weekday(t)
473
-
474
500
  Fugit::Cron::Parser::WEEKDS.index(t.string[0, 3].downcase)
475
501
  end
476
502
 
477
503
  def rewrite_weekdays(t)
478
-
479
504
  #Raabro.pp(t, colours: true)
480
505
  slot(:weekday, _rewrite_subs(t, :weekday))
481
506
  end
@@ -542,12 +567,15 @@ module Fugit
542
567
  end
543
568
 
544
569
  def rewrite_to_hour(t)
570
+
545
571
  #Raabro.pp(t, colours: true)
546
572
  ht0, ht1 = t.subgather(nil)
547
573
  h0, h1 = rewrite(ht0), rewrite(ht1)
574
+
548
575
  fail ArgumentError.new(
549
576
  "cannot deal with #{ht0.strinp} to #{ht1.strinp}, minutes diverge"
550
577
  ) if h0.data1 != h1.data1
578
+
551
579
  slot(:hm, "#{h0._data0}-#{h1._data0}", 0, strong: 0)
552
580
  end
553
581
 
@@ -710,7 +738,7 @@ module Fugit
710
738
  e.uniq.sort_by(&letters_last).collect(&:to_s).join(',') }
711
739
  .join(' ')
712
740
 
713
- c = Fugit::Cron.parse(s)
741
+ c = Fugit::Cron.parse(s, opts)
714
742
 
715
743
  if opts[:strict]
716
744
  restrict(a, c)
data/lib/fugit/parse.rb CHANGED
@@ -6,13 +6,13 @@ module Fugit
6
6
 
7
7
  class << self
8
8
 
9
- def parse_cron(s); ::Fugit::Cron.parse(s); end
9
+ def parse_cron(s, opts={}); ::Fugit::Cron.parse(s, opts || {}); end
10
10
  def parse_duration(s); ::Fugit::Duration.parse(s); end
11
11
  def parse_nat(s, opts={}); ::Fugit::Nat.parse(s, opts || {}); end
12
12
  def parse_at(s, opts={}); ::Fugit::At.parse(s, opts || {}); end
13
13
  def parse_in(s); parse_duration(s); end
14
14
 
15
- def do_parse_cron(s); ::Fugit::Cron.do_parse(s); end
15
+ def do_parse_cron(s, opts={}); ::Fugit::Cron.do_parse(s, opts || {}); end
16
16
  def do_parse_duration(s); ::Fugit::Duration.do_parse(s); end
17
17
  def do_parse_nat(s, opts={}); ::Fugit::Nat.do_parse(s, opts || {}); end
18
18
  def do_parse_at(s); ::Fugit::At.do_parse(s); end
@@ -22,7 +22,7 @@ module Fugit
22
22
 
23
23
  opts[:at] = opts[:in] if opts.has_key?(:in)
24
24
 
25
- (opts[:cron] != false && parse_cron(s)) || # 542ms 616ms
25
+ (opts[:cron] != false && parse_cron(s, opts || {})) || # 542ms 616ms
26
26
  (opts[:duration] != false && parse_duration(s)) || # 645ms # 534ms
27
27
  (opts[:nat] != false && parse_nat(s, opts || {})) || # 2s # 35s
28
28
  (opts[:at] != false && parse_at(s, opts || {})) || # 568ms 622ms
@@ -54,22 +54,24 @@ module Fugit
54
54
 
55
55
  def parse_cronish(s, opts={})
56
56
 
57
- r = parse_cron(s) || parse_nat(s, opts)
57
+ r = parse_cron(s, opts) || parse_nat(s, opts)
58
58
 
59
59
  r.is_a?(::Fugit::Cron) ? r : nil
60
60
  end
61
61
 
62
62
  def do_parse_cronish(s, opts={})
63
63
 
64
- parse_cronish(s) ||
64
+ parse_cronish(s, opts) ||
65
65
  fail(ArgumentError.new("not cron or 'natural' cron string: #{s.inspect}"))
66
66
  end
67
67
 
68
+ # Still an exploration, but what was the goal? 2026-09-14
69
+ #
68
70
  def parse_max(s, opts={})
69
71
 
70
72
  s0 = s.lines.first
71
73
 
72
- (0..[ ::Fugit::Nat::MAX_INPUT_LENGTH, s0.length - 1 ].min).each do |i|
74
+ (0..[ ::Fugit::MAX_INPUT_LENGTH, s0.length - 1 ].min).each do |i|
73
75
 
74
76
  s1 =
75
77
  s0[0, s0.length - i].rstrip
data/lib/fugit.rb CHANGED
@@ -1,9 +1,9 @@
1
- # frozen_string_literal: true
2
-
3
1
 
4
2
  module Fugit
5
3
 
6
- VERSION = '1.12.3'
4
+ VERSION = '1.14.0'.freeze
5
+
6
+ MAX_INPUT_LENGTH = 256
7
7
  end
8
8
 
9
9
  require 'time'
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fugit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.3
4
+ version: 1.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-07-01 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: raabro
@@ -39,19 +38,19 @@ dependencies:
39
38
  - !ruby/object:Gem::Version
40
39
  version: '1.4'
41
40
  - !ruby/object:Gem::Dependency
42
- name: rspec
41
+ name: probatio
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - "~>"
46
45
  - !ruby/object:Gem::Version
47
- version: '3.8'
46
+ version: '1.6'
48
47
  type: :development
49
48
  prerelease: false
50
49
  version_requirements: !ruby/object:Gem::Requirement
51
50
  requirements:
52
51
  - - "~>"
53
52
  - !ruby/object:Gem::Version
54
- version: '3.8'
53
+ version: '1.6'
55
54
  - !ruby/object:Gem::Dependency
56
55
  name: chronic
57
56
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +65,20 @@ dependencies:
66
65
  - - "~>"
67
66
  - !ruby/object:Gem::Version
68
67
  version: '0.10'
68
+ - !ruby/object:Gem::Dependency
69
+ name: ostruct
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
69
82
  description: Time tools for flor and the floraison project. Cron parsing and occurrence
70
83
  computing. Timestamps and more.
71
84
  email:
@@ -96,7 +109,6 @@ metadata:
96
109
  homepage_uri: https://github.com/floraison/fugit
97
110
  source_code_uri: https://github.com/floraison/fugit
98
111
  rubygems_mfa_required: 'true'
99
- post_install_message:
100
112
  rdoc_options: []
101
113
  require_paths:
102
114
  - lib
@@ -111,8 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
123
  - !ruby/object:Gem::Version
112
124
  version: '0'
113
125
  requirements: []
114
- rubygems_version: 3.4.19
115
- signing_key:
126
+ rubygems_version: 3.6.9
116
127
  specification_version: 4
117
128
  summary: time tools for flor
118
129
  test_files: []