fugit 1.3.9 → 1.4.0
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +20 -4
- data/fugit.gemspec +2 -2
- data/lib/fugit.rb +2 -1
- data/lib/fugit/at.rb +1 -0
- data/lib/fugit/cron.rb +18 -11
- data/lib/fugit/duration.rb +3 -3
- data/lib/fugit/misc.rb +1 -0
- data/lib/fugit/nat.rb +504 -355
- data/lib/fugit/parse.rb +1 -0
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 123f788edd6b7510be158be7ffdca00424eea5755aff767ae643180689947636
|
4
|
+
data.tar.gz: c789eaf6ecf0ae363faafa8536b11b97e6c6e02af35983ae13f9c8649fe63ab3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7af25bbc69dcf5f891900d1620f171451a38ea269cb888ff440061ba0d8f1357a3789bcc446b71beba27a5029ad3214a65197d32165c4ed8e7fcc98fd25ad7e
|
7
|
+
data.tar.gz: 89dad0285342e14e9ba1e346a1aae742775048c87bd569b1b8ec5a5edde914435cc3ffb414baa52b948b7af948e5c2cff9ea75cf61503133454eebf780eaebe3
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
# CHANGELOG.md
|
3
3
|
|
4
4
|
|
5
|
+
## fugit 1.4.0 released 2020-10-27
|
6
|
+
|
7
|
+
* Ensure cron accepts "25-L" for monthday, gh-45
|
8
|
+
* Allow for "every weekday 8am to 5pm", gh-44
|
9
|
+
* Allow "every day from the 25th to the last", gh-45
|
10
|
+
* Rework nat parser
|
11
|
+
|
12
|
+
|
5
13
|
## fugit 1.3.9 released 2020-09-17
|
6
14
|
|
7
15
|
* Prevent "New York skip", gh-43, thanks @honglooker
|
data/README.md
CHANGED
@@ -321,19 +321,35 @@ Fugit.parse('every day at five') # ==> Fugit::Cron instance '0 5 * * *'
|
|
321
321
|
|
322
322
|
### Ambiguous nats
|
323
323
|
|
324
|
-
Not all strings result in a clean, single, cron expression.
|
324
|
+
Not all strings result in a clean, single, cron expression. The `multi: false|true|:fail` argument to `Fugit::Nat.parse` could help.
|
325
325
|
|
326
326
|
```ruby
|
327
|
+
Fugit::Nat.parse('every day at 16:00 and 18:00')
|
328
|
+
.to_cron_s
|
329
|
+
# ==> '0 16,18 * * *' (a single Fugit::Cron instances)
|
327
330
|
Fugit::Nat.parse('every day at 16:00 and 18:00', multi: true)
|
328
|
-
|
331
|
+
.collect(&:to_cron_s)
|
332
|
+
# ==> [ '0 16,18 * * *' ] (array of Fugit::Cron instances, here only one)
|
333
|
+
|
329
334
|
Fugit::Nat.parse('every day at 16:15 and 18:30')
|
330
|
-
|
335
|
+
.to_cron_s
|
336
|
+
# ==> '15 16 * * *' (a single of Fugit::Cron instances)
|
331
337
|
Fugit::Nat.parse('every day at 16:15 and 18:30', multi: true)
|
332
|
-
|
338
|
+
.collect(&:to_cron_s)
|
339
|
+
# ==> [ '15 16 * * *', '30 18 * * *' ] (two Fugit::Cron instances)
|
340
|
+
|
333
341
|
Fugit::Nat.parse('every day at 16:15 and 18:30', multi: :fail)
|
334
342
|
# ==> ArgumentError: multiple crons in "every day at 16:15 and 18:30" (15 16 * * * | 30 18 * * *)
|
343
|
+
Fugit::Nat.parse('every day at 16:15 nada 18:30', multi: true)
|
344
|
+
# ==> nil
|
335
345
|
```
|
336
346
|
|
347
|
+
`multi: true` indicates to `Fugit::Nat` that an array of `Fugit::Cron` instances is expected as a result.
|
348
|
+
|
349
|
+
`multi: :fail` tells `Fugit::Nat.parse` to fail if the result is more than 1 `Fugit::Cron` instances.
|
350
|
+
|
351
|
+
`multi: false` is the default behaviour, return a single `Fugit::Cron` instance or nil when it cannot parse.
|
352
|
+
|
337
353
|
|
338
354
|
## LICENSE
|
339
355
|
|
data/fugit.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.platform = Gem::Platform::RUBY
|
11
11
|
s.authors = [ 'John Mettraux' ]
|
12
12
|
s.email = [ 'jmettraux+flor@gmail.com' ]
|
13
|
-
s.homepage = '
|
13
|
+
s.homepage = 'https://github.com/floraison/fugit'
|
14
14
|
s.license = 'MIT'
|
15
15
|
s.summary = 'time tools for flor'
|
16
16
|
|
@@ -40,7 +40,7 @@ Time tools for flor and the floraison project. Cron parsing and occurrence compu
|
|
40
40
|
#s.add_runtime_dependency 'tzinfo'
|
41
41
|
# this dependency appears in 'et-orbi'
|
42
42
|
|
43
|
-
s.add_runtime_dependency 'raabro', '~> 1.
|
43
|
+
s.add_runtime_dependency 'raabro', '~> 1.4'
|
44
44
|
s.add_runtime_dependency 'et-orbi', '~> 1.1', '>= 1.1.8'
|
45
45
|
|
46
46
|
s.add_development_dependency 'rspec', '~> 3.8'
|
data/lib/fugit.rb
CHANGED
data/lib/fugit/at.rb
CHANGED
data/lib/fugit/cron.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Fugit
|
3
4
|
|
@@ -12,9 +13,9 @@ module Fugit
|
|
12
13
|
'@daily' => '0 0 * * *',
|
13
14
|
'@midnight' => '0 0 * * *',
|
14
15
|
'@noon' => '0 12 * * *',
|
15
|
-
'@hourly' => '0 * * * *' }
|
16
|
+
'@hourly' => '0 * * * *' }.freeze
|
16
17
|
MAXDAYS = [
|
17
|
-
nil, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
|
18
|
+
nil, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ].freeze
|
18
19
|
|
19
20
|
attr_reader(
|
20
21
|
:original, :zone)
|
@@ -336,7 +337,7 @@ module Fugit
|
|
336
337
|
[ :seconds, 1, 60 ],
|
337
338
|
[ :minutes, 60, 60 ],
|
338
339
|
[ :hours, 3600, 24 ],
|
339
|
-
[ :days, 24 * 3600, 365 ] ]
|
340
|
+
[ :days, 24 * 3600, 365 ] ].freeze
|
340
341
|
|
341
342
|
def rough_frequency
|
342
343
|
|
@@ -495,7 +496,7 @@ module Fugit
|
|
495
496
|
|
496
497
|
sla = 1 if sla == nil
|
497
498
|
sta = min if sta == nil
|
498
|
-
edn = max if edn == nil
|
499
|
+
edn = max if edn == nil || edn < 0 && sta > 0
|
499
500
|
|
500
501
|
range(min, max, sta, edn, sla)
|
501
502
|
end
|
@@ -507,12 +508,10 @@ module Fugit
|
|
507
508
|
{ min: min, max: max, sta: sta, edn: edn, sla: sla }.inspect
|
508
509
|
) if (sta < 0 && edn > 0) || (edn < 0 && sta > 0)
|
509
510
|
|
510
|
-
#p({ min: min, max: max, sta: sta, edn: edn, sla: sla })
|
511
511
|
a = []
|
512
512
|
|
513
513
|
omin, omax = min, max
|
514
514
|
min, max = -max, -1 if sta < 0
|
515
|
-
#p({ min: min, max: max })
|
516
515
|
|
517
516
|
cur = sta
|
518
517
|
|
@@ -612,10 +611,18 @@ module Fugit
|
|
612
611
|
|
613
612
|
module Parser include Raabro
|
614
613
|
|
615
|
-
WEEKDAYS =
|
616
|
-
|
614
|
+
WEEKDAYS =
|
615
|
+
%w[ sunday monday tuesday wednesday thursday friday saturday ].freeze
|
617
616
|
|
618
|
-
|
617
|
+
WEEKDS =
|
618
|
+
WEEKDAYS.collect { |d| d[0, 3] }.freeze
|
619
|
+
DOW_REX =
|
620
|
+
/([0-7]|#{WEEKDS.join('|')})/i.freeze
|
621
|
+
|
622
|
+
MONTHS =
|
623
|
+
%w[ - jan feb mar apr may jun jul aug sep oct nov dec ].freeze
|
624
|
+
MONTH_REX =
|
625
|
+
/(1[0-2]|0?[1-9]|#{MONTHS[1..-1].join('|')})/i.freeze
|
619
626
|
|
620
627
|
# piece parsers bottom to top
|
621
628
|
|
@@ -629,8 +636,8 @@ module Fugit
|
|
629
636
|
def mos(i); rex(:mos, i, /[0-5]?\d/); end # min or sec
|
630
637
|
def hou(i); rex(:hou, i, /(2[0-4]|[01]?[0-9])/); end
|
631
638
|
def dom(i); rex(:dom, i, /(-?(3[01]|[12][0-9]|0?[1-9])|last|l)/i); end
|
632
|
-
def mon(i); rex(:mon, i,
|
633
|
-
def dow(i); rex(:dow, i,
|
639
|
+
def mon(i); rex(:mon, i, MONTH_REX); end
|
640
|
+
def dow(i); rex(:dow, i, DOW_REX); end
|
634
641
|
|
635
642
|
def dow_hash(i); rex(:hash, i, /#(-?[1-5]|last|l)/i); end
|
636
643
|
|
data/lib/fugit/duration.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Fugit
|
3
4
|
|
@@ -66,10 +67,9 @@ module Fugit
|
|
66
67
|
day: { a: 'D', r: 'd', i: 'D', s: 24 * 3600, I: true, l: 'day' },
|
67
68
|
hou: { a: 'h', r: 'h', i: 'H', s: 3600, I: true, l: 'hour' },
|
68
69
|
min: { a: 'm', r: 'm', i: 'M', s: 60, I: true, l: 'minute' },
|
69
|
-
sec: { a: 's', r: 's', i: 'S', s: 1, I: true, l: 'second' }
|
70
|
-
}
|
70
|
+
sec: { a: 's', r: 's', i: 'S', s: 1, I: true, l: 'second' } }.freeze
|
71
71
|
INFLA_KEYS, NON_INFLA_KEYS =
|
72
|
-
KEYS.partition { |k, v| v[:I] }
|
72
|
+
KEYS.partition { |k, v| v[:I] }.freeze
|
73
73
|
|
74
74
|
def _to_s(key)
|
75
75
|
|
data/lib/fugit/misc.rb
CHANGED
data/lib/fugit/nat.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Fugit
|
3
4
|
|
@@ -16,7 +17,12 @@ module Fugit
|
|
16
17
|
|
17
18
|
#p s; Raabro.pp(Parser.parse(s, debug: 3), colours: true)
|
18
19
|
#(p s; Raabro.pp(Parser.parse(s, debug: 1), colours: true)) rescue nil
|
19
|
-
|
20
|
+
|
21
|
+
if slots = Parser.parse(s)
|
22
|
+
slots.to_crons(opts.merge(_s: s))
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
20
26
|
end
|
21
27
|
|
22
28
|
def do_parse(s, opts={})
|
@@ -24,510 +30,653 @@ module Fugit
|
|
24
30
|
parse(s, opts) ||
|
25
31
|
fail(ArgumentError.new("could not parse a nat #{s.inspect}"))
|
26
32
|
end
|
33
|
+
end
|
27
34
|
|
28
|
-
|
35
|
+
module Parser include Raabro
|
29
36
|
|
30
|
-
|
37
|
+
one_to_nine =
|
38
|
+
%w[ one two three four five six seven eight nine ]
|
39
|
+
sixties =
|
40
|
+
%w[ zero ] + one_to_nine +
|
41
|
+
%w[ ten eleven twelve thirteen fourteen fifteen sixteen seventeen
|
42
|
+
eighteen nineteen ] +
|
43
|
+
%w[ twenty thirty fourty fifty ]
|
44
|
+
.collect { |a|
|
45
|
+
([ nil ] + one_to_nine)
|
46
|
+
.collect { |b| [ a, b ].compact.join('-') } }
|
47
|
+
.flatten
|
48
|
+
|
49
|
+
NHOURS = sixties[0, 13]
|
50
|
+
.each_with_index
|
51
|
+
.inject({}) { |h, (n, i)| h[n] = i; h }
|
52
|
+
.merge!(
|
53
|
+
'midnight' => 0, 'oh' => 0, 'noon' => 12)
|
54
|
+
.freeze
|
55
|
+
NMINUTES = sixties
|
56
|
+
.each_with_index
|
57
|
+
.inject({}) { |h, (n, i)| h[n] = i; h }
|
58
|
+
.merge!(
|
59
|
+
"o'clock" => 0, 'hundred' => 0)
|
60
|
+
.freeze
|
61
|
+
|
62
|
+
WEEKDAYS = (
|
63
|
+
Fugit::Cron::Parser::WEEKDAYS +
|
64
|
+
Fugit::Cron::Parser::WEEKDS).freeze
|
65
|
+
|
66
|
+
POINTS = %w[
|
67
|
+
minutes? mins? seconds? secs? hours? hou h ].freeze
|
68
|
+
|
69
|
+
INTERVALS = %w[
|
70
|
+
seconds? minutes? hours? days? months?
|
71
|
+
sec min
|
72
|
+
s m h d M ].freeze
|
31
73
|
|
32
|
-
|
33
|
-
|
74
|
+
oh = {
|
75
|
+
'1st' => 1, '2nd' => 2, '3rd' => 3, '21st' => 21, '22nd' => 22,
|
76
|
+
'23rd' => 23, '31st' => 31,
|
77
|
+
'last' => 'L' }
|
78
|
+
(4..30)
|
79
|
+
.each { |i| oh["#{i}th"] = i.to_i }
|
80
|
+
%w[
|
81
|
+
first second third fourth fifth sixth seventh eighth ninth tenth
|
82
|
+
eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth
|
83
|
+
eighteenth nineteenth twentieth twenty-first twenty-second twenty-third
|
84
|
+
twenty-fourth twenty-fifth twenty-sixth twenty-seventh twenty-eighth
|
85
|
+
twenty-ninth thirtieth thirty-first ]
|
86
|
+
.each_with_index { |e, i| oh[e] = i + 1 }
|
87
|
+
OMONTHDAYS = oh.freeze
|
34
88
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
#
|
89
|
+
OMONTHDAY_REX = /#{OMONTHDAYS.keys.join('|')}/i.freeze
|
90
|
+
MONTHDAY_REX = /3[0-1]|[0-2]?[0-9]/.freeze
|
91
|
+
WEEKDAY_REX = /(#{WEEKDAYS.join('|')})(?=($|[-, \t]))/i.freeze
|
92
|
+
# prevent "mon" from eating "monday"
|
93
|
+
NAMED_M_REX = /#{NMINUTES.keys.join('|')}/i.freeze
|
94
|
+
NAMED_H_REX = /#{NHOURS.keys.join('|')}/i.freeze
|
95
|
+
POINT_REX = /(#{POINTS.join('|')})[ \t]+/i.freeze
|
96
|
+
INTERVAL_REX = /[ \t]*(#{INTERVALS.join('|')})/.freeze
|
43
97
|
|
44
|
-
|
45
|
-
|
46
|
-
return nil
|
47
|
-
end
|
98
|
+
#
|
99
|
+
# parsers bottom to top #################################################
|
48
100
|
|
49
|
-
|
101
|
+
def _every(i); rex(nil, i, /[ \t]*every[ \t]+/i); end
|
102
|
+
def _from(i); rex(nil, i, /[ \t]*from[ \t]+/i); end
|
103
|
+
def _at(i); rex(nil, i, /[ \t]*at[ \t]+/i); end
|
104
|
+
def _on(i); rex(nil, i, /[ \t]*on[ \t]+/i); end
|
105
|
+
def _to(i); rex(nil, i, /[ \t]*to[ \t]+/i); end
|
50
106
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
.inject({}) { |r, (m, hs)| (r[hs.sort] ||= []) << m; r }
|
55
|
-
.to_a
|
56
|
-
.sort_by { |hs, ms| -hs.size }
|
57
|
-
if hours.empty?
|
58
|
-
hours << (h[:dom] ? [ [ '0' ], [ '0' ] ] : [ [ '*' ], [ '*' ] ])
|
59
|
-
end
|
107
|
+
def _and(i); rex(nil, i, /[ \t]*and[ \t]+/i); end
|
108
|
+
def _and_or_or(i); rex(nil, i, /[ \t]*(and|or)[ \t]+/i); end
|
109
|
+
def _in_or_on(i); rex(nil, i, /(in|on)[ \t]+/i); end
|
60
110
|
|
61
|
-
|
62
|
-
|
111
|
+
def _and_or_or_or_comma(i)
|
112
|
+
rex(nil, i, /[ \t]*(,[ \t]*)?((and|or)[ \t]+|,[ \t]*)/i); end
|
63
113
|
|
64
|
-
|
65
|
-
|
66
|
-
"(#{crons.collect(&:original).join(' | ')})"
|
67
|
-
) if opts[:multi] == :fail && crons.size > 1
|
114
|
+
def _to_or_dash(i);
|
115
|
+
rex(nil, i, /[ \t]*-[ \t]*|[ \t]+(to|through)[ \t]+/i); end
|
68
116
|
|
69
|
-
|
70
|
-
|
71
|
-
else
|
72
|
-
crons.first
|
73
|
-
end
|
74
|
-
end
|
117
|
+
def _day_s(i); rex(nil, i, /[ \t]*days?[ \t]+/i); end
|
118
|
+
def _the(i); rex(nil, i, /[ \t]*the[ \t]+/i); end
|
75
119
|
|
76
|
-
def
|
120
|
+
def _space(i); rex(nil, i, /[ \t]+/); end
|
121
|
+
def _sep(i); rex(nil, i, /([ \t]+|[ \t]*,[ \t]*)/); end
|
77
122
|
|
78
|
-
|
79
|
-
s = []
|
80
|
-
s << h[:sec] if h[:sec]
|
81
|
-
s << h[:hms][1].join(',')
|
82
|
-
s << h[:hms][0].join(',')
|
83
|
-
s << (h[:dom] || '*') << (h[:mon] || '*') << (h[:dow] || '*')
|
84
|
-
s << h[:tz] if h[:tz]
|
123
|
+
def count(i); rex(:count, i, /\d+/); end
|
85
124
|
|
86
|
-
|
125
|
+
def omonthday(i)
|
126
|
+
rex(:omonthday, i, OMONTHDAY_REX)
|
127
|
+
end
|
128
|
+
def monthday(i)
|
129
|
+
rex(:monthday, i, MONTHDAY_REX)
|
130
|
+
end
|
131
|
+
def weekday(i)
|
132
|
+
rex(:weekday, i, WEEKDAY_REX)
|
87
133
|
end
|
88
134
|
|
89
|
-
def
|
90
|
-
|
91
|
-
def parse_interval_elt(e, opts, h)
|
135
|
+
def omonthdays(i); jseq(nil, i, :omonthday, :_and_or_or_or_comma); end
|
136
|
+
def monthdays(i); jseq(nil, i, :monthday, :_and_or_or_or_comma); end
|
92
137
|
|
93
|
-
|
138
|
+
def weekdays(i); jseq(:weekdays, i, :weekday, :_and_or_or_or_comma); end
|
94
139
|
|
95
|
-
|
96
|
-
when 's', 'sec', 'second', 'seconds'
|
97
|
-
h[:sec] = eone(e)
|
98
|
-
when 'm', 'min', 'mins', 'minute', 'minutes'
|
99
|
-
h[:hms] ||= [ [ '*', eone(e) ] ]
|
100
|
-
when 'h', 'hour', 'hours'
|
101
|
-
hms = h[:hms]
|
102
|
-
if hms && hms.size == 1 && hms.first.first == '*'
|
103
|
-
hms.first[0] = eone(e)
|
104
|
-
elsif ! hms
|
105
|
-
h[:hms] = [ [ eone(e), 0 ] ]
|
106
|
-
end
|
107
|
-
when 'd', 'day', 'days'
|
108
|
-
h[:dom] = "*/#{e1}" if e1 > 1
|
109
|
-
h[:hms] ||= [ [ 0, 0 ] ]
|
110
|
-
when 'w', 'week', 'weeks'
|
111
|
-
h[:_fail] = "cannot have crons for \"every #{e1} weeks\"" if e1 > 1
|
112
|
-
h[:hms] ||= [ [ 0, 0 ] ]
|
113
|
-
h[:dow] ||= 0
|
114
|
-
when 'M', 'month', 'months'
|
115
|
-
h[:_fail] = "cannot have crons for \"every #{e1} months\"" if e1 > 12
|
116
|
-
h[:hms] ||= [ [ 0, 0 ] ]
|
117
|
-
h[:dom] = 1
|
118
|
-
h[:mon] = eone(e)
|
119
|
-
when 'Y', 'y', 'year', 'years'
|
120
|
-
h[:_fail] = "cannot have crons for \"every #{e1} years\"" if e1 > 1
|
121
|
-
h[:hms] ||= [ [ 0, 0 ] ]
|
122
|
-
h[:dom] = 1
|
123
|
-
h[:mon] = 1
|
124
|
-
end
|
125
|
-
end
|
140
|
+
def on_the(i); seq(nil, i, :_the, :omonthdays); end
|
126
141
|
|
127
|
-
def
|
142
|
+
def _minute(i); rex(nil, i, /[ \t]*minute[ \t]+/i) end
|
128
143
|
|
129
|
-
|
130
|
-
|
144
|
+
def _dmin(i)
|
145
|
+
rex(:dmin, i, /[0-5]?[0-9]/)
|
131
146
|
end
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
h[:hms] ||= [ [ 0, 0 ] ]
|
136
|
-
h[:dow] = e[1] == e[2] ? e[1] : "#{e[1]}-#{e[2]}"
|
147
|
+
def and_dmin(i)
|
148
|
+
seq(nil, i, :_and_or_or_or_comma, :_minute, '?', :_dmin)
|
137
149
|
end
|
138
150
|
|
139
|
-
def
|
140
|
-
|
141
|
-
h[:dom] = e[1..-1].join(',')
|
151
|
+
def on_minutes(i)
|
152
|
+
seq(:on_minutes, i, :_minute, :_dmin, :and_dmin, '*')
|
142
153
|
end
|
143
154
|
|
144
|
-
def
|
145
|
-
|
146
|
-
(h[:hms] ||= []).concat(e[1])
|
147
|
-
|
148
|
-
l = h[:hms].last
|
149
|
-
h[:sec] = l.pop if l.size > 2
|
155
|
+
def on_thex(i);
|
156
|
+
rex(:on_thex, i, /[ \t]*the[ \t]+(hour|minute)[ \t]*/i);
|
150
157
|
end
|
151
158
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
h[:dow] = e1[0]
|
156
|
-
h[:hms] = [ e1[1] ]
|
159
|
+
def on_thes(i); jseq(:on_thes, i, :on_the, :_and_or_or_or_comma); end
|
160
|
+
def on_days(i); seq(:on_days, i, :_day_s, :monthdays); end
|
161
|
+
def on_weekdays(i); ren(:on_weekdays, i, :weekdays); end
|
157
162
|
|
158
|
-
|
159
|
-
|
163
|
+
def on_object(i)
|
164
|
+
alt(nil, i, :on_days, :on_weekdays, :on_minutes, :on_thes, :on_thex)
|
160
165
|
end
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
h[:tz] = e[1]
|
166
|
+
def on_objects(i)
|
167
|
+
jseq(nil, i, :on_object, :_and)
|
165
168
|
end
|
166
|
-
end
|
167
|
-
|
168
|
-
module Parser include Raabro
|
169
|
-
|
170
|
-
NUMS = %w[
|
171
|
-
zero one two three four five six seven eight nine ten eleven twelve ]
|
172
|
-
|
173
|
-
WEEKDAYS =
|
174
|
-
Fugit::Cron::Parser::WEEKDS + Fugit::Cron::Parser::WEEKDAYS
|
175
169
|
|
176
|
-
|
177
|
-
'
|
178
|
-
'
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
'fifty' => 50, 'fifty-five' => 55 }
|
186
|
-
|
187
|
-
oh = {
|
188
|
-
'1st' => 1, '2nd' => 2, '3rd' => 3, '21st' => 21, '22nd' => 22,
|
189
|
-
'23rd' => 23, '31st' => 31 }
|
190
|
-
%w[ 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 24 25 26 27 28 29 30 ]
|
191
|
-
.each { |i| oh["#{i}th"] = i.to_i }
|
192
|
-
%w[
|
193
|
-
first second third fourth fifth sixth seventh eighth ninth tenth
|
194
|
-
eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth
|
195
|
-
eighteenth nineteenth twentieth twenty-first twenty-second twenty-third
|
196
|
-
twenty-fourth twenty-fifth twenty-fifth twenty-sixth twenty-seventh
|
197
|
-
twenty-eighth twenty-ninth thirtieth thirty-first ]
|
198
|
-
.each_with_index { |e, i| oh[e] = i + 1 }
|
199
|
-
ORDINALS = oh
|
200
|
-
|
201
|
-
# piece parsers bottom to top
|
202
|
-
|
203
|
-
def _from(i); rex(nil, i, /\s*from\s+/i); end
|
204
|
-
def _every(i); rex(nil, i, /\s*(every)\s+/i); end
|
205
|
-
def _at(i); rex(nil, i, /\s*at\s+/i); end
|
206
|
-
def _in(i); rex(nil, i, /\s*(in|on)\s+/i); end
|
207
|
-
def _to(i); rex(nil, i, /\s*to\s+/i); end
|
208
|
-
def _dash(i); rex(nil, i, /-\s*/i); end
|
209
|
-
def _and(i); rex(nil, i, /\s*and\s+/i); end
|
210
|
-
def _on(i); rex(nil, i, /\s*on\s+/i); end
|
211
|
-
|
212
|
-
def _and_or_comma(i)
|
213
|
-
rex(nil, i, /\s*(,?\s*and\s|,?\s*or\s|,)\s*/i)
|
170
|
+
#'every month on day 2 at 10:00' => '0 10 2 * *',
|
171
|
+
#'every month on day 2 and 5 at 10:00' => '0 10 2,5 * *',
|
172
|
+
#'every month on days 1,15 at 10:00' => '0 10 1,15 * *',
|
173
|
+
#
|
174
|
+
#'every week on monday 18:23' => '23 18 * * 1',
|
175
|
+
#
|
176
|
+
# every month on the 1st
|
177
|
+
def on(i)
|
178
|
+
seq(:on, i, :_on, :on_objects)
|
214
179
|
end
|
215
|
-
|
216
|
-
|
180
|
+
|
181
|
+
def city_tz(i)
|
182
|
+
rex(nil, i, /[A-Z][a-zA-Z0-9+\-]+(\/[A-Z][a-zA-Z0-9+\-_]+){0,2}/)
|
217
183
|
end
|
218
|
-
def
|
219
|
-
rex(nil, i,
|
184
|
+
def named_tz(i)
|
185
|
+
rex(nil, i, /Z|UTC/)
|
220
186
|
end
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
def tz_name(i)
|
225
|
-
rex(nil, i,
|
226
|
-
/\s*[A-Z][a-zA-Z0-9+\-]+(\/[A-Z][a-zA-Z0-9+\-_]+){0,2}(\s+|$)/)
|
187
|
+
def delta_tz(i)
|
188
|
+
rex(nil, i, /[-+]([01][0-9]|2[0-4])(:?(00|15|30|45))?/)
|
227
189
|
end
|
228
|
-
def
|
229
|
-
|
230
|
-
/\s*[-+]([01][0-9]|2[0-4]):?(00|15|30|45)(\s+|$)/)
|
190
|
+
def tz(i)
|
191
|
+
alt(:tz, i, :city_tz, :named_tz, :delta_tz)
|
231
192
|
end
|
232
193
|
def tzone(i)
|
233
|
-
|
194
|
+
seq(nil, i, :_in_or_on, '?', :tz)
|
234
195
|
end
|
235
196
|
|
236
|
-
def
|
237
|
-
rex(
|
197
|
+
def digital_hour(i)
|
198
|
+
rex(
|
199
|
+
:digital_hour, i,
|
200
|
+
/(2[0-4]|[0-1]?[0-9]):([0-5][0-9])([ \t]*(am|pm))?/i)
|
238
201
|
end
|
239
202
|
|
240
|
-
def
|
241
|
-
rex(:
|
203
|
+
def ampm(i)
|
204
|
+
rex(:ampm, i, /[ \t]*(am|pm)/i)
|
242
205
|
end
|
243
|
-
def
|
244
|
-
|
245
|
-
end
|
246
|
-
def named_digits(i)
|
247
|
-
seq(nil, i, :named_digit, '+', :and_named_digits, '*')
|
206
|
+
def dark(i)
|
207
|
+
rex(:dark, i, /[ \t]*dark/i)
|
248
208
|
end
|
249
209
|
|
250
|
-
def
|
251
|
-
|
210
|
+
def simple_h(i)
|
211
|
+
rex(:simple_h, i, /#{(0..24).to_a.reverse.join('|')}/)
|
252
212
|
end
|
253
|
-
|
254
|
-
|
255
|
-
rex(:nminute, i, /(#{NMINUTES.keys.join('|')})\s*/i)
|
213
|
+
def simple_hour(i)
|
214
|
+
seq(:simple_hour, i, :simple_h, :ampm, '?')
|
256
215
|
end
|
257
|
-
|
258
|
-
|
216
|
+
|
217
|
+
def named_m(i)
|
218
|
+
rex(:named_m, i, NAMED_M_REX)
|
259
219
|
end
|
260
|
-
def
|
261
|
-
seq(
|
220
|
+
def named_min(i)
|
221
|
+
seq(nil, i, :_space, :named_m)
|
262
222
|
end
|
263
223
|
|
224
|
+
def named_h(i)
|
225
|
+
rex(:named_h, i, NAMED_H_REX)
|
226
|
+
end
|
264
227
|
def named_hour(i)
|
265
|
-
|
228
|
+
seq(:named_hour, i, :named_h, :dark, '?', :named_min, '?', :ampm, '?')
|
266
229
|
end
|
267
230
|
|
268
|
-
def
|
269
|
-
rex(:shour, i, /(2[0-4]|[01]?[0-9])/)
|
270
|
-
end
|
271
|
-
def simple_hour(i)
|
272
|
-
seq(:simple_hour, i, :shour, :am_pm, '?')
|
273
|
-
end
|
231
|
+
def _point(i); rex(:point, i, POINT_REX); end
|
274
232
|
|
275
|
-
def
|
276
|
-
|
277
|
-
def dig_hour(i); alt(nil, i, :dig_hour_a, :dig_hour_b); end
|
278
|
-
#
|
279
|
-
def digital_hour(i)
|
280
|
-
seq(:digital_hour, i, :dig_hour, :am_pm, '?')
|
233
|
+
def counts(i)
|
234
|
+
jseq(nil, i, :count, :_and_or_or_or_comma)
|
281
235
|
end
|
282
236
|
|
237
|
+
def at_p(i)
|
238
|
+
seq(:at_p, i, :_point, :counts)
|
239
|
+
end
|
283
240
|
def at_point(i)
|
284
|
-
|
285
|
-
:digital_hour, :simple_hour, :named_hour, :numeral_hour,
|
286
|
-
:named_digits)
|
241
|
+
jseq(nil, i, :at_p, :_and_or_or)
|
287
242
|
end
|
288
243
|
|
289
|
-
|
290
|
-
|
244
|
+
# at five
|
245
|
+
# at five pm
|
246
|
+
# at five o'clock
|
247
|
+
# at 16:30
|
248
|
+
# at noon
|
249
|
+
# at 18:00 UTC <-- ...tz
|
250
|
+
def at_object(i)
|
251
|
+
alt(nil, i, :named_hour, :digital_hour, :simple_hour, :at_point)
|
291
252
|
end
|
292
|
-
|
293
|
-
|
294
|
-
seq(nil, i, :_and_or_comma, :at_point)
|
253
|
+
def at_objects(i)
|
254
|
+
jseq(nil, i, :at_object, :_and_or_or_or_comma)
|
295
255
|
end
|
296
256
|
|
297
|
-
def
|
298
|
-
|
299
|
-
/(
|
300
|
-
y(ears?)?|months?|w(eeks?)?|d(ays?)?|
|
301
|
-
h(ours?)?|m(in(ute)?s?)?|s(ec(ond)?s?)?
|
302
|
-
)(\s+|$)/ix)
|
257
|
+
def at(i)
|
258
|
+
seq(:at, i, :_at, '?', :at_objects)
|
303
259
|
end
|
304
260
|
|
305
|
-
def
|
306
|
-
rex(:
|
307
|
-
/(year|month|week|day|hour|min(ute)?|sec(ond)?)(\s+|$)/i)
|
261
|
+
def interval(i)
|
262
|
+
rex(:interval, i, INTERVAL_REX)
|
308
263
|
end
|
309
|
-
|
310
|
-
|
264
|
+
|
265
|
+
# every day
|
266
|
+
# every 1 minute
|
267
|
+
def every_interval(i)
|
268
|
+
seq(:every_interval, i, :count, '?', :interval)
|
311
269
|
end
|
312
270
|
|
313
|
-
def
|
314
|
-
rex(:
|
271
|
+
def every_single_interval(i)
|
272
|
+
rex(:every_single_interval, i, /(1[ \t]+)?(week|year)/)
|
315
273
|
end
|
316
274
|
|
317
|
-
def
|
318
|
-
|
275
|
+
def to_weekday(i)
|
276
|
+
seq(:to_weekday, i, :weekday, :_to_or_dash, :weekday)
|
277
|
+
end
|
319
278
|
|
320
|
-
def
|
321
|
-
|
279
|
+
def weekday_range(i)
|
280
|
+
alt(nil, i, :to_weekday, :weekdays)
|
322
281
|
end
|
323
|
-
|
324
|
-
|
282
|
+
|
283
|
+
def to_omonthday(i)
|
284
|
+
seq(:to_omonthday, i,
|
285
|
+
:_the, '?', :omonthday, :_to, :_the, '?', :omonthday)
|
325
286
|
end
|
326
|
-
|
327
|
-
|
287
|
+
|
288
|
+
def to_hour(i)
|
289
|
+
seq(:to_hour, i, :at_object, :_to, :at_object)
|
328
290
|
end
|
329
291
|
|
330
|
-
def
|
331
|
-
|
292
|
+
def from_object(i)
|
293
|
+
alt(nil, i, :to_weekday, :to_omonthday, :to_hour)
|
332
294
|
end
|
333
|
-
def
|
334
|
-
|
295
|
+
def from_objects(i)
|
296
|
+
jseq(nil, i, :from_object, :_and_or_or)
|
335
297
|
end
|
336
|
-
def
|
337
|
-
|
298
|
+
def from(i)
|
299
|
+
seq(nil, i, :_from, '?', :from_objects)
|
338
300
|
end
|
339
301
|
|
340
|
-
|
341
|
-
|
302
|
+
# every monday
|
303
|
+
# every Fri-Sun
|
304
|
+
# every Monday and Tuesday
|
305
|
+
def every_weekday(i)
|
306
|
+
jseq(nil, i, :weekday_range, :_and_or_or)
|
342
307
|
end
|
343
308
|
|
344
|
-
def
|
345
|
-
|
309
|
+
def otm(i)
|
310
|
+
rex(nil, i, /[ \t]+of the month/)
|
346
311
|
end
|
347
|
-
|
348
|
-
|
312
|
+
|
313
|
+
# every 1st of the month
|
314
|
+
# every first of the month
|
315
|
+
# Every 2nd of the month
|
316
|
+
# Every second of the month
|
317
|
+
# every 15th of the month
|
318
|
+
def every_of_the_month(i)
|
319
|
+
seq(nil, i, :omonthdays, :otm)
|
349
320
|
end
|
350
|
-
|
351
|
-
|
321
|
+
|
322
|
+
def every_named(i)
|
323
|
+
rex(:every_named, i, /weekday/i)
|
352
324
|
end
|
353
325
|
|
354
|
-
def
|
355
|
-
|
326
|
+
def every_object(i)
|
327
|
+
alt(
|
328
|
+
nil, i,
|
329
|
+
:every_weekday, :every_of_the_month,
|
330
|
+
:every_interval, :every_named, :every_single_interval)
|
356
331
|
end
|
357
|
-
def
|
358
|
-
|
332
|
+
def every_objects(i)
|
333
|
+
jseq(nil, i, :every_object, :_and_or_or)
|
359
334
|
end
|
360
|
-
|
361
|
-
|
335
|
+
|
336
|
+
def every(i)
|
337
|
+
seq(:every, i, :_every, :every_objects)
|
362
338
|
end
|
363
339
|
|
364
|
-
def
|
365
|
-
alt(nil, i, :
|
340
|
+
def nat_elt(i)
|
341
|
+
alt(nil, i, :every, :from, :at, :tzone, :on)
|
342
|
+
end
|
343
|
+
def nat(i)
|
344
|
+
jseq(:nat, i, :nat_elt, :_sep)
|
366
345
|
end
|
367
346
|
|
368
|
-
|
369
|
-
|
347
|
+
#
|
348
|
+
# rewrite parsed tree ###################################################
|
349
|
+
|
350
|
+
def slot(key, data0, data1=nil, opts=nil)
|
351
|
+
Slot.new(key, data0, data1, opts)
|
370
352
|
end
|
371
353
|
|
372
|
-
def
|
373
|
-
|
354
|
+
def _rewrite_subs(t, key=nil)
|
355
|
+
t.subgather(key).collect { |ct| rewrite(ct) }
|
374
356
|
end
|
375
|
-
def
|
376
|
-
|
357
|
+
def _rewrite_sub(t, key=nil)
|
358
|
+
st = t.sublookup(key)
|
359
|
+
st ? rewrite(st) : nil
|
377
360
|
end
|
378
361
|
|
379
|
-
def
|
380
|
-
|
362
|
+
def rewrite_dmin(t)
|
363
|
+
t.strinp
|
381
364
|
end
|
382
|
-
|
383
|
-
|
365
|
+
|
366
|
+
def rewrite_on_minutes(t)
|
367
|
+
#Raabro.pp(t, colours: true)
|
368
|
+
mins = t.subgather(:dmin).collect(&:strinp)
|
369
|
+
#slot(:m, mins.join(','))
|
370
|
+
slot(:hm, '*', mins.join(','), strong: 1)
|
384
371
|
end
|
385
|
-
|
386
|
-
|
372
|
+
|
373
|
+
def rewrite_on_thex(t)
|
374
|
+
case s = t.string
|
375
|
+
#when /hour/i then slot(:h, 0)
|
376
|
+
#else slot(:m, '*')
|
377
|
+
when /hour/i then slot(:hm, 0, '*', strong: 0)
|
378
|
+
else slot(:hm, '*', '*', strong: 1)
|
379
|
+
end
|
387
380
|
end
|
388
|
-
|
389
|
-
|
381
|
+
|
382
|
+
def rewrite_on_thes(t)
|
383
|
+
_rewrite_subs(t, :omonthday)
|
390
384
|
end
|
391
|
-
def
|
392
|
-
|
385
|
+
def rewrite_on_days(t)
|
386
|
+
_rewrite_subs(t, :monthday)
|
393
387
|
end
|
394
388
|
|
395
|
-
def
|
396
|
-
|
397
|
-
end
|
398
|
-
def at_every(i)
|
399
|
-
seq(nil, i, :at, :every, :tz, '?')
|
389
|
+
def rewrite_on(t)
|
390
|
+
_rewrite_subs(t)
|
400
391
|
end
|
401
392
|
|
402
|
-
def
|
403
|
-
|
393
|
+
def rewrite_monthday(t)
|
394
|
+
slot(:monthday, t.string.to_i)
|
404
395
|
end
|
405
396
|
|
406
|
-
def
|
407
|
-
|
397
|
+
def rewrite_omonthday(t)
|
398
|
+
slot(:monthday, OMONTHDAYS[t.string.downcase])
|
408
399
|
end
|
409
|
-
|
410
|
-
|
400
|
+
|
401
|
+
def rewrite_at_p(t)
|
402
|
+
pt = t.sublookup(:point).strinpd
|
403
|
+
pt = pt.start_with?('mon') ? 'M' : pt[0, 1]
|
404
|
+
pts = t.subgather(:count).collect { |e| e.string.to_i }
|
405
|
+
#p [ pt, pts ]
|
406
|
+
case pt
|
407
|
+
#when 'm' then slot(:m, pts)
|
408
|
+
when 'm' then slot(:hm, '*', pts, strong: 1)
|
409
|
+
when 's' then slot(:second, pts)
|
410
|
+
else slot(pt.to_sym, pts)
|
411
|
+
end
|
411
412
|
end
|
412
|
-
|
413
|
-
|
413
|
+
|
414
|
+
def rewrite_every_single_interval(t)
|
415
|
+
case t.string
|
416
|
+
when /year/i then [ slot(:month, 1, :weak), slot(:monthday, 1, :weak) ]
|
417
|
+
#when /week/i then xxx...
|
418
|
+
else slot(:weekday, 0, :weak)
|
419
|
+
end
|
414
420
|
end
|
415
421
|
|
416
|
-
def
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
422
|
+
def rewrite_every_interval(t)
|
423
|
+
|
424
|
+
#Raabro.pp(t, colours: true)
|
425
|
+
ci = t.subgather(nil).collect(&:string)
|
426
|
+
i = ci.pop.strip[0, 3]
|
427
|
+
c = (ci.pop || '1').strip
|
428
|
+
i = (i == 'M' || i.downcase == 'mon') ? 'M' : i[0, 1].downcase
|
429
|
+
cc = c == '1' ? '*' : "*/#{c}"
|
430
|
+
|
431
|
+
case i
|
432
|
+
when 'M' then slot(:month, cc)
|
433
|
+
when 'd' then slot(:monthday, cc, :weak)
|
434
|
+
#when 'h' then slot(:hm, cc, 0, weak: :minute)
|
435
|
+
when 'h' then slot(:hm, cc, 0, weak: 1)
|
436
|
+
when 'm' then slot(:hm, '*', cc, strong: 1)
|
437
|
+
when 's' then slot(:second, cc)
|
438
|
+
else {}
|
439
|
+
end
|
421
440
|
end
|
422
441
|
|
423
|
-
|
442
|
+
def rewrite_every_named(t)
|
424
443
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
444
|
+
case s = t.string
|
445
|
+
when /weekday/i then slot(:weekday, '1-5', :weak)
|
446
|
+
when /week/i then slot(:weekday, '0', :weak)
|
447
|
+
else fail "cannot rewrite #{s.inspect}"
|
448
|
+
end
|
430
449
|
end
|
431
|
-
|
432
|
-
|
450
|
+
|
451
|
+
def rewrite_tz(t)
|
452
|
+
slot(:tz, t.string)
|
433
453
|
end
|
434
|
-
|
435
|
-
|
454
|
+
|
455
|
+
def rewrite_weekday(t)
|
456
|
+
Fugit::Cron::Parser::WEEKDS.index(t.string[0, 3].downcase)
|
436
457
|
end
|
437
458
|
|
438
|
-
def
|
459
|
+
def rewrite_weekdays(t)
|
460
|
+
#Raabro.pp(t, colours: true)
|
461
|
+
slot(:weekday, _rewrite_subs(t, :weekday))
|
462
|
+
end
|
463
|
+
alias rewrite_on_weekdays rewrite_weekdays
|
439
464
|
|
440
|
-
def
|
465
|
+
def rewrite_to_weekday(t)
|
466
|
+
wd0, wd1 = _rewrite_subs(t, :weekday)
|
467
|
+
#wd1 = 7 if wd1 == 0
|
468
|
+
slot(:weekday, "#{wd0}-#{wd1}")
|
469
|
+
end
|
441
470
|
|
442
|
-
|
471
|
+
def rewrite_to_omonthday(t)
|
472
|
+
md0, md1 = _rewrite_subs(t, :omonthday).collect(&:_data0)
|
473
|
+
slot(:monthday, "#{md0}-#{md1}")
|
443
474
|
end
|
444
475
|
|
445
|
-
def
|
476
|
+
def rewrite_digital_hour(t)
|
477
|
+
h, m, ap = t.strinpd.split(/[: \t]+/)
|
478
|
+
h, m = h.to_i, m.to_i
|
479
|
+
h += 12 if ap && ap == 'pm'
|
480
|
+
slot(:hm, h.to_i, m.to_i)
|
481
|
+
end
|
446
482
|
|
447
|
-
|
483
|
+
def rewrite_simple_hour(t)
|
484
|
+
h, ap = t.subgather(nil).collect(&:strinpd)
|
485
|
+
h = h.to_i
|
486
|
+
h = h + 12 if ap == 'pm'
|
487
|
+
slot(:hm, h, 0)
|
448
488
|
end
|
449
489
|
|
450
|
-
def
|
490
|
+
def rewrite_named_hour(t)
|
451
491
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
end
|
492
|
+
ht = t.sublookup(:named_h)
|
493
|
+
mt = t.sublookup(:named_m)
|
494
|
+
apt = t.sublookup(:ampm)
|
456
495
|
|
457
|
-
|
496
|
+
h = ht.strinp
|
497
|
+
m = mt ? mt.strinp : 0
|
498
|
+
#p [ 0, '-->', h, m ]
|
499
|
+
h = NHOURS[h]
|
500
|
+
m = NMINUTES[m] || m
|
501
|
+
#p [ 1, '-->', h, m ]
|
458
502
|
|
459
|
-
|
503
|
+
h += 12 if h < 13 && apt && apt.strinpd == 'pm'
|
460
504
|
|
461
|
-
|
462
|
-
when /^s/ then [ '*', '*', i ]
|
463
|
-
when /^m/ then [ '*', i ]
|
464
|
-
end
|
505
|
+
slot(:hm, h, m)
|
465
506
|
end
|
466
507
|
|
467
|
-
def
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
[ v, m ]
|
508
|
+
def rewrite_to_hour(t)
|
509
|
+
#Raabro.pp(t, colours: true)
|
510
|
+
ht0, ht1 = t.subgather(nil)
|
511
|
+
h0, h1 = rewrite(ht0), rewrite(ht1)
|
512
|
+
fail ArgumentError.new(
|
513
|
+
"cannot deal with #{ht0.strinp} to #{ht1.strinp}, minutes diverge"
|
514
|
+
) if h0.data1 != h1.data1
|
515
|
+
slot(:hm, "#{h0._data0}-#{h1._data0}", 0, strong: 0)
|
476
516
|
end
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
v += 12 if vs[1] == 'pm'
|
481
|
-
[ v, 0 ]
|
517
|
+
|
518
|
+
def rewrite_at(t)
|
519
|
+
_rewrite_subs(t)
|
482
520
|
end
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
min = m[2].to_i
|
487
|
-
[ hou, min ]
|
521
|
+
|
522
|
+
def rewrite_every(t)
|
523
|
+
_rewrite_sub(t)
|
488
524
|
end
|
489
525
|
|
490
|
-
def
|
526
|
+
def rewrite_nat(t)
|
527
|
+
#Raabro.pp(t, colours: true)
|
528
|
+
Fugit::Nat::SlotGroup.new(_rewrite_subs(t).flatten)
|
529
|
+
end
|
530
|
+
end
|
491
531
|
|
492
|
-
|
532
|
+
class Slot
|
533
|
+
attr_reader :key
|
534
|
+
attr_accessor :_data0, :_data1
|
535
|
+
def initialize(key, d0, d1=nil, opts=nil)
|
536
|
+
d1, opts = d1.is_a?(Symbol) ? [ nil, d1 ] : [ d1, opts ]
|
537
|
+
@key, @_data0, @_data1 = key, d0, d1
|
538
|
+
@opts = (opts.is_a?(Symbol) ? { opts => true } : opts) || {}
|
539
|
+
end
|
540
|
+
def data0; @data0 ||= Array(@_data0); end
|
541
|
+
def data1; @data1 ||= Array(@_data1); end
|
542
|
+
def weak; @opts[:weak]; end
|
543
|
+
def strong; @opts[:strong]; end
|
544
|
+
def graded?; weak || strong; end
|
545
|
+
def append(slot)
|
546
|
+
@_data0, @_data1 = conflate(0, slot), conflate(1, slot)
|
547
|
+
@opts.clear
|
548
|
+
self
|
549
|
+
end
|
550
|
+
def inspect
|
551
|
+
a = [ @key, @_data0 ]
|
552
|
+
a << @_data1 if @_data1 != nil
|
553
|
+
a << @opts if @opts && @opts.keys.any?
|
554
|
+
"(slot #{a.collect(&:inspect).join(' ')})"
|
555
|
+
end
|
556
|
+
def a; [ data0, data1 ]; end
|
557
|
+
protected
|
558
|
+
def to_a(x)
|
559
|
+
return [] if x == '*'
|
560
|
+
Array(x)
|
561
|
+
end
|
562
|
+
def conflate(index, slot)
|
563
|
+
a, b = index == 0 ? [ @_data0, slot._data0 ] : [ @_data1, slot._data1 ]
|
564
|
+
return a if b == nil
|
565
|
+
return b if a == nil
|
566
|
+
if ra = (index == 0 && slot.strong == 1 && hour_range)
|
567
|
+
h0, h1 = ra[0], ra[1] - 1; return h0 == h1 ? h0 : "#{h0}-#{h1}"
|
568
|
+
elsif rb = (index == 0 && strong == 1 && slot.hour_range)
|
569
|
+
h0, h1 = rb[0], rb[1] - 1; return h0 == h1 ? h0 : "#{h0}-#{h1}"
|
570
|
+
end
|
571
|
+
return a if strong == index || strong == true
|
572
|
+
return b if slot.strong == index || slot.strong == true
|
573
|
+
return a if slot.weak == index || slot.weak == true
|
574
|
+
return b if weak == index || weak == true
|
575
|
+
return [ '*' ] if a == '*' && b == '*'
|
576
|
+
to_a(a).concat(to_a(b))
|
577
|
+
end
|
578
|
+
def hour_range
|
579
|
+
m = (key == :hm && @_data1 == 0 && @_data0.match(/\A(\d+)-(\d+)\z/))
|
580
|
+
m ? [ m[1].to_i, m[2].to_i ] : nil
|
493
581
|
end
|
582
|
+
end
|
494
583
|
|
495
|
-
|
584
|
+
class SlotGroup
|
496
585
|
|
497
|
-
def
|
586
|
+
def initialize(slots)
|
498
587
|
|
499
|
-
#
|
500
|
-
|
501
|
-
|
588
|
+
#puts "SlotGroup.new " + slots.inspect
|
589
|
+
@slots = {}
|
590
|
+
@hms = []
|
591
|
+
|
592
|
+
slots.each do |s|
|
593
|
+
if s.key == :hm
|
594
|
+
#ls = @hms.last; @hms.pop if ls && ls.key == :hm && ls.weak == true
|
595
|
+
@hms << s
|
596
|
+
elsif hs = @slots[s.key]
|
597
|
+
hs.append(s)
|
598
|
+
else
|
599
|
+
@slots[s.key] = s
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
if @slots[:monthday] || @slots[:weekday]
|
604
|
+
@hms << make_slot(:hm, 0, 0) if @hms.empty?
|
605
|
+
elsif @slots[:month]
|
606
|
+
@hms << make_slot(:hm, 0, 0) if @hms.empty?
|
607
|
+
@slots[:monthday] ||= make_slot(:monthday, 1)
|
608
|
+
end
|
502
609
|
end
|
503
610
|
|
504
|
-
|
611
|
+
def to_crons(opts)
|
612
|
+
|
613
|
+
multi = opts.has_key?(:multi) ? opts[:multi] : false
|
614
|
+
|
615
|
+
hms = determine_hms
|
616
|
+
|
617
|
+
if multi == :fail && hms.count > 1
|
618
|
+
fail(ArgumentError.new(
|
619
|
+
"multiple crons in #{opts[:_s].inspect} - #{@slots.inspect}"))
|
620
|
+
elsif multi == true
|
621
|
+
hms.collect { |hm| parse_cron(hm) }
|
622
|
+
else
|
623
|
+
parse_cron(hms.first)
|
624
|
+
end
|
625
|
+
end
|
505
626
|
|
506
|
-
|
507
|
-
def rewrite_dow_list(t); [ :dow_list, *_rewrite_children(t) ]; end
|
627
|
+
protected
|
508
628
|
|
509
|
-
def
|
629
|
+
def make_slot(key, data0, data1=nil)
|
510
630
|
|
511
|
-
|
631
|
+
Fugit::Nat::Slot.new(key, data0, data1)
|
512
632
|
end
|
513
633
|
|
514
|
-
def
|
634
|
+
def determine_hms
|
635
|
+
|
636
|
+
return [ [ [ '*' ], [ '*' ] ] ] if @hms.empty?
|
515
637
|
|
516
|
-
|
638
|
+
hms = @hms.dup
|
639
|
+
#
|
640
|
+
while ig = (hms.count > 1 && hms.index { |hm| hm.graded? }) do
|
641
|
+
sg = hms[ig]
|
642
|
+
so = hms.delete_at(ig == 0 ? 1 : ig - 1)
|
643
|
+
sg.append(so)
|
644
|
+
end
|
517
645
|
|
518
|
-
|
646
|
+
hms
|
647
|
+
.collect(&:a)
|
648
|
+
.inject({}) { |r, hm|
|
649
|
+
hm[1].each { |m| (r[m] ||= []).concat(hm[0]) }
|
650
|
+
r }
|
651
|
+
.inject({}) { |r, (m, hs)|
|
652
|
+
(r[hs.sort] ||= []) << m
|
653
|
+
r }
|
654
|
+
.to_a
|
519
655
|
end
|
520
656
|
|
521
|
-
|
522
|
-
alias rewrite_at _rewrite_multiple
|
657
|
+
def parse_cron(hm)
|
523
658
|
|
524
|
-
|
525
|
-
|
659
|
+
a = [
|
660
|
+
slot(:second, '0'),
|
661
|
+
hm[1],
|
662
|
+
hm[0],
|
663
|
+
slot(:monthday, '*'),
|
664
|
+
slot(:month, '*'),
|
665
|
+
slot(:weekday, '*') ]
|
666
|
+
tz = @slots[:tz]
|
667
|
+
a << tz.data0 if tz
|
668
|
+
a.shift if a.first == [ '0' ]
|
526
669
|
|
527
|
-
|
670
|
+
s = a
|
671
|
+
.collect { |e| e.uniq.sort.collect(&:to_s).join(',') }
|
672
|
+
.join(' ')
|
673
|
+
|
674
|
+
Fugit::Cron.parse(s)
|
675
|
+
end
|
528
676
|
|
529
|
-
|
530
|
-
|
677
|
+
def slot(key, default)
|
678
|
+
s = @slots[key]
|
679
|
+
s ? s.data0 : [ default ]
|
531
680
|
end
|
532
681
|
end
|
533
682
|
end
|