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 +4 -4
- data/CHANGELOG.md +10 -0
- data/CREDITS.md +3 -2
- data/README.md +23 -0
- data/fugit.gemspec +4 -1
- data/lib/fugit/cron.rb +87 -36
- data/lib/fugit/duration.rb +11 -1
- data/lib/fugit/misc.rb +2 -2
- data/lib/fugit/nat.rb +41 -13
- data/lib/fugit/parse.rb +8 -6
- data/lib/fugit.rb +3 -3
- metadata +20 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 11380138d493b9ed80a43bffc6a61f74de5a2c52132ae2b9746c8097b3f8015a
|
|
4
|
+
data.tar.gz: 40ec86bcc48074cc6d3a5bc02b7c2ae84ba3f9fc505104373fc83c7c984ec04b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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(
|
|
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
|
|
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
|
-
|
|
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)
|
data/lib/fugit/duration.rb
CHANGED
|
@@ -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
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
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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
|
-
|
|
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::
|
|
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
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.
|
|
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:
|
|
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:
|
|
41
|
+
name: probatio
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
44
43
|
requirements:
|
|
45
44
|
- - "~>"
|
|
46
45
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
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: '
|
|
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.
|
|
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: []
|