fugit 1.12.3 → 1.13.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 +4 -4
- data/CHANGELOG.md +5 -0
- data/CREDITS.md +1 -1
- data/README.md +23 -0
- data/fugit.gemspec +1 -0
- data/lib/fugit/cron.rb +77 -36
- data/lib/fugit/nat.rb +1 -1
- data/lib/fugit/parse.rb +5 -5
- data/lib/fugit.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15c7da961f6616177b4837e7db2b8d2cbef8a73af0e39d482bbde88ca927d420
|
|
4
|
+
data.tar.gz: bdb787682ba39f3bd873c935378d7097291ff275c9c2443a4bf42990e71dfa92
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c920de689a07b8e5b082afa2d67ff26a2ad3422e0a35afc0c02fee71d92d6a76da391d7ec6d03e55d62cbc1a46cbf1296bccb4a37ec9df9d72f35d3e4ecaf0ad
|
|
7
|
+
data.tar.gz: 11694200215f7506f64f862d7f63e86b3fc79be5ad4a4ddfe9278143c40991bcd2c89356e9e314d5caad125b0b26623daf3da64ee2e92b49ca1480b59fc220f3
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
# CHANGELOG.md
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
## fugit 1.13.0 released 2026-07-10
|
|
6
|
+
|
|
7
|
+
* Random values support in cron string `"10 ~ * * *"` gh-121 Nicols Bachschmidt
|
|
8
|
+
|
|
9
|
+
|
|
5
10
|
## fugit 1.12.3 released 2026-07-01
|
|
6
11
|
|
|
7
12
|
* Wrap-around for weekday ranges with step value, gh-119 Nicolas Bachschmidt
|
data/CREDITS.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Mark R. James, https://github.com/mrj, AM vs America/Los_Angeles, gh-113
|
|
9
9
|
* Tejas Bubane, https://github.com/tejasbubane, r3.4 in test matrix, gh-109
|
|
10
10
|
* Luis Castillo, https://github.com/lekastillo, nice_hash gh-108
|
|
11
|
-
* Geremia Taglialatela, https://github.com/tagliala, gh-105 gh-107
|
|
11
|
+
* Geremia Taglialatela, https://github.com/tagliala, gh-105 gh-107 gh-122
|
|
12
12
|
* https://github.com/personnumber3377, gh-104 Fugit.parse choke on long input
|
|
13
13
|
* Michael Scrivo, https://github.com/mscrivo, gh-103
|
|
14
14
|
* Benjamin Darcet, https://github.com/bdarcet gh-95 gh-96 et-orbi #rweek
|
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
|
@@ -45,6 +45,7 @@ Time tools for flor and the floraison project. Cron parsing and occurrence compu
|
|
|
45
45
|
|
|
46
46
|
s.add_development_dependency 'rspec', '~> 3.8'
|
|
47
47
|
s.add_development_dependency 'chronic', '~> 0.10'
|
|
48
|
+
s.add_development_dependency 'ostruct'
|
|
48
49
|
|
|
49
50
|
s.require_path = 'lib'
|
|
50
51
|
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)
|
|
@@ -48,12 +48,12 @@ module Fugit
|
|
|
48
48
|
#p s; Raabro.pp(Parser.parse(s, debug: 3), colors: true)
|
|
49
49
|
h = Parser.parse(s)
|
|
50
50
|
|
|
51
|
-
self.allocate.send(:init, s0, h)
|
|
51
|
+
self.allocate.send(:init, s0, h, opts)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
def do_parse(s)
|
|
54
|
+
def do_parse(s, opts={})
|
|
55
55
|
|
|
56
|
-
parse(s) ||
|
|
56
|
+
parse(s, opts) ||
|
|
57
57
|
fail(ArgumentError.new("invalid cron string #{trunc(s)}"))
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -559,7 +559,7 @@ module Fugit
|
|
|
559
559
|
|
|
560
560
|
FREQUENCY_CACHE = {}
|
|
561
561
|
|
|
562
|
-
def init(original, h)
|
|
562
|
+
def init(original, h, opts)
|
|
563
563
|
|
|
564
564
|
return nil unless h
|
|
565
565
|
|
|
@@ -568,12 +568,12 @@ module Fugit
|
|
|
568
568
|
@day_and = h[:&]
|
|
569
569
|
|
|
570
570
|
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]) &&
|
|
571
|
+
determine_seconds(h[:sec], opts) &&
|
|
572
|
+
determine_minutes(h[:min], opts) &&
|
|
573
|
+
determine_hours(h[:hou], opts) &&
|
|
574
|
+
determine_monthdays(h[:dom], opts) &&
|
|
575
|
+
determine_months(h[:mon], opts) &&
|
|
576
|
+
determine_weekdays(h[:dow], opts) &&
|
|
577
577
|
determine_timezone(h[:tz])
|
|
578
578
|
|
|
579
579
|
return nil unless valid
|
|
@@ -582,9 +582,9 @@ module Fugit
|
|
|
582
582
|
self
|
|
583
583
|
end
|
|
584
584
|
|
|
585
|
-
def expand(min, max, r)
|
|
585
|
+
def expand(min, max, opts, r)
|
|
586
586
|
|
|
587
|
-
sta, edn, sla = r
|
|
587
|
+
sta, edn, sep, sla = r
|
|
588
588
|
|
|
589
589
|
#return false if sla && sla > max
|
|
590
590
|
#
|
|
@@ -593,6 +593,11 @@ module Fugit
|
|
|
593
593
|
|
|
594
594
|
return false if sla && sla < 1
|
|
595
595
|
|
|
596
|
+
if sep == :tilde
|
|
597
|
+
sta = random(min, max, sta, edn, sla, opts)
|
|
598
|
+
edn = nil unless sla
|
|
599
|
+
end
|
|
600
|
+
|
|
596
601
|
edn = max if sla && edn.nil?
|
|
597
602
|
|
|
598
603
|
return nil if sta.nil? && edn.nil? && sla.nil?
|
|
@@ -605,6 +610,24 @@ module Fugit
|
|
|
605
610
|
range(min, max, sta, edn, sla)
|
|
606
611
|
end
|
|
607
612
|
|
|
613
|
+
def random(min, max, sta, edn, sla, opts)
|
|
614
|
+
|
|
615
|
+
sta = min if sta.nil?
|
|
616
|
+
edn = max if edn.nil?
|
|
617
|
+
|
|
618
|
+
random = opts.fetch(:random, true)
|
|
619
|
+
random = Random if random == true
|
|
620
|
+
return sta unless random
|
|
621
|
+
|
|
622
|
+
n = edn - sta + 1
|
|
623
|
+
n = max - min + 1 + n if n <= 0
|
|
624
|
+
n = sla if sla && sla < n
|
|
625
|
+
|
|
626
|
+
r = sta + random.rand(n)
|
|
627
|
+
r = r + min - max - 1 if r > max
|
|
628
|
+
r
|
|
629
|
+
end
|
|
630
|
+
|
|
608
631
|
def range(min, max, sta, edn, sla)
|
|
609
632
|
|
|
610
633
|
return [ nil ] if sta == min && edn == max && sla == 1
|
|
@@ -647,13 +670,13 @@ module Fugit
|
|
|
647
670
|
.uniq
|
|
648
671
|
end
|
|
649
672
|
|
|
650
|
-
def do_determine(key, arr, min, max)
|
|
673
|
+
def do_determine(key, arr, min, max, opts)
|
|
651
674
|
|
|
652
675
|
null = false
|
|
653
676
|
|
|
654
677
|
r = arr
|
|
655
678
|
.collect { |v|
|
|
656
|
-
expand(min, max, v) }
|
|
679
|
+
expand(min, max, opts, v) }
|
|
657
680
|
.flatten(1)
|
|
658
681
|
.collect { |e|
|
|
659
682
|
return false if e == false
|
|
@@ -664,31 +687,36 @@ module Fugit
|
|
|
664
687
|
r.uniq.sort
|
|
665
688
|
end
|
|
666
689
|
|
|
667
|
-
def determine_seconds(arr)
|
|
668
|
-
(@seconds = do_determine(:seconds, arr || [ 0 ], 0, 59)) != false
|
|
690
|
+
def determine_seconds(arr, opts)
|
|
691
|
+
(@seconds = do_determine(:seconds, arr || [ 0 ], 0, 59, opts)) != false
|
|
669
692
|
end
|
|
670
693
|
|
|
671
|
-
def determine_minutes(arr)
|
|
672
|
-
(@minutes = do_determine(:minutes, arr, 0, 59)) != false
|
|
694
|
+
def determine_minutes(arr, opts)
|
|
695
|
+
(@minutes = do_determine(:minutes, arr, 0, 59, opts)) != false
|
|
673
696
|
end
|
|
674
697
|
|
|
675
|
-
def determine_hours(arr)
|
|
676
|
-
(@hours = do_determine(:hours, arr, 0, 23)) != false
|
|
698
|
+
def determine_hours(arr, opts)
|
|
699
|
+
(@hours = do_determine(:hours, arr, 0, 23, opts)) != false
|
|
677
700
|
end
|
|
678
701
|
|
|
679
|
-
def determine_monthdays(arr)
|
|
680
|
-
(@monthdays = do_determine(:monthdays, arr, 1, 31)) != false
|
|
702
|
+
def determine_monthdays(arr, opts)
|
|
703
|
+
(@monthdays = do_determine(:monthdays, arr, 1, 31, opts)) != false
|
|
681
704
|
end
|
|
682
705
|
|
|
683
|
-
def determine_months(arr)
|
|
684
|
-
(@months = do_determine(:months, arr, 1, 12)) != false
|
|
706
|
+
def determine_months(arr, opts)
|
|
707
|
+
(@months = do_determine(:months, arr, 1, 12, opts)) != false
|
|
685
708
|
end
|
|
686
709
|
|
|
687
|
-
def determine_weekdays(arr)
|
|
710
|
+
def determine_weekdays(arr, opts)
|
|
688
711
|
|
|
689
712
|
@weekdays = []
|
|
690
713
|
|
|
691
|
-
arr.each do |a, z, sl, ha, mo| # a to z, slash, hash, and mod
|
|
714
|
+
arr.each do |a, z, sp, sl, ha, mo| # a to z, seperator, slash, hash, and mod
|
|
715
|
+
if sp == :tilde
|
|
716
|
+
a = random(0, 6, a, z, sl, opts)
|
|
717
|
+
z = nil unless sl
|
|
718
|
+
end
|
|
719
|
+
|
|
692
720
|
if ha || mo
|
|
693
721
|
@weekdays << [ a, ha || mo ]
|
|
694
722
|
elsif sl
|
|
@@ -759,7 +787,8 @@ module Fugit
|
|
|
759
787
|
|
|
760
788
|
def s(i); rex(nil, i, /[ \t]+/); end
|
|
761
789
|
def star(i); str(nil, i, '*'); end
|
|
762
|
-
def hyphen(i); str(
|
|
790
|
+
def hyphen(i); str(:hyphen, i, '-'); end
|
|
791
|
+
def tilde(i); str(:tilde, i, '~'); end
|
|
763
792
|
def comma(i); rex(nil, i, /,([ \t]*,)*/); end
|
|
764
793
|
def comma?(i); rex(nil, i, /([ \t]*,)*/); end
|
|
765
794
|
def and?(i); rex(nil, i, /&?/); end
|
|
@@ -787,12 +816,19 @@ module Fugit
|
|
|
787
816
|
def r_mon(i); seq(nil, i, :mon, :_mon, '?'); end
|
|
788
817
|
def r_dow(i); seq(nil, i, :dow, :_dow, '?'); end
|
|
789
818
|
|
|
819
|
+
# t: tilde range
|
|
820
|
+
def t_mos(i); seq(nil, i, :mos, '?', :tilde, :mos, '?'); end
|
|
821
|
+
def t_hou(i); seq(nil, i, :hou, '?', :tilde, :hou, '?'); end
|
|
822
|
+
def t_dom(i); seq(nil, i, :dom, '?', :tilde, :dom, '?'); end
|
|
823
|
+
def t_mon(i); seq(nil, i, :mon, '?', :tilde, :mon, '?'); end
|
|
824
|
+
def t_dow(i); seq(nil, i, :dow, '?', :tilde, :dow, '?'); end
|
|
825
|
+
|
|
790
826
|
# 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
|
|
827
|
+
def sor_mos(i); alt(nil, i, :star, :t_mos, :r_mos); end
|
|
828
|
+
def sor_hou(i); alt(nil, i, :star, :t_hou, :r_hou); end
|
|
829
|
+
def sor_dom(i); alt(nil, i, :star, :t_dom, :r_dom); end
|
|
830
|
+
def sor_mon(i); alt(nil, i, :star, :t_mon, :r_mon); end
|
|
831
|
+
def sor_dow(i); alt(nil, i, :star, :t_dow, :r_dow); end
|
|
796
832
|
|
|
797
833
|
# sorws: star or range with[out] slash
|
|
798
834
|
def sorws_mos(i); seq(nil, i, :sor_mos, :slash, '?'); end
|
|
@@ -872,12 +908,16 @@ module Fugit
|
|
|
872
908
|
|
|
873
909
|
def rewrite_elt(k, t)
|
|
874
910
|
|
|
875
|
-
at, zt, slt, hat, mot = nil
|
|
911
|
+
at, zt, spt, slt, hat, mot = nil
|
|
912
|
+
|
|
913
|
+
t.subgather(nil).each do |tt|
|
|
876
914
|
case tt.name
|
|
877
915
|
when :slash then slt = tt
|
|
878
916
|
when :hash then hat = tt
|
|
879
917
|
when :mod then mot = tt
|
|
880
|
-
|
|
918
|
+
when :hyphen then spt = tt
|
|
919
|
+
when :tilde then spt = tt
|
|
920
|
+
else if spt; zt ||= tt; else; at = tt; end
|
|
881
921
|
end
|
|
882
922
|
end
|
|
883
923
|
|
|
@@ -891,11 +931,12 @@ module Fugit
|
|
|
891
931
|
|
|
892
932
|
a = at ? rewrite_bound(k, at) : nil
|
|
893
933
|
z = zt ? rewrite_bound(k, zt) : nil
|
|
934
|
+
sp = spt ? spt.name : nil
|
|
894
935
|
|
|
895
936
|
#a, z = z, a if a && z && a > z
|
|
896
937
|
# handled downstream since gh-27
|
|
897
938
|
|
|
898
|
-
[ a, z, sl, ha, mo ]
|
|
939
|
+
[ a, z, sp, sl, ha, mo ]
|
|
899
940
|
end
|
|
900
941
|
|
|
901
942
|
def rewrite_entry(t)
|
data/lib/fugit/nat.rb
CHANGED
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,14 +54,14 @@ 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
|
|
data/lib/fugit.rb
CHANGED
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: 1.
|
|
4
|
+
version: 1.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- John Mettraux
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: raabro
|
|
@@ -66,6 +66,20 @@ dependencies:
|
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0.10'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: ostruct
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
69
83
|
description: Time tools for flor and the floraison project. Cron parsing and occurrence
|
|
70
84
|
computing. Timestamps and more.
|
|
71
85
|
email:
|