flor 0.14.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +9 -0
- data/CREDITS.md +21 -0
- data/LICENSE.txt +4 -1
- data/Makefile +4 -0
- data/README.md +8 -0
- data/flor.gemspec +10 -10
- data/lib/flor.rb +2 -2
- data/lib/flor/changes.rb +3 -3
- data/lib/flor/colours.rb +14 -8
- data/lib/flor/conf.rb +63 -58
- data/lib/flor/core.rb +4 -4
- data/lib/flor/core/executor.rb +65 -29
- data/lib/flor/core/node.rb +37 -20
- data/lib/flor/core/procedure.rb +182 -40
- data/lib/flor/core/texecutor.rb +125 -52
- data/lib/flor/djan.rb +111 -82
- data/lib/flor/dollar.rb +31 -30
- data/lib/flor/flor.rb +314 -237
- data/lib/flor/id.rb +7 -2
- data/lib/flor/log.rb +250 -245
- data/lib/flor/parser.rb +72 -38
- data/lib/flor/pcore/_arr.rb +10 -10
- data/lib/flor/pcore/_att.rb +49 -14
- data/lib/flor/pcore/_coll.rb +18 -0
- data/lib/flor/pcore/_obj.rb +23 -7
- data/lib/flor/pcore/_pat_.rb +1 -1
- data/lib/flor/pcore/_pat_guard.rb +8 -0
- data/lib/flor/pcore/_pat_obj.rb +3 -3
- data/lib/flor/pcore/_pat_or.rb +4 -0
- data/lib/flor/pcore/_pat_regex.rb +24 -0
- data/lib/flor/pcore/_skip.rb +4 -0
- data/lib/flor/pcore/_val.rb +0 -1
- data/lib/flor/pcore/all.rb +111 -0
- data/lib/flor/pcore/any.rb +83 -0
- data/lib/flor/pcore/arith.rb +35 -6
- data/lib/flor/pcore/break.rb +39 -1
- data/lib/flor/pcore/case.rb +82 -4
- data/lib/flor/pcore/cmp.rb +7 -7
- data/lib/flor/pcore/collect.rb +50 -0
- data/lib/flor/pcore/cond.rb +17 -3
- data/lib/flor/pcore/cursor.rb +8 -2
- data/lib/flor/pcore/detect.rb +45 -0
- data/lib/flor/pcore/each.rb +52 -0
- data/lib/flor/pcore/empty.rb +60 -0
- data/lib/flor/pcore/filter.rb +94 -0
- data/lib/flor/pcore/find.rb +67 -0
- data/lib/flor/pcore/for_each.rb +65 -0
- data/lib/flor/pcore/includes.rb +32 -0
- data/lib/flor/pcore/inject.rb +55 -0
- data/lib/flor/pcore/iterator.rb +151 -0
- data/lib/flor/pcore/keys.rb +60 -0
- data/lib/flor/pcore/length.rb +34 -7
- data/lib/flor/pcore/logo.rb +18 -0
- data/lib/flor/pcore/loop.rb +4 -0
- data/lib/flor/pcore/map.rb +77 -46
- data/lib/flor/pcore/match.rb +8 -2
- data/lib/flor/pcore/matchr.rb +4 -5
- data/lib/flor/pcore/move.rb +3 -3
- data/lib/flor/pcore/noeval.rb +13 -0
- data/lib/flor/pcore/not.rb +16 -0
- data/lib/flor/pcore/on.rb +172 -0
- data/lib/flor/pcore/on_cancel.rb +54 -0
- data/lib/flor/pcore/on_error.rb +68 -0
- data/lib/flor/pcore/rand.rb +2 -2
- data/lib/flor/pcore/range.rb +2 -1
- data/lib/flor/pcore/reduce.rb +124 -0
- data/lib/flor/pcore/reverse.rb +46 -0
- data/lib/flor/pcore/select.rb +72 -0
- data/lib/flor/pcore/set.rb +8 -0
- data/lib/flor/pcore/stall.rb +10 -0
- data/lib/flor/pcore/to_array.rb +61 -0
- data/lib/flor/pcore/until.rb +34 -0
- data/lib/flor/punit/cancel.rb +30 -5
- data/lib/flor/punit/ccollect.rb +11 -0
- data/lib/flor/punit/cmap.rb +10 -5
- data/lib/flor/punit/concurrence.rb +42 -51
- data/lib/flor/punit/cron.rb +33 -0
- data/lib/flor/punit/do_trap.rb +42 -0
- data/lib/flor/punit/every.rb +48 -13
- data/lib/flor/punit/graft.rb +3 -3
- data/lib/flor/punit/on_timeout.rb +38 -0
- data/lib/flor/punit/schedule.rb +69 -6
- data/lib/flor/punit/signal.rb +54 -0
- data/lib/flor/punit/sleep.rb +1 -1
- data/lib/flor/punit/task.rb +4 -1
- data/lib/flor/punit/trap.rb +188 -13
- data/lib/flor/tools/shell.rb +408 -62
- data/lib/flor/tools/shell_out.rb +31 -0
- data/lib/flor/unit.rb +1 -1
- data/lib/flor/unit/caller.rb +177 -0
- data/lib/flor/unit/executor.rb +1 -0
- data/lib/flor/unit/ganger.rb +15 -21
- data/lib/flor/unit/hook.rb +1 -1
- data/lib/flor/unit/hooker.rb +22 -10
- data/lib/flor/unit/loader.rb +22 -22
- data/lib/flor/unit/logger.rb +63 -36
- data/lib/flor/unit/models.rb +6 -1
- data/lib/flor/unit/models/execution.rb +12 -1
- data/lib/flor/unit/models/message.rb +7 -0
- data/lib/flor/unit/models/trap.rb +31 -17
- data/lib/flor/unit/scheduler.rb +18 -10
- data/lib/flor/unit/storage.rb +83 -23
- data/lib/flor/unit/waiter.rb +1 -2
- metadata +96 -52
- data/lib/flor/deep.rb +0 -144
- data/lib/flor/punit/on.rb +0 -57
- data/lib/flor/unit/runner.rb +0 -84
- data/match.md +0 -22
data/lib/flor/punit/cancel.rb
CHANGED
@@ -9,6 +9,27 @@ class Flor::Pro::Cancel < Flor::Procedure
|
|
9
9
|
# sequence
|
10
10
|
# cancel ref: 'blue'
|
11
11
|
# ```
|
12
|
+
# You can drop the `ref:`
|
13
|
+
# ```
|
14
|
+
# concurrence
|
15
|
+
# sequence tag: 'blue'
|
16
|
+
# sequence
|
17
|
+
# cancel 'blue'
|
18
|
+
# ```
|
19
|
+
#
|
20
|
+
# It's also OK to use nids directly:
|
21
|
+
# ```
|
22
|
+
# concurrence # 0
|
23
|
+
# sequence # 0_0
|
24
|
+
# # ...
|
25
|
+
# sequence # 0_1
|
26
|
+
# cancel nid: '0_0'
|
27
|
+
# # or
|
28
|
+
# #cancel '0_0'
|
29
|
+
# ```
|
30
|
+
# But it's kind of brittle compared to using tags.
|
31
|
+
#
|
32
|
+
# # TODO document "kill"
|
12
33
|
|
13
34
|
name 'cancel', 'kill'
|
14
35
|
# ruote had "undo" as well...
|
@@ -26,19 +47,23 @@ class Flor::Pro::Cancel < Flor::Procedure
|
|
26
47
|
.inject([]) { |a, (k, v)|
|
27
48
|
v = Array(v)
|
28
49
|
a.concat(v) if v.all? { |e| e.is_a?(String) }
|
29
|
-
a
|
30
|
-
} +
|
50
|
+
a } +
|
31
51
|
att_a('nid') +
|
32
52
|
att_a('ref')
|
33
53
|
|
34
54
|
nids, tags = targets.partition { |t| Flor.is_nid?(t) }
|
35
|
-
|
36
55
|
nids += tags_to_nids(tags)
|
56
|
+
nids = nids.uniq
|
37
57
|
|
38
58
|
fla = @node['heap']
|
39
59
|
|
40
|
-
|
41
|
-
|
60
|
+
messages = nids
|
61
|
+
.collect { |nid| wrap_cancel('nid' => nid, 'flavour' => fla)[0] }
|
62
|
+
|
63
|
+
messages = messages + wrap_reply \
|
64
|
+
unless nids.find { |nid| is_ancestor_node?(nid) }
|
65
|
+
|
66
|
+
messages
|
42
67
|
end
|
43
68
|
end
|
44
69
|
|
data/lib/flor/punit/cmap.rb
CHANGED
@@ -26,20 +26,25 @@ class Flor::Pro::Cmap < Flor::Procedure
|
|
26
26
|
|
27
27
|
fun = payload['ret']
|
28
28
|
|
29
|
-
fail
|
30
|
-
|
31
|
-
) unless Flor.is_func_tree?(fun)
|
29
|
+
fail Flor::FlorError.new("'#{tree[0]}' expects a function", self) \
|
30
|
+
unless Flor.is_func_tree?(fun)
|
32
31
|
|
33
32
|
@node['fun'] = fun
|
34
33
|
|
35
34
|
att(nil)
|
36
|
-
.collect
|
35
|
+
.collect
|
36
|
+
.with_index { |e, i|
|
37
|
+
apply(fun, [ e, i ], tree[2], vars: { 'idx' => i }) }
|
37
38
|
.flatten(1)
|
38
39
|
end
|
39
40
|
|
40
41
|
def receive_elt
|
41
42
|
|
42
|
-
|
43
|
+
idx =
|
44
|
+
(message['rvars'] && message['rvars']['idx']) ||
|
45
|
+
Flor.sub_nid(message['from']) - 1 # fall back :-(
|
46
|
+
|
47
|
+
@node['col'][idx] = payload['ret']
|
43
48
|
|
44
49
|
return [] if cnodes_any?
|
45
50
|
|
@@ -47,12 +47,25 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
47
47
|
# being already gone).
|
48
48
|
#
|
49
49
|
# `remaining:` may be shortened to `rem:`.
|
50
|
+
#
|
50
51
|
# ```
|
51
52
|
# concurrence expect: 1 rem: 'forget'
|
53
|
+
# #
|
54
|
+
# # will forget child 'alpha' as soon as child 'bravo' replies,
|
55
|
+
# # and vice versa.
|
56
|
+
# #
|
57
|
+
# task 'alpha'
|
58
|
+
# task 'bravo'
|
59
|
+
# ```
|
60
|
+
#
|
61
|
+
# ```
|
62
|
+
# concurrence expect: 1 rem: 'wait'
|
63
|
+
# #
|
64
|
+
# # if 'alpha' replies before 'bravo', the concurrence will wait for
|
65
|
+
# # 'bravo', without cancelling it. And vice versa.
|
66
|
+
# #
|
52
67
|
# task 'alpha'
|
53
68
|
# task 'bravo'
|
54
|
-
# # will forget child 'alpha' as soon as child 'bravo' replies,
|
55
|
-
# # and vice versa.
|
56
69
|
# ```
|
57
70
|
|
58
71
|
name 'concurrence'
|
@@ -60,12 +73,16 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
60
73
|
def pre_execute
|
61
74
|
|
62
75
|
@node['atts'] = []
|
76
|
+
@node['payloads'] = {}
|
63
77
|
end
|
64
78
|
|
65
79
|
def receive_last_att
|
66
80
|
|
67
81
|
return wrap_reply unless children[@ncid]
|
68
82
|
|
83
|
+
@node['receiver'] = determine_receiver
|
84
|
+
@node['merger'] = determine_merger
|
85
|
+
|
69
86
|
(@ncid..children.size - 1)
|
70
87
|
.map { |i| execute_child(i, 0, 'payload' => payload.copy_current) }
|
71
88
|
.flatten(1)
|
@@ -75,23 +92,32 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
75
92
|
|
76
93
|
def receive_non_att
|
77
94
|
|
78
|
-
@node['
|
79
|
-
@node['merger'] ||= determine_merger
|
95
|
+
@node['payloads'][@message['from']] = @message['payload']
|
80
96
|
|
81
|
-
|
97
|
+
over = @node['over'] || invoke_receiver
|
98
|
+
just_over = over && ! @node['over']
|
99
|
+
@node['over'] ||= just_over
|
82
100
|
|
83
|
-
|
84
|
-
|
101
|
+
@node['merged_payload'] ||= just_over ? invoke_merger : nil
|
102
|
+
rem = just_over ? (att(:remaining, :rem) || 'cancel') : nil
|
85
103
|
|
86
|
-
|
104
|
+
cancel_children(rem) + reply_to_parent(rem)
|
105
|
+
end
|
87
106
|
|
88
|
-
|
107
|
+
def cancel_children(rem)
|
89
108
|
|
90
|
-
|
91
|
-
|
109
|
+
(rem && rem != 'forget') ? wrap_cancel_children : []
|
110
|
+
end
|
111
|
+
|
112
|
+
def reply_to_parent(rem)
|
92
113
|
|
93
|
-
|
94
|
-
|
114
|
+
return [] \
|
115
|
+
if @node['replied']
|
116
|
+
return [] \
|
117
|
+
if @node['payloads'].size < non_att_count && ( ! rem || rem == 'wait')
|
118
|
+
|
119
|
+
@node['replied'] = true
|
120
|
+
wrap_reply('payload' => @node['merged_payload'])
|
95
121
|
end
|
96
122
|
|
97
123
|
def receive_from_child_when_closed
|
@@ -119,51 +145,16 @@ class Flor::Pro::Concurrence < Flor::Procedure
|
|
119
145
|
'default_merge'
|
120
146
|
end
|
121
147
|
|
122
|
-
def
|
123
|
-
|
124
|
-
# remaining:
|
125
|
-
# * 'cancel' (default)
|
126
|
-
# * 'forget'
|
127
|
-
# * 'wait'
|
128
|
-
|
129
|
-
rem = att(:remaining, :rem)
|
130
|
-
|
131
|
-
return [] if rem == 'forget'
|
132
|
-
|
133
|
-
wrap_cancel_children
|
134
|
-
end
|
135
|
-
|
136
|
-
def invoke_receiver
|
137
|
-
|
138
|
-
# TODO: receiver function case
|
139
|
-
|
140
|
-
self.send(@node['receiver'])
|
141
|
-
end
|
142
|
-
|
143
|
-
def invoke_merger
|
144
|
-
|
145
|
-
# TODO: merger function case
|
146
|
-
|
147
|
-
self.send(@node['merger'])
|
148
|
-
end
|
149
|
-
|
150
|
-
def store_payload
|
151
|
-
|
152
|
-
(@node['payloads'] ||= {})[@message['from']] =
|
153
|
-
@message['payload']
|
154
|
-
end
|
148
|
+
def invoke_receiver; self.send(@node['receiver']); end
|
149
|
+
def invoke_merger; self.send(@node['merger']); end
|
155
150
|
|
156
151
|
def default_receive
|
157
152
|
|
158
|
-
|
159
|
-
|
160
|
-
@node['payloads'].size >= non_att_children.size
|
153
|
+
@node['payloads'].size >= non_att_count
|
161
154
|
end
|
162
155
|
|
163
156
|
def expect_integer_receive
|
164
157
|
|
165
|
-
store_payload
|
166
|
-
|
167
158
|
@node['payloads'].size >= att(:expect)
|
168
159
|
end
|
169
160
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
require 'flor/punit/schedule'
|
3
|
+
|
4
|
+
|
5
|
+
class Flor::Pro::Cron < Flor::Macro::Schedule
|
6
|
+
#
|
7
|
+
# "cron" is a macro procedure.
|
8
|
+
#
|
9
|
+
# ```
|
10
|
+
# cron '0 0 1 jan *'
|
11
|
+
# task albert 'take out garbage'
|
12
|
+
# ```
|
13
|
+
#
|
14
|
+
# is automatically turned into:
|
15
|
+
#
|
16
|
+
# ```
|
17
|
+
# schedule cron: '0 0 1 jan *'
|
18
|
+
# def msg
|
19
|
+
# task albert 'take out garbage'
|
20
|
+
# ```
|
21
|
+
#
|
22
|
+
# ## see also
|
23
|
+
#
|
24
|
+
# Schedule, and every.
|
25
|
+
|
26
|
+
name 'cron'
|
27
|
+
|
28
|
+
def rewrite_tree
|
29
|
+
|
30
|
+
rewrite_schedule_tree('cron')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
class Flor::Pro::DoTrap < Flor::Macro
|
3
|
+
#
|
4
|
+
# A version of trap that accepts a block instead of a function.
|
5
|
+
#
|
6
|
+
# do-trap accepts the same attributes as [trap][trap.md] does.
|
7
|
+
#
|
8
|
+
# ```
|
9
|
+
# sequence
|
10
|
+
# do-trap 'terminated'
|
11
|
+
# trace "terminated(f:$(msg.from))"
|
12
|
+
# trace "here($(nid))"
|
13
|
+
# ```
|
14
|
+
# which traces to:
|
15
|
+
# ```
|
16
|
+
# here(0_1_0_0)
|
17
|
+
# terminated(f:0)
|
18
|
+
# ```
|
19
|
+
#
|
20
|
+
# ## see also
|
21
|
+
#
|
22
|
+
# Trap, on, signal.
|
23
|
+
|
24
|
+
name 'do-trap'
|
25
|
+
|
26
|
+
def rewrite_tree
|
27
|
+
|
28
|
+
l = tree[2]
|
29
|
+
|
30
|
+
th = [ 'trap', [], l, *tree[3] ]
|
31
|
+
att_children.each { |ac| th[1] << Flor.dup(ac) }
|
32
|
+
|
33
|
+
td = [ 'def', [], l ]
|
34
|
+
td[1] << [ '_att', [ [ 'msg', [], l ] ], l ]
|
35
|
+
non_att_children.each { |nac| td[1] << Flor.dup(nac) }
|
36
|
+
|
37
|
+
th[1] << td
|
38
|
+
|
39
|
+
th
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
data/lib/flor/punit/every.rb
CHANGED
@@ -1,22 +1,57 @@
|
|
1
1
|
|
2
|
-
|
2
|
+
require 'flor/punit/schedule'
|
3
|
+
|
4
|
+
|
5
|
+
class Flor::Pro::Every < Flor::Macro::Schedule
|
6
|
+
#
|
7
|
+
# "every" is a macro procedure.
|
8
|
+
#
|
9
|
+
# ```
|
10
|
+
# every 'day at midnight'
|
11
|
+
# task 'alpha'
|
12
|
+
# ```
|
13
|
+
#
|
14
|
+
# is automatically turned into:
|
15
|
+
#
|
16
|
+
# ```
|
17
|
+
# schedule every: 'day at midnight'
|
18
|
+
# def msg
|
19
|
+
# task 'alpha'
|
20
|
+
# ```
|
21
|
+
#
|
22
|
+
# ## time strings
|
23
|
+
#
|
24
|
+
# Every understands time durations and, somehow, frequencies.
|
25
|
+
#
|
26
|
+
# ```
|
27
|
+
# every: "5m10s"
|
28
|
+
# every: "5 minutes and 10 seconds"
|
29
|
+
# ```
|
30
|
+
#
|
31
|
+
# Fugit translates `every: 'day at five'` into `cron: '0 5 * * *'`.
|
32
|
+
#
|
33
|
+
# ```
|
34
|
+
# every: 'day at five' # ==> '0 5 * * *'
|
35
|
+
# every: 'weekday at five' # ==> '0 5 * * 1,2,3,4,5'
|
36
|
+
# every: 'day at 5 pm' # ==> '0 17 * * *'
|
37
|
+
# every: 'tuesday at 5 pm' # ==> '0 17 * * 2'
|
38
|
+
# every: 'wed at 5 pm' # ==> '0 17 * * 3'
|
39
|
+
# every: 'day at 16:30' # ==> '30 16 * * *'
|
40
|
+
# every: 'day at noon' # ==> '0 12 * * *'
|
41
|
+
# every: 'day at midnight' # ==> '0 0 * * *'
|
42
|
+
# every: 'tuesday and monday at 5pm' # ==> '0 17 * * 1,2'
|
43
|
+
# every: 'wed or Monday at 5pm and 11' # ==> '0 11,17 * * 1,3'
|
44
|
+
# ```
|
45
|
+
#
|
46
|
+
# ## see also
|
47
|
+
#
|
48
|
+
# Cron, at, in, every, and sleep.
|
3
49
|
|
4
50
|
name 'every'
|
5
51
|
|
6
52
|
def rewrite_tree
|
7
53
|
|
8
|
-
|
9
|
-
|
10
|
-
th = [ 'schedule', [], l, *tree[3] ]
|
11
|
-
att_children.each { |ac| th[1] << Flor.dup(ac) }
|
12
|
-
|
13
|
-
td = [ 'def', [], l ]
|
14
|
-
td[1] << [ '_att', [ [ 'msg', [], l ] ], l ]
|
15
|
-
non_att_children.each { |nac| td[1] << Flor.dup(nac) }
|
16
|
-
|
17
|
-
th[1] << td
|
18
|
-
|
19
|
-
th
|
54
|
+
rewrite_schedule_tree(nil)
|
20
55
|
end
|
21
56
|
end
|
22
57
|
|
data/lib/flor/punit/graft.rb
CHANGED
@@ -56,11 +56,11 @@ class Flor::Pro::Graft < Flor::Procedure
|
|
56
56
|
source_path, source =
|
57
57
|
@executor.unit.loader.library(domain, sub, subflows: true)
|
58
58
|
|
59
|
-
fail
|
60
|
-
"no subtree #{sub.inspect} found (domain #{domain.inspect})"
|
59
|
+
fail Flor::FlorError.new(
|
60
|
+
"no subtree #{sub.inspect} found (domain #{domain.inspect})", self
|
61
61
|
) unless source
|
62
62
|
|
63
|
-
tree = Flor
|
63
|
+
tree = Flor.parse(source, source_path, {})
|
64
64
|
|
65
65
|
# graft subtree into parent node
|
66
66
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
class Flor::Pro::OnTimeout < Flor::Procedure
|
3
|
+
#
|
4
|
+
# Counterpart to the on_timeout: attribute.
|
5
|
+
#
|
6
|
+
# Sets the on_timeout "attribute" of the parent procedure.
|
7
|
+
#
|
8
|
+
# ```
|
9
|
+
# set l []
|
10
|
+
# sequence timeout: '1s'
|
11
|
+
# push l 0
|
12
|
+
# on_timeout (def msg \ push l "$(msg.point):$(msg.nid)")
|
13
|
+
# stall _
|
14
|
+
# push l 2
|
15
|
+
# push l 3
|
16
|
+
# ```
|
17
|
+
# Ends up with `[ 0, 'cancel:0_1', 3 ]` in the variable `l`. The on_timeout
|
18
|
+
# is set on the "sequence".
|
19
|
+
#
|
20
|
+
# ## see also
|
21
|
+
#
|
22
|
+
# On, on_error, on_cancel.
|
23
|
+
|
24
|
+
name 'on_timeout'
|
25
|
+
|
26
|
+
def pre_execute
|
27
|
+
|
28
|
+
unatt_unkeyed_children
|
29
|
+
end
|
30
|
+
|
31
|
+
def receive_non_att
|
32
|
+
|
33
|
+
store_on(:timeout)
|
34
|
+
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
data/lib/flor/punit/schedule.rb
CHANGED
@@ -9,7 +9,38 @@ class Flor::Pro::Schedule < Flor::Procedure
|
|
9
9
|
# check_systems
|
10
10
|
# ```
|
11
11
|
#
|
12
|
-
#
|
12
|
+
# It understands `cron:`, `at:`, `in:`, and `every:`.
|
13
|
+
#
|
14
|
+
# The time string parsing is done by the
|
15
|
+
# [fugit](https://github.com/floraison/fugit) gem.
|
16
|
+
#
|
17
|
+
# ## every:
|
18
|
+
#
|
19
|
+
# Every understands time durations and, somehow, frequencies.
|
20
|
+
#
|
21
|
+
# ```
|
22
|
+
# every: "5m10s"
|
23
|
+
# every: "5 minutes and 10 seconds"
|
24
|
+
# ```
|
25
|
+
#
|
26
|
+
# Fugit translates `every: 'day at five'` into `cron: '0 5 * * *'`.
|
27
|
+
#
|
28
|
+
# ```
|
29
|
+
# every: 'day at five' # ==> '0 5 * * *'
|
30
|
+
# every: 'weekday at five' # ==> '0 5 * * 1,2,3,4,5'
|
31
|
+
# every: 'day at 5 pm' # ==> '0 17 * * *'
|
32
|
+
# every: 'tuesday at 5 pm' # ==> '0 17 * * 2'
|
33
|
+
# every: 'wed at 5 pm' # ==> '0 17 * * 3'
|
34
|
+
# every: 'day at 16:30' # ==> '30 16 * * *'
|
35
|
+
# every: 'day at noon' # ==> '0 12 * * *'
|
36
|
+
# every: 'day at midnight' # ==> '0 0 * * *'
|
37
|
+
# every: 'tuesday and monday at 5pm' # ==> '0 17 * * 1,2'
|
38
|
+
# every: 'wed or Monday at 5pm and 11' # ==> '0 11,17 * * 1,3'
|
39
|
+
# ```
|
40
|
+
#
|
41
|
+
# ## see also
|
42
|
+
#
|
43
|
+
# Cron, at, in, every, and sleep.
|
13
44
|
|
14
45
|
name 'schedule'
|
15
46
|
|
@@ -22,18 +53,18 @@ class Flor::Pro::Schedule < Flor::Procedure
|
|
22
53
|
|
23
54
|
fun = @fcid > 0 ? payload['ret'] : nil
|
24
55
|
|
25
|
-
fail
|
26
|
-
"missing a function to call when the scheduler triggers"
|
56
|
+
fail Flor::FlorError.new(
|
57
|
+
"missing a function to call when the scheduler triggers", self
|
27
58
|
) unless fun
|
28
59
|
|
29
|
-
m = apply(fun, [], tree[2], false).first
|
60
|
+
m = apply(fun, [], tree[2], anid: false).first
|
30
61
|
|
31
62
|
t, s =
|
32
63
|
@node['atts'].find { |k, v| %w[ cron at in every ].include?(k) } ||
|
33
64
|
@node['atts'].find { |k, v| k == nil }
|
34
65
|
|
35
|
-
fail
|
36
|
-
"missing a schedule"
|
66
|
+
fail Flor::FlorError.new(
|
67
|
+
"missing a schedule", self
|
37
68
|
) unless s
|
38
69
|
|
39
70
|
@node['scheduled'] = true
|
@@ -57,3 +88,35 @@ class Flor::Pro::Schedule < Flor::Procedure
|
|
57
88
|
end
|
58
89
|
end
|
59
90
|
|
91
|
+
|
92
|
+
class Flor::Macro::Schedule < Flor::Macro
|
93
|
+
|
94
|
+
def rewrite_schedule_tree(schedule_type)
|
95
|
+
|
96
|
+
atts = att_children
|
97
|
+
schedule_i = atts.index { |at| at[1].size == 1 }
|
98
|
+
|
99
|
+
fail Flor::FlorError.new("schedule not found in #{tree.inspect}", self) \
|
100
|
+
unless schedule_i
|
101
|
+
|
102
|
+
schedule =
|
103
|
+
schedule_type ?
|
104
|
+
Flor.dup(atts.delete_at(schedule_i)[1][0]) :
|
105
|
+
nil
|
106
|
+
|
107
|
+
l = tree[2]
|
108
|
+
|
109
|
+
th = [ 'schedule', [], l, *tree[3] ]
|
110
|
+
th[1] << [ '_att', [ [ schedule_type, [], l ], schedule ], l ] if schedule
|
111
|
+
atts.each { |ac| th[1] << Flor.dup(ac) }
|
112
|
+
|
113
|
+
td = [ 'def', [], l ]
|
114
|
+
td[1] << [ '_att', [ [ 'msg', [], l ] ], l ]
|
115
|
+
non_att_children.each { |nac| td[1] << Flor.dup(nac) }
|
116
|
+
|
117
|
+
th[1] << td
|
118
|
+
|
119
|
+
th
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|