fugit 1.3.5 → 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 +29 -0
- data/CREDITS.md +3 -0
- data/README.md +44 -5
- data/fugit.gemspec +2 -2
- data/lib/fugit.rb +2 -1
- data/lib/fugit/at.rb +1 -0
- data/lib/fugit/cron.rb +29 -14
- data/lib/fugit/duration.rb +3 -3
- data/lib/fugit/misc.rb +1 -0
- data/lib/fugit/nat.rb +569 -246
- data/lib/fugit/parse.rb +1 -0
- metadata +10 -10
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,35 @@
|
|
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
|
+
|
13
|
+
## fugit 1.3.9 released 2020-09-17
|
14
|
+
|
15
|
+
* Prevent "New York skip", gh-43, thanks @honglooker
|
16
|
+
|
17
|
+
|
18
|
+
## fugit 1.3.8 released 2020-08-06
|
19
|
+
|
20
|
+
* Parse 'every day at 8:30' and ' at 8:30 pm', gh-42
|
21
|
+
|
22
|
+
|
23
|
+
## fugit 1.3.7 released 2020-08-05
|
24
|
+
|
25
|
+
* Parse 'every 12 hours at minute 50', gh-41
|
26
|
+
|
27
|
+
|
28
|
+
## fugit 1.3.6 released 2020-06-01
|
29
|
+
|
30
|
+
* Introduce new nat syntaxed, gh-38
|
31
|
+
* Rework nat parser
|
32
|
+
|
33
|
+
|
5
34
|
## fugit 1.3.5 released 2020-05-07
|
6
35
|
|
7
36
|
* Implement cron @noon, gh-37
|
data/CREDITS.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
|
2
2
|
# fugit credits
|
3
3
|
|
4
|
+
* Honglooker https://github.com/honglooker gh-43, New York cron skip
|
5
|
+
* Jérôme Dalbert https://github.com/jeromedalbert gh-41, gh-42
|
6
|
+
* Danny Ben Shitrit https://github.com/DannyBen nat variants, gh-38
|
4
7
|
* Dominik Sander https://github.com/dsander #rough_frequency 0, gh-36
|
5
8
|
* Milovan Zogovic https://github.com/assembler Cron#match? vs TZ, gh-31
|
6
9
|
* Jessica Stokes https://github.com/ticky 0-24 issue with cron, gh-30
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ Time tools for [flor](https://github.com/floraison/flor) and the floraison group
|
|
9
9
|
|
10
10
|
It uses [et-orbi](https://github.com/floraison/et-orbi) to represent time instances and [raabro](https://github.com/floraison/raabro) as a basis for its parsers.
|
11
11
|
|
12
|
-
Fugit is a core dependency of [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) 3.5.
|
12
|
+
Fugit is a core dependency of [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) >= 3.5.
|
13
13
|
|
14
14
|
|
15
15
|
## Related projects
|
@@ -232,6 +232,29 @@ p d.to_plain_s # => "2Y2M1D5h3600s"
|
|
232
232
|
p Fugit::Duration.parse('1y2M1d4h').to_sec # => 36820800
|
233
233
|
```
|
234
234
|
|
235
|
+
There is a `#deflate` method
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
Fugit::Duration.parse(1000).to_plain_s # => "1000s"
|
239
|
+
Fugit::Duration.parse(3600).to_plain_s # => "3600s"
|
240
|
+
Fugit::Duration.parse(1000).deflate.to_plain_s # => "16m40s"
|
241
|
+
Fugit::Duration.parse(3600).deflate.to_plain_s # => "1h"
|
242
|
+
|
243
|
+
# or event shorter
|
244
|
+
Fugit.parse(1000).deflate.to_plain_s # => "16m40s"
|
245
|
+
Fugit.parse(3600).deflate.to_plain_s # => "1h"
|
246
|
+
```
|
247
|
+
|
248
|
+
There is also an `#inflate` method
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
Fugit::Duration.parse('1h30m12').inflate.to_plain_s # => "5412s"
|
252
|
+
Fugit.parse('1h30m12').inflate.to_plain_s # => "5412s"
|
253
|
+
|
254
|
+
Fugit.parse('1h30m12').to_sec # => 5412
|
255
|
+
Fugit.parse('1h30m12').to_sec.to_s + 's' # => "5412s"
|
256
|
+
```
|
257
|
+
|
235
258
|
The `to_*_s` methods are also available as class methods:
|
236
259
|
```ruby
|
237
260
|
p Fugit::Duration.to_plain_s('1y2M1d4h')
|
@@ -298,19 +321,35 @@ Fugit.parse('every day at five') # ==> Fugit::Cron instance '0 5 * * *'
|
|
298
321
|
|
299
322
|
### Ambiguous nats
|
300
323
|
|
301
|
-
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.
|
302
325
|
|
303
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)
|
304
330
|
Fugit::Nat.parse('every day at 16:00 and 18:00', multi: true)
|
305
|
-
|
331
|
+
.collect(&:to_cron_s)
|
332
|
+
# ==> [ '0 16,18 * * *' ] (array of Fugit::Cron instances, here only one)
|
333
|
+
|
306
334
|
Fugit::Nat.parse('every day at 16:15 and 18:30')
|
307
|
-
|
335
|
+
.to_cron_s
|
336
|
+
# ==> '15 16 * * *' (a single of Fugit::Cron instances)
|
308
337
|
Fugit::Nat.parse('every day at 16:15 and 18:30', multi: true)
|
309
|
-
|
338
|
+
.collect(&:to_cron_s)
|
339
|
+
# ==> [ '15 16 * * *', '30 18 * * *' ] (two Fugit::Cron instances)
|
340
|
+
|
310
341
|
Fugit::Nat.parse('every day at 16:15 and 18:30', multi: :fail)
|
311
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
|
312
345
|
```
|
313
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
|
+
|
314
353
|
|
315
354
|
## LICENSE
|
316
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)
|
@@ -236,6 +237,8 @@ module Fugit
|
|
236
237
|
# the translation occurs in the timezone of
|
237
238
|
# this Fugit::Cron instance
|
238
239
|
|
240
|
+
zfrom = t.time.strftime('%z|%Z')
|
241
|
+
|
239
242
|
loop do
|
240
243
|
|
241
244
|
fail RuntimeError.new(
|
@@ -251,8 +254,14 @@ module Fugit
|
|
251
254
|
min_match?(t) || (t.inc_min; next)
|
252
255
|
sec_match?(t) || (t.inc_sec; next)
|
253
256
|
|
254
|
-
|
255
|
-
|
257
|
+
tt = t.time
|
258
|
+
st = tt.strftime('%F|%T')
|
259
|
+
zt = tt.strftime('%z|%Z')
|
260
|
+
#
|
261
|
+
if st == sfrom && zt != zfrom
|
262
|
+
from, sfrom, zfrom, ifrom = tt, st, zt, t.to_i
|
263
|
+
next
|
264
|
+
end
|
256
265
|
#
|
257
266
|
# when transitioning out of DST, this prevents #next_time from
|
258
267
|
# yielding the same literal time twice in a row, see gh-6
|
@@ -328,7 +337,7 @@ module Fugit
|
|
328
337
|
[ :seconds, 1, 60 ],
|
329
338
|
[ :minutes, 60, 60 ],
|
330
339
|
[ :hours, 3600, 24 ],
|
331
|
-
[ :days, 24 * 3600, 365 ] ]
|
340
|
+
[ :days, 24 * 3600, 365 ] ].freeze
|
332
341
|
|
333
342
|
def rough_frequency
|
334
343
|
|
@@ -487,7 +496,7 @@ module Fugit
|
|
487
496
|
|
488
497
|
sla = 1 if sla == nil
|
489
498
|
sta = min if sta == nil
|
490
|
-
edn = max if edn == nil
|
499
|
+
edn = max if edn == nil || edn < 0 && sta > 0
|
491
500
|
|
492
501
|
range(min, max, sta, edn, sla)
|
493
502
|
end
|
@@ -499,12 +508,10 @@ module Fugit
|
|
499
508
|
{ min: min, max: max, sta: sta, edn: edn, sla: sla }.inspect
|
500
509
|
) if (sta < 0 && edn > 0) || (edn < 0 && sta > 0)
|
501
510
|
|
502
|
-
#p({ min: min, max: max, sta: sta, edn: edn, sla: sla })
|
503
511
|
a = []
|
504
512
|
|
505
513
|
omin, omax = min, max
|
506
514
|
min, max = -max, -1 if sta < 0
|
507
|
-
#p({ min: min, max: max })
|
508
515
|
|
509
516
|
cur = sta
|
510
517
|
|
@@ -604,10 +611,18 @@ module Fugit
|
|
604
611
|
|
605
612
|
module Parser include Raabro
|
606
613
|
|
607
|
-
WEEKDAYS =
|
608
|
-
|
614
|
+
WEEKDAYS =
|
615
|
+
%w[ sunday monday tuesday wednesday thursday friday saturday ].freeze
|
616
|
+
|
617
|
+
WEEKDS =
|
618
|
+
WEEKDAYS.collect { |d| d[0, 3] }.freeze
|
619
|
+
DOW_REX =
|
620
|
+
/([0-7]|#{WEEKDS.join('|')})/i.freeze
|
609
621
|
|
610
|
-
MONTHS =
|
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
|
611
626
|
|
612
627
|
# piece parsers bottom to top
|
613
628
|
|
@@ -621,8 +636,8 @@ module Fugit
|
|
621
636
|
def mos(i); rex(:mos, i, /[0-5]?\d/); end # min or sec
|
622
637
|
def hou(i); rex(:hou, i, /(2[0-4]|[01]?[0-9])/); end
|
623
638
|
def dom(i); rex(:dom, i, /(-?(3[01]|[12][0-9]|0?[1-9])|last|l)/i); end
|
624
|
-
def mon(i); rex(:mon, i,
|
625
|
-
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
|
626
641
|
|
627
642
|
def dow_hash(i); rex(:hash, i, /#(-?[1-5]|last|l)/i); end
|
628
643
|
|
@@ -757,7 +772,7 @@ module Fugit
|
|
757
772
|
|
758
773
|
def rewrite_tz(t)
|
759
774
|
|
760
|
-
s = t.
|
775
|
+
s = t.strim
|
761
776
|
z = EtOrbi.get_tzone(s)
|
762
777
|
|
763
778
|
[ s, z ]
|
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,16 +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
|
-
a = Parser.parse(s)
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
if a.include?([ :flag, 'from' ]) && a.find { |e| e[0] == :day_range }
|
27
|
-
|
28
|
-
nil
|
21
|
+
if slots = Parser.parse(s)
|
22
|
+
slots.to_crons(opts.merge(_s: s))
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
29
26
|
end
|
30
27
|
|
31
28
|
def do_parse(s, opts={})
|
@@ -33,327 +30,653 @@ module Fugit
|
|
33
30
|
parse(s, opts) ||
|
34
31
|
fail(ArgumentError.new("could not parse a nat #{s.inspect}"))
|
35
32
|
end
|
33
|
+
end
|
36
34
|
|
37
|
-
|
35
|
+
module Parser include Raabro
|
38
36
|
|
39
|
-
|
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
|
40
61
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
.inject({}) { |h, e| (h[e[1][1]] ||= []) << e[1][2]; h }
|
45
|
-
.values
|
46
|
-
.uniq
|
47
|
-
crons =
|
48
|
-
ms.size > 1 ?
|
49
|
-
hms.collect { |e| parse_cron([ e ] + aa, opts) } :
|
50
|
-
[ parse_cron(a, opts) ]
|
62
|
+
WEEKDAYS = (
|
63
|
+
Fugit::Cron::Parser::WEEKDAYS +
|
64
|
+
Fugit::Cron::Parser::WEEKDS).freeze
|
51
65
|
|
52
|
-
|
53
|
-
|
54
|
-
"(#{crons.collect(&:original).join(' | ')})"
|
55
|
-
) if opts[:multi] == :fail && crons.size > 1
|
66
|
+
POINTS = %w[
|
67
|
+
minutes? mins? seconds? secs? hours? hou h ].freeze
|
56
68
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
69
|
+
INTERVALS = %w[
|
70
|
+
seconds? minutes? hours? days? months?
|
71
|
+
sec min
|
72
|
+
s m h d M ].freeze
|
73
|
+
|
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
|
88
|
+
|
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
|
97
|
+
|
98
|
+
#
|
99
|
+
# parsers bottom to top #################################################
|
100
|
+
|
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
|
106
|
+
|
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
|
110
|
+
|
111
|
+
def _and_or_or_or_comma(i)
|
112
|
+
rex(nil, i, /[ \t]*(,[ \t]*)?((and|or)[ \t]+|,[ \t]*)/i); end
|
113
|
+
|
114
|
+
def _to_or_dash(i);
|
115
|
+
rex(nil, i, /[ \t]*-[ \t]*|[ \t]+(to|through)[ \t]+/i); end
|
116
|
+
|
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
|
119
|
+
|
120
|
+
def _space(i); rex(nil, i, /[ \t]+/); end
|
121
|
+
def _sep(i); rex(nil, i, /([ \t]+|[ \t]*,[ \t]*)/); end
|
122
|
+
|
123
|
+
def count(i); rex(:count, i, /\d+/); end
|
124
|
+
|
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)
|
62
133
|
end
|
63
134
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
i0s, es = a.partition { |e| e[0] == :interval0 }
|
70
|
-
a = es + i0s
|
71
|
-
# interval0s are fallback
|
72
|
-
|
73
|
-
a.each do |key, val|
|
74
|
-
case key
|
75
|
-
when :biz_day
|
76
|
-
(h[:dow] ||= []) << '1-5'
|
77
|
-
when :name_day
|
78
|
-
(h[:dow] ||= []) << val
|
79
|
-
when :day_range
|
80
|
-
(h[:dow] ||= []) << val.collect { |v| v.to_s[0, 3] }.join('-')
|
81
|
-
when :tz
|
82
|
-
h[:tz] = val
|
83
|
-
when :point
|
84
|
-
process_point(h, *val)
|
85
|
-
when :interval1
|
86
|
-
process_interval1(h, *val[0].to_h.first)
|
87
|
-
when :interval0
|
88
|
-
process_interval0(h, val)
|
89
|
-
end
|
90
|
-
end
|
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
|
137
|
+
|
138
|
+
def weekdays(i); jseq(:weekdays, i, :weekday, :_and_or_or_or_comma); end
|
91
139
|
|
92
|
-
|
140
|
+
def on_the(i); seq(nil, i, :_the, :omonthdays); end
|
93
141
|
|
94
|
-
|
95
|
-
h[:hou] = (h[:hou] || []).uniq.sort
|
96
|
-
h[:dow].sort! if h[:dow]
|
142
|
+
def _minute(i); rex(nil, i, /[ \t]*minute[ \t]+/i) end
|
97
143
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
144
|
+
def _dmin(i)
|
145
|
+
rex(:dmin, i, /[0-5]?[0-9]/)
|
146
|
+
end
|
147
|
+
def and_dmin(i)
|
148
|
+
seq(nil, i, :_and_or_or_or_comma, :_minute, '?', :_dmin)
|
149
|
+
end
|
104
150
|
|
105
|
-
|
151
|
+
def on_minutes(i)
|
152
|
+
seq(:on_minutes, i, :_minute, :_dmin, :and_dmin, '*')
|
153
|
+
end
|
106
154
|
|
107
|
-
|
155
|
+
def on_thex(i);
|
156
|
+
rex(:on_thex, i, /[ \t]*the[ \t]+(hour|minute)[ \t]*/i);
|
108
157
|
end
|
109
158
|
|
110
|
-
def
|
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
|
111
162
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
(h[:min] ||= []) << v1.to_i if v1
|
118
|
-
when :sec, :min
|
119
|
-
(h[key] ||= []) << value[0]
|
120
|
-
end
|
163
|
+
def on_object(i)
|
164
|
+
alt(nil, i, :on_days, :on_weekdays, :on_minutes, :on_thes, :on_thex)
|
165
|
+
end
|
166
|
+
def on_objects(i)
|
167
|
+
jseq(nil, i, :on_object, :_and)
|
121
168
|
end
|
122
169
|
|
123
|
-
|
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)
|
179
|
+
end
|
124
180
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
h[:hou] = [ 0 ]
|
140
|
-
end
|
141
|
-
when 'week'
|
142
|
-
unless h[:min] || h[:hou] || h[:dow]
|
143
|
-
h[:min] = [ 0 ]
|
144
|
-
h[:hou] = [ 0 ]
|
145
|
-
h[:dow] = [ 0 ]
|
146
|
-
end
|
147
|
-
when 'month'
|
148
|
-
unless h[:min] || h[:hou]
|
149
|
-
h[:min] = [ 0 ]
|
150
|
-
h[:hou] = [ 0 ]
|
151
|
-
end
|
152
|
-
(h[:dom] ||= []) << 1
|
153
|
-
when 'year'
|
154
|
-
unless h[:min] || h[:hou]
|
155
|
-
h[:min] = [ 0 ]
|
156
|
-
h[:hou] = [ 0 ]
|
157
|
-
end
|
158
|
-
(h[:dom] ||= []) << 1
|
159
|
-
(h[:mon] ||= []) << 1
|
160
|
-
end
|
181
|
+
def city_tz(i)
|
182
|
+
rex(nil, i, /[A-Z][a-zA-Z0-9+\-]+(\/[A-Z][a-zA-Z0-9+\-_]+){0,2}/)
|
183
|
+
end
|
184
|
+
def named_tz(i)
|
185
|
+
rex(nil, i, /Z|UTC/)
|
186
|
+
end
|
187
|
+
def delta_tz(i)
|
188
|
+
rex(nil, i, /[-+]([01][0-9]|2[0-4])(:?(00|15|30|45))?/)
|
189
|
+
end
|
190
|
+
def tz(i)
|
191
|
+
alt(:tz, i, :city_tz, :named_tz, :delta_tz)
|
192
|
+
end
|
193
|
+
def tzone(i)
|
194
|
+
seq(nil, i, :_in_or_on, '?', :tz)
|
161
195
|
end
|
162
196
|
|
163
|
-
def
|
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)
|
201
|
+
end
|
164
202
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
203
|
+
def ampm(i)
|
204
|
+
rex(:ampm, i, /[ \t]*(am|pm)/i)
|
205
|
+
end
|
206
|
+
def dark(i)
|
207
|
+
rex(:dark, i, /[ \t]*dark/i)
|
208
|
+
end
|
170
209
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
when :mon
|
177
|
-
h[:hou] = [ 0 ]
|
178
|
-
h[:dom] = [ 1 ]
|
179
|
-
h[:mon] = [ value == 1 ? '*' : "*/#{value}" ]
|
180
|
-
when :wee
|
181
|
-
h[:hou] = [ 0 ]
|
182
|
-
h[:dow] = [ 0 ] # Sunday
|
183
|
-
when :day
|
184
|
-
h[:hou] = [ 0 ]
|
185
|
-
h[:dom] = [ value == 1 ? '*' : "*/#{value}" ]
|
186
|
-
when :hou
|
187
|
-
h[:hou] = [ value == 1 ? '*' : "*/#{value}" ]
|
188
|
-
when :min
|
189
|
-
h[:hou] = [ '*' ]
|
190
|
-
h[:min] = [ value == 1 ? '*' : "*/#{value}" ]
|
191
|
-
when :sec
|
192
|
-
h[:hou] = [ '*' ]
|
193
|
-
h[:min] = [ '*' ]
|
194
|
-
h[:sec] = [ value == 1 ? '*' : "*/#{value}" ]
|
195
|
-
end
|
210
|
+
def simple_h(i)
|
211
|
+
rex(:simple_h, i, /#{(0..24).to_a.reverse.join('|')}/)
|
212
|
+
end
|
213
|
+
def simple_hour(i)
|
214
|
+
seq(:simple_hour, i, :simple_h, :ampm, '?')
|
196
215
|
end
|
197
|
-
end
|
198
216
|
|
199
|
-
|
217
|
+
def named_m(i)
|
218
|
+
rex(:named_m, i, NAMED_M_REX)
|
219
|
+
end
|
220
|
+
def named_min(i)
|
221
|
+
seq(nil, i, :_space, :named_m)
|
222
|
+
end
|
200
223
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
224
|
+
def named_h(i)
|
225
|
+
rex(:named_h, i, NAMED_H_REX)
|
226
|
+
end
|
227
|
+
def named_hour(i)
|
228
|
+
seq(:named_hour, i, :named_h, :dark, '?', :named_min, '?', :ampm, '?')
|
229
|
+
end
|
205
230
|
|
206
|
-
|
207
|
-
Fugit::Cron::Parser::WEEKDS + Fugit::Cron::Parser::WEEKDAYS
|
231
|
+
def _point(i); rex(:point, i, POINT_REX); end
|
208
232
|
|
209
|
-
|
210
|
-
|
233
|
+
def counts(i)
|
234
|
+
jseq(nil, i, :count, :_and_or_or_or_comma)
|
235
|
+
end
|
236
|
+
|
237
|
+
def at_p(i)
|
238
|
+
seq(:at_p, i, :_point, :counts)
|
239
|
+
end
|
240
|
+
def at_point(i)
|
241
|
+
jseq(nil, i, :at_p, :_and_or_or)
|
242
|
+
end
|
211
243
|
|
212
|
-
|
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)
|
252
|
+
end
|
253
|
+
def at_objects(i)
|
254
|
+
jseq(nil, i, :at_object, :_and_or_or_or_comma)
|
255
|
+
end
|
213
256
|
|
214
|
-
def
|
215
|
-
|
216
|
-
/(year|month|week|day|hour|min(ute)?|sec(ond)?)(?![a-z])/i)
|
257
|
+
def at(i)
|
258
|
+
seq(:at, i, :_at, '?', :at_objects)
|
217
259
|
end
|
218
260
|
|
219
|
-
def
|
220
|
-
rex(:
|
261
|
+
def interval(i)
|
262
|
+
rex(:interval, i, INTERVAL_REX)
|
221
263
|
end
|
222
264
|
|
223
|
-
|
224
|
-
|
265
|
+
# every day
|
266
|
+
# every 1 minute
|
267
|
+
def every_interval(i)
|
268
|
+
seq(:every_interval, i, :count, '?', :interval)
|
225
269
|
end
|
226
270
|
|
227
|
-
def
|
228
|
-
rex(:
|
271
|
+
def every_single_interval(i)
|
272
|
+
rex(:every_single_interval, i, /(1[ \t]+)?(week|year)/)
|
229
273
|
end
|
230
|
-
|
231
|
-
|
274
|
+
|
275
|
+
def to_weekday(i)
|
276
|
+
seq(:to_weekday, i, :weekday, :_to_or_dash, :weekday)
|
232
277
|
end
|
233
278
|
|
234
|
-
def
|
235
|
-
|
279
|
+
def weekday_range(i)
|
280
|
+
alt(nil, i, :to_weekday, :weekdays)
|
236
281
|
end
|
237
|
-
|
238
|
-
|
282
|
+
|
283
|
+
def to_omonthday(i)
|
284
|
+
seq(:to_omonthday, i,
|
285
|
+
:_the, '?', :omonthday, :_to, :_the, '?', :omonthday)
|
239
286
|
end
|
240
287
|
|
241
|
-
def
|
242
|
-
|
288
|
+
def to_hour(i)
|
289
|
+
seq(:to_hour, i, :at_object, :_to, :at_object)
|
243
290
|
end
|
244
291
|
|
245
|
-
def
|
246
|
-
|
292
|
+
def from_object(i)
|
293
|
+
alt(nil, i, :to_weekday, :to_omonthday, :to_hour)
|
294
|
+
end
|
295
|
+
def from_objects(i)
|
296
|
+
jseq(nil, i, :from_object, :_and_or_or)
|
297
|
+
end
|
298
|
+
def from(i)
|
299
|
+
seq(nil, i, :_from, '?', :from_objects)
|
300
|
+
end
|
247
301
|
|
248
|
-
|
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)
|
307
|
+
end
|
249
308
|
|
250
|
-
def
|
251
|
-
|
309
|
+
def otm(i)
|
310
|
+
rex(nil, i, /[ \t]+of the month/)
|
252
311
|
end
|
253
312
|
|
254
|
-
|
255
|
-
|
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)
|
256
320
|
end
|
257
|
-
|
258
|
-
|
321
|
+
|
322
|
+
def every_named(i)
|
323
|
+
rex(:every_named, i, /weekday/i)
|
259
324
|
end
|
260
|
-
def _tz(i); alt(:tz, i, :_tz_delta, :_tz_name); end
|
261
325
|
|
262
|
-
def
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
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)
|
331
|
+
end
|
332
|
+
def every_objects(i)
|
333
|
+
jseq(nil, i, :every_object, :_and_or_or)
|
270
334
|
end
|
271
335
|
|
272
|
-
def
|
273
|
-
|
336
|
+
def every(i)
|
337
|
+
seq(:every, i, :_every, :every_objects)
|
274
338
|
end
|
275
339
|
|
276
|
-
def
|
277
|
-
alt(
|
278
|
-
|
279
|
-
|
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)
|
280
345
|
end
|
281
346
|
|
282
|
-
|
347
|
+
#
|
348
|
+
# rewrite parsed tree ###################################################
|
283
349
|
|
284
|
-
def
|
285
|
-
|
286
|
-
:flag,
|
287
|
-
:interval1,
|
288
|
-
:point,
|
289
|
-
:interval0,
|
290
|
-
:day_range, :biz_day, :name_day,
|
291
|
-
:_tz)
|
350
|
+
def slot(key, data0, data1=nil, opts=nil)
|
351
|
+
Slot.new(key, data0, data1, opts)
|
292
352
|
end
|
293
353
|
|
294
|
-
def
|
354
|
+
def _rewrite_subs(t, key=nil)
|
355
|
+
t.subgather(key).collect { |ct| rewrite(ct) }
|
356
|
+
end
|
357
|
+
def _rewrite_sub(t, key=nil)
|
358
|
+
st = t.sublookup(key)
|
359
|
+
st ? rewrite(st) : nil
|
360
|
+
end
|
295
361
|
|
296
|
-
def
|
297
|
-
|
362
|
+
def rewrite_dmin(t)
|
363
|
+
t.strinp
|
364
|
+
end
|
298
365
|
|
299
|
-
|
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)
|
371
|
+
end
|
300
372
|
|
301
|
-
def
|
302
|
-
|
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
|
303
380
|
end
|
304
|
-
alias rewrite_flag _rewrite
|
305
|
-
alias rewrite_interval0 _rewrite
|
306
|
-
alias rewrite_biz_day _rewrite
|
307
381
|
|
308
|
-
def
|
309
|
-
|
382
|
+
def rewrite_on_thes(t)
|
383
|
+
_rewrite_subs(t, :omonthday)
|
384
|
+
end
|
385
|
+
def rewrite_on_days(t)
|
386
|
+
_rewrite_subs(t, :monthday)
|
310
387
|
end
|
311
388
|
|
312
|
-
def
|
313
|
-
|
389
|
+
def rewrite_on(t)
|
390
|
+
_rewrite_subs(t)
|
314
391
|
end
|
315
392
|
|
316
|
-
def
|
317
|
-
|
393
|
+
def rewrite_monthday(t)
|
394
|
+
slot(:monthday, t.string.to_i)
|
318
395
|
end
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
v += 12 if vs[1] == 'pm'
|
323
|
-
[ :hour, v, 0 ]
|
396
|
+
|
397
|
+
def rewrite_omonthday(t)
|
398
|
+
slot(:monthday, OMONTHDAYS[t.string.downcase])
|
324
399
|
end
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
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
|
330
412
|
end
|
331
|
-
|
332
|
-
|
333
|
-
|
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
|
334
420
|
end
|
335
421
|
|
336
|
-
def
|
337
|
-
|
338
|
-
|
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
|
339
440
|
end
|
340
441
|
|
341
|
-
def
|
342
|
-
|
442
|
+
def rewrite_every_named(t)
|
443
|
+
|
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
|
343
449
|
end
|
344
450
|
|
345
451
|
def rewrite_tz(t)
|
346
|
-
|
452
|
+
slot(:tz, t.string)
|
347
453
|
end
|
348
454
|
|
349
|
-
def
|
350
|
-
|
455
|
+
def rewrite_weekday(t)
|
456
|
+
Fugit::Cron::Parser::WEEKDS.index(t.string[0, 3].downcase)
|
351
457
|
end
|
352
458
|
|
353
|
-
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
|
464
|
+
|
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
|
470
|
+
|
471
|
+
def rewrite_to_omonthday(t)
|
472
|
+
md0, md1 = _rewrite_subs(t, :omonthday).collect(&:_data0)
|
473
|
+
slot(:monthday, "#{md0}-#{md1}")
|
474
|
+
end
|
475
|
+
|
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
|
482
|
+
|
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)
|
488
|
+
end
|
489
|
+
|
490
|
+
def rewrite_named_hour(t)
|
491
|
+
|
492
|
+
ht = t.sublookup(:named_h)
|
493
|
+
mt = t.sublookup(:named_m)
|
494
|
+
apt = t.sublookup(:ampm)
|
495
|
+
|
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 ]
|
502
|
+
|
503
|
+
h += 12 if h < 13 && apt && apt.strinpd == 'pm'
|
504
|
+
|
505
|
+
slot(:hm, h, m)
|
506
|
+
end
|
507
|
+
|
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)
|
516
|
+
end
|
517
|
+
|
518
|
+
def rewrite_at(t)
|
519
|
+
_rewrite_subs(t)
|
520
|
+
end
|
521
|
+
|
522
|
+
def rewrite_every(t)
|
523
|
+
_rewrite_sub(t)
|
524
|
+
end
|
354
525
|
|
526
|
+
def rewrite_nat(t)
|
355
527
|
#Raabro.pp(t, colours: true)
|
356
|
-
|
528
|
+
Fugit::Nat::SlotGroup.new(_rewrite_subs(t).flatten)
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
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
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
class SlotGroup
|
585
|
+
|
586
|
+
def initialize(slots)
|
587
|
+
|
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
|
609
|
+
end
|
610
|
+
|
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
|
626
|
+
|
627
|
+
protected
|
628
|
+
|
629
|
+
def make_slot(key, data0, data1=nil)
|
630
|
+
|
631
|
+
Fugit::Nat::Slot.new(key, data0, data1)
|
632
|
+
end
|
633
|
+
|
634
|
+
def determine_hms
|
635
|
+
|
636
|
+
return [ [ [ '*' ], [ '*' ] ] ] if @hms.empty?
|
637
|
+
|
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
|
645
|
+
|
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
|
655
|
+
end
|
656
|
+
|
657
|
+
def parse_cron(hm)
|
658
|
+
|
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' ]
|
669
|
+
|
670
|
+
s = a
|
671
|
+
.collect { |e| e.uniq.sort.collect(&:to_s).join(',') }
|
672
|
+
.join(' ')
|
673
|
+
|
674
|
+
Fugit::Cron.parse(s)
|
675
|
+
end
|
676
|
+
|
677
|
+
def slot(key, default)
|
678
|
+
s = @slots[key]
|
679
|
+
s ? s.data0 : [ default ]
|
357
680
|
end
|
358
681
|
end
|
359
682
|
end
|
data/lib/fugit/parse.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.4.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: 2020-
|
11
|
+
date: 2020-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: raabro
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.4'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.4'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: et-orbi
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,15 +93,15 @@ files:
|
|
93
93
|
- lib/fugit/misc.rb
|
94
94
|
- lib/fugit/nat.rb
|
95
95
|
- lib/fugit/parse.rb
|
96
|
-
homepage:
|
96
|
+
homepage: https://github.com/floraison/fugit
|
97
97
|
licenses:
|
98
98
|
- MIT
|
99
99
|
metadata:
|
100
|
-
changelog_uri:
|
101
|
-
documentation_uri:
|
102
|
-
bug_tracker_uri:
|
103
|
-
homepage_uri:
|
104
|
-
source_code_uri:
|
100
|
+
changelog_uri: https://github.com/floraison/fugit/blob/master/CHANGELOG.md
|
101
|
+
documentation_uri: https://github.com/floraison/fugit
|
102
|
+
bug_tracker_uri: https://github.com/floraison/fugit/issues
|
103
|
+
homepage_uri: https://github.com/floraison/fugit
|
104
|
+
source_code_uri: https://github.com/floraison/fugit
|
105
105
|
post_install_message:
|
106
106
|
rdoc_options: []
|
107
107
|
require_paths:
|