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/pcore/map.rb
CHANGED
@@ -1,53 +1,84 @@
|
|
1
1
|
|
2
|
-
class Flor::Pro::Map < Flor::
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
2
|
+
class Flor::Pro::Map < Flor::Pro::Iterator
|
3
|
+
#
|
4
|
+
# This is the classical "map" procedure. It accepts a collection
|
5
|
+
# and a function and yields a new collection.
|
6
|
+
#
|
7
|
+
# ```
|
8
|
+
# map [ 1, 2, 3 ]
|
9
|
+
# def x
|
10
|
+
# + x 3
|
11
|
+
# # f.ret yields [ 4, 5, 6 ]
|
12
|
+
# ```
|
13
|
+
#
|
14
|
+
# The collection if not given is taken from `f.ret`:
|
15
|
+
# ```
|
16
|
+
# [ 1, 2, 3 ]
|
17
|
+
# map
|
18
|
+
# def x
|
19
|
+
# + x 2
|
20
|
+
# # f.ret yields [ 3, 4, 5 ]
|
21
|
+
# ```
|
22
|
+
#
|
23
|
+
# The function may be given by reference:
|
24
|
+
# ```
|
25
|
+
# define add3 x
|
26
|
+
# + x 3
|
27
|
+
# map [ 0, 1 ] add3
|
28
|
+
# ```
|
29
|
+
#
|
30
|
+
# There is an implicit `idx` var:
|
31
|
+
# ```
|
32
|
+
# map [ 'a', 'b' ]
|
33
|
+
# def x \ [ idx, x ]
|
34
|
+
# # f.ret yields [ [ 0, 'a' ], [ 1, 'b' ] ]
|
35
|
+
# ```
|
36
|
+
# but that index can be included in the function signature:
|
37
|
+
# ```
|
38
|
+
# map [ 'a', 'b' ]
|
39
|
+
# def x i \ [ x, i ]
|
40
|
+
# # f.ret yields [ [ 'a', 0 ], [ 'b', 1 ] ]
|
41
|
+
# ```
|
42
|
+
#
|
43
|
+
# ## with objects (hashes)
|
44
|
+
#
|
45
|
+
# ```
|
46
|
+
# map { a: 'A', b: 'B', c: 'C' }
|
47
|
+
# def k v \ [ k v ]
|
48
|
+
# # f.ret --> [ [ 'a', 'A' ], [ 'b', 'B' ], [ 'c', 'C' ] ]
|
49
|
+
#
|
50
|
+
# map { a: 'A', b: 'B', c: 'C' }
|
51
|
+
# def k v i \ [ i k v ]
|
52
|
+
# # f.ret --> [ [ 0, 'a', 'A' ], [ 1, 'b', 'B' ], [ 2, 'c', 'C' ] ]
|
53
|
+
# ```
|
54
|
+
#
|
55
|
+
# ## iterating and functions
|
56
|
+
#
|
57
|
+
# Iterating functions accept 0 to 3 arguments when iterating over an
|
58
|
+
# array and 0 to 4 arguments when iterating over an object.
|
59
|
+
#
|
60
|
+
# Those arguments are `[ value, index, length ]` for arrays.
|
61
|
+
# They are `[ key, value, index, length ]` for objects.
|
62
|
+
#
|
63
|
+
# The corresponding `key`, `val`, `idx` and `len` variables are also
|
64
|
+
# set in the closure for the function call.
|
65
|
+
#
|
66
|
+
# ## see also
|
67
|
+
#
|
68
|
+
# Collect.
|
69
|
+
|
70
|
+
name 'map'
|
71
|
+
|
72
|
+
protected
|
73
|
+
|
74
|
+
def receive_iteration
|
75
|
+
|
76
|
+
@node['res'] << payload['ret']
|
17
77
|
end
|
18
78
|
|
19
|
-
def
|
20
|
-
|
21
|
-
@node['col'] ||=
|
22
|
-
Flor.to_coll(
|
23
|
-
if Flor.is_func_tree?(payload['ret'])
|
24
|
-
node_payload_ret
|
25
|
-
else
|
26
|
-
payload['ret']
|
27
|
-
end)
|
28
|
-
|
29
|
-
return execute_child(@ncid) \
|
30
|
-
if @node['fun'] == nil && children[@ncid] != nil
|
31
|
-
|
32
|
-
if @node['idx'] < 0
|
33
|
-
@node['fun'] = payload['ret']
|
34
|
-
elsif res = @node['res']
|
35
|
-
res << payload['ret']
|
36
|
-
end
|
37
|
-
|
38
|
-
@node['idx'] += 1
|
39
|
-
@node['mtime'] = Flor.tstamp
|
40
|
-
|
41
|
-
if @node['idx'] == @node['col'].size
|
42
|
-
if res = @node['res']
|
43
|
-
payload['ret'] = @node['res']
|
44
|
-
end
|
45
|
-
return wrap_reply
|
46
|
-
end
|
47
|
-
|
48
|
-
@node['vars']['idx'] = @node['idx']
|
79
|
+
def iterator_result
|
49
80
|
|
50
|
-
|
81
|
+
@node['res']
|
51
82
|
end
|
52
83
|
end
|
53
84
|
|
data/lib/flor/pcore/match.rb
CHANGED
@@ -184,6 +184,10 @@ class Flor::Pro::Match < Flor::Pro::Case
|
|
184
184
|
# (guard {name})
|
185
185
|
# (guard {name} {pattern|conditional}*)
|
186
186
|
# ```
|
187
|
+
#
|
188
|
+
# ## see also
|
189
|
+
#
|
190
|
+
# Case.
|
187
191
|
|
188
192
|
name 'match'
|
189
193
|
|
@@ -192,7 +196,7 @@ class Flor::Pro::Match < Flor::Pro::Case
|
|
192
196
|
unatt_unkeyed_children
|
193
197
|
|
194
198
|
conditional = true
|
195
|
-
@node['val'] = payload['ret'] if
|
199
|
+
@node['val'] = payload['ret'] if non_att_count.even?
|
196
200
|
found_val = @node.has_key?('val')
|
197
201
|
t = tree
|
198
202
|
changed = false
|
@@ -216,7 +220,7 @@ class Flor::Pro::Match < Flor::Pro::Case
|
|
216
220
|
t = tree[1][index]
|
217
221
|
|
218
222
|
payload['_pat_val'] = @node['val'] \
|
219
|
-
if t && t[0].match(/\A_pat_(arr|obj|or|guard)\z/)
|
223
|
+
if t && t[0].match(/\A_pat_(arr|obj|or|guard|regex)\z/)
|
220
224
|
|
221
225
|
super
|
222
226
|
end
|
@@ -225,6 +229,8 @@ class Flor::Pro::Match < Flor::Pro::Case
|
|
225
229
|
|
226
230
|
def patternize(t)
|
227
231
|
|
232
|
+
return [ '_pat_regex', *t[1..-1] ] if t[0] == '_rxs'
|
233
|
+
|
228
234
|
return t unless t[1].is_a?(Array)
|
229
235
|
|
230
236
|
bang = t[1]
|
data/lib/flor/pcore/matchr.rb
CHANGED
@@ -73,18 +73,17 @@ class Flor::Pro::Matchr < Flor::Procedure
|
|
73
73
|
rets = @node['rets'].dup
|
74
74
|
rets.unshift(node_payload_ret) if rets.size < 2
|
75
75
|
|
76
|
-
fail
|
77
|
-
"'#{tree[0]}' needs 1 or 2 arguments"
|
76
|
+
fail Flor::FlorError.new(
|
77
|
+
"'#{tree[0]}' needs 1 or 2 arguments", self
|
78
78
|
) if rets.size < 2
|
79
79
|
|
80
80
|
rex =
|
81
|
-
rets.find { |r|
|
81
|
+
rets.find { |r| Flor.is_regex_tree?(r) } ||
|
82
82
|
rets.last
|
83
83
|
|
84
84
|
str = (rets - [ rex ]).first
|
85
85
|
|
86
|
-
rex =
|
87
|
-
rex = rex.match(/\A\/[^\/]*\/[a-z]*\z/) ? Kernel.eval(rex) : Regexp.new(rex)
|
86
|
+
rex = Flor.to_regex(rex)
|
88
87
|
|
89
88
|
[ rex, str ]
|
90
89
|
end
|
data/lib/flor/pcore/move.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
|
2
2
|
class Flor::Pro::Move < Flor::Procedure
|
3
3
|
#
|
4
|
-
# Moves a cursor to a given position
|
4
|
+
# Moves a cursor to a given position, a kind of local goto.
|
5
5
|
#
|
6
6
|
# ```
|
7
7
|
# cursor
|
8
|
-
# do-this
|
8
|
+
# do-this _
|
9
9
|
# move to: 'do-that-other-thing'
|
10
|
-
# do-that _ #
|
10
|
+
# do-that _ # gets skipped
|
11
11
|
# do-that-other-thing _
|
12
12
|
# ```
|
13
13
|
|
data/lib/flor/pcore/noeval.rb
CHANGED
@@ -11,6 +11,19 @@ class Flor::Pro::NoEval < Flor::Procedure
|
|
11
11
|
# [ 1, 2, 3 ]
|
12
12
|
# # f.ret is still 1 here, not [ 1, 2, 3 ]
|
13
13
|
# ```
|
14
|
+
#
|
15
|
+
# Could be useful when determining on the fly what the "parent"
|
16
|
+
# procedure should be.
|
17
|
+
# ```
|
18
|
+
# set head
|
19
|
+
# case (size f.customers)
|
20
|
+
# 0; noeval
|
21
|
+
# [ 1, 10 ]; concurrence
|
22
|
+
# else; sequence
|
23
|
+
# head
|
24
|
+
# task 'a'
|
25
|
+
# task 'b'
|
26
|
+
# ```
|
14
27
|
|
15
28
|
name 'noeval'
|
16
29
|
|
data/lib/flor/pcore/not.rb
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
|
2
2
|
class Flor::Pro::Not < Flor::Procedure
|
3
|
+
#
|
4
|
+
# `not` negates its last child (or its last unkeyed attribute)
|
5
|
+
#
|
6
|
+
# ```
|
7
|
+
# not _ # --> true
|
8
|
+
# not true # --> false
|
9
|
+
# not false # --> true
|
10
|
+
# not 0 # --> false
|
11
|
+
# not 1 # --> false
|
12
|
+
# ```
|
13
|
+
#
|
14
|
+
# ```
|
15
|
+
# not
|
16
|
+
# true
|
17
|
+
# false # --> true
|
18
|
+
# ```
|
3
19
|
|
4
20
|
name 'not'
|
5
21
|
|
@@ -0,0 +1,172 @@
|
|
1
|
+
|
2
|
+
class Flor::Pro::On < Flor::Macro
|
3
|
+
#
|
4
|
+
# Catches signals or errors.
|
5
|
+
#
|
6
|
+
# ## signals
|
7
|
+
#
|
8
|
+
# Turns
|
9
|
+
# ```
|
10
|
+
# on 'approve'
|
11
|
+
# task 'bob' mission: 'gather signatures'
|
12
|
+
# ```
|
13
|
+
# into
|
14
|
+
# ```
|
15
|
+
# trap point: 'signal', name: 'approve'
|
16
|
+
# def msg
|
17
|
+
# task 'bob' mission: 'gather signatures'
|
18
|
+
# ```
|
19
|
+
#
|
20
|
+
# It's OK trapping multiple signal names:
|
21
|
+
# ```
|
22
|
+
# on [ /^bl/ 'red' 'white' ]
|
23
|
+
# task 'bob' mission: "order can of $(sig) paint"
|
24
|
+
# ```
|
25
|
+
#
|
26
|
+
# ## error
|
27
|
+
#
|
28
|
+
# "on" understands `on error` with a block. It in facts turns:
|
29
|
+
# ```
|
30
|
+
# sequence
|
31
|
+
# on error
|
32
|
+
# push f.l err.msg # a block with an `err` variable
|
33
|
+
# # ...
|
34
|
+
# ```
|
35
|
+
# into:
|
36
|
+
# ```
|
37
|
+
# sequence
|
38
|
+
# on_error
|
39
|
+
# def err # a anonymous function definition with an `err` argument
|
40
|
+
# push f.l err.msg
|
41
|
+
# # ...
|
42
|
+
# ```
|
43
|
+
#
|
44
|
+
# Please note that "error" in `on error` is not quoted, nor double quoted.
|
45
|
+
# If it were, it would trap the signal named "error".
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# ## cancel
|
49
|
+
#
|
50
|
+
# "on" understands `on cancel` with a block. It in facts turns:
|
51
|
+
# ```
|
52
|
+
# sequence
|
53
|
+
# on cancel
|
54
|
+
# push f.l msg # a block with a `msg` variable
|
55
|
+
# # ...
|
56
|
+
# ```
|
57
|
+
# into:
|
58
|
+
# ```
|
59
|
+
# sequence
|
60
|
+
# on_cancel
|
61
|
+
# def msg # a anonymous function definition with a `msg` argument
|
62
|
+
# push f.l msg
|
63
|
+
# # ...
|
64
|
+
# ```
|
65
|
+
#
|
66
|
+
# Please note that "cancel" in `on cancel` is not quoted, nor double quoted.
|
67
|
+
# If it were, it would trap the signal named "cancel".
|
68
|
+
#
|
69
|
+
#
|
70
|
+
# ## timeout
|
71
|
+
#
|
72
|
+
# `on timeout` turns:
|
73
|
+
# ```
|
74
|
+
# sequence timeout: '1w'
|
75
|
+
# on timeout
|
76
|
+
# push f.l msg # a block with a `msg` variable
|
77
|
+
# # ...
|
78
|
+
# ```
|
79
|
+
# into:
|
80
|
+
# ```
|
81
|
+
# sequence timeout: '1w'
|
82
|
+
# on_timeout
|
83
|
+
# def msg # a anonymous function definition with a `msg` argument
|
84
|
+
# push f.l msg
|
85
|
+
# # ...
|
86
|
+
# ```
|
87
|
+
#
|
88
|
+
# Please note that "timeout" in `on timeout` is not quoted, nor double quoted.
|
89
|
+
# If it were, it would trap the signal named "timeout".
|
90
|
+
#
|
91
|
+
#
|
92
|
+
# ## see also
|
93
|
+
#
|
94
|
+
# Trap and signal.
|
95
|
+
|
96
|
+
name 'on'
|
97
|
+
|
98
|
+
def rewrite_tree
|
99
|
+
|
100
|
+
if att = find_catch # 22
|
101
|
+
rewrite_as_catch_tree(att)
|
102
|
+
else
|
103
|
+
rewrite_as_trap_tree
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
protected
|
108
|
+
|
109
|
+
CATCHES = %w[ error cancel timeout ]
|
110
|
+
|
111
|
+
def find_catch
|
112
|
+
|
113
|
+
att_children
|
114
|
+
.each_with_index { |t, i|
|
115
|
+
tt = t[1].is_a?(Array) && t[1].length == 1 && t[1].first
|
116
|
+
return [ tt[0], i ] if tt && tt[1] == [] && CATCHES.include?(tt[0]) }
|
117
|
+
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
|
121
|
+
def rewrite_as_catch_tree(att)
|
122
|
+
|
123
|
+
flavour, index = att
|
124
|
+
|
125
|
+
atts = att_children
|
126
|
+
atts.delete_at(index)
|
127
|
+
|
128
|
+
l = tree[2]
|
129
|
+
|
130
|
+
th = [ "on_#{flavour}", [], l, *tree[3] ]
|
131
|
+
atts.each { |ac| th[1] << Flor.dup(ac) }
|
132
|
+
|
133
|
+
td = [ 'def', [], l ]
|
134
|
+
td[1] << [ '_att', [ [ 'msg', [], l ] ], l ]
|
135
|
+
td[1] << [ '_att', [ [ 'err', [], l ] ], l ] if flavour == 'error'
|
136
|
+
non_att_children.each { |nac| td[1] << Flor.dup(nac) }
|
137
|
+
|
138
|
+
th[1] << td
|
139
|
+
|
140
|
+
th
|
141
|
+
end
|
142
|
+
|
143
|
+
def rewrite_as_trap_tree
|
144
|
+
|
145
|
+
atts = att_children
|
146
|
+
signame_i = atts.index { |at| at[1].size == 1 }
|
147
|
+
|
148
|
+
fail Flor::FlorError.new("signal name not found in #{tree.inspect}", self) \
|
149
|
+
unless signame_i
|
150
|
+
|
151
|
+
tname = atts[signame_i]
|
152
|
+
tname = Flor.dup(tname[1][0])
|
153
|
+
atts.delete_at(signame_i)
|
154
|
+
|
155
|
+
l = tree[2]
|
156
|
+
|
157
|
+
th = [ 'trap', [], l, *tree[3] ]
|
158
|
+
th[1] << [ '_att', [ [ 'point', [], l ], [ '_sqs', 'signal', l ] ], l ]
|
159
|
+
th[1] << [ '_att', [ [ 'name', [], l ], tname ], l ]
|
160
|
+
th[1] << [ '_att', [ [ 'payload', [], l ], [ '_sqs', 'event', l ] ], l ]
|
161
|
+
atts.each { |ac| th[1] << Flor.dup(ac) }
|
162
|
+
|
163
|
+
td = [ 'def', [], l ]
|
164
|
+
td[1] << [ '_att', [ [ 'msg', [], l ] ], l ]
|
165
|
+
non_att_children.each { |nac| td[1] << Flor.dup(nac) }
|
166
|
+
|
167
|
+
th[1] << td
|
168
|
+
|
169
|
+
th
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
class Flor::Pro::OnCancel < Flor::Procedure
|
3
|
+
#
|
4
|
+
# Counterpart to the on_cancel: attribute.
|
5
|
+
#
|
6
|
+
# ```
|
7
|
+
# set f.l []
|
8
|
+
# sequence
|
9
|
+
# on_cancel (def msg \ push f.l "$(msg.point):$(msg.nid)")
|
10
|
+
# push f.l 0
|
11
|
+
# cancel '0_1' # cancels the containing sequence
|
12
|
+
# push f.l 1
|
13
|
+
# push f.l 2
|
14
|
+
# ```
|
15
|
+
# Ends up with `[ 0, 'cancel:0_1', 2 ]` in the field `l`.
|
16
|
+
#
|
17
|
+
# ## on and on_cancel
|
18
|
+
#
|
19
|
+
# "on_cancel" is made to allow for `on cancel`, so that:
|
20
|
+
# ```
|
21
|
+
# sequence
|
22
|
+
# on cancel
|
23
|
+
# push f.l msg # a block with a `msg` variable
|
24
|
+
# # ...
|
25
|
+
# ```
|
26
|
+
# gets turned into:
|
27
|
+
# ```
|
28
|
+
# sequence
|
29
|
+
# on_cancel
|
30
|
+
# def msg # a anonymous function definition with a `msg` argument
|
31
|
+
# push f.l msg
|
32
|
+
# # ...
|
33
|
+
# ```
|
34
|
+
#
|
35
|
+
#
|
36
|
+
# ## see also
|
37
|
+
#
|
38
|
+
# On, on_error.
|
39
|
+
|
40
|
+
name 'on_cancel'
|
41
|
+
|
42
|
+
def pre_execute
|
43
|
+
|
44
|
+
unatt_unkeyed_children
|
45
|
+
end
|
46
|
+
|
47
|
+
def receive_non_att
|
48
|
+
|
49
|
+
store_on(:cancel)
|
50
|
+
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|