flor 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/CHANGELOG.md +7 -0
  2. data/Makefile +3 -0
  3. data/lib/flor.rb +1 -1
  4. data/lib/flor/colours.rb +7 -3
  5. data/lib/flor/conf.rb +21 -15
  6. data/lib/flor/core/executor.rb +71 -77
  7. data/lib/flor/core/node.rb +6 -1
  8. data/lib/flor/core/procedure.rb +112 -58
  9. data/lib/flor/core/texecutor.rb +6 -5
  10. data/lib/flor/log.rb +9 -7
  11. data/lib/flor/migrations/0003_timer_onid_bnid.rb +35 -0
  12. data/lib/flor/migrations/0004_trap_bnid.rb +16 -0
  13. data/lib/flor/pcore/_arr.rb +2 -2
  14. data/lib/flor/pcore/_atom.rb +1 -1
  15. data/lib/flor/pcore/_att.rb +59 -13
  16. data/lib/flor/pcore/_happly.rb +3 -3
  17. data/lib/flor/pcore/_obj.rb +22 -2
  18. data/lib/flor/pcore/_skip.rb +2 -2
  19. data/lib/flor/pcore/apply.rb +1 -1
  20. data/lib/flor/pcore/arith.rb +1 -1
  21. data/lib/flor/pcore/break.rb +2 -2
  22. data/lib/flor/pcore/case.rb +1 -1
  23. data/lib/flor/pcore/cmp.rb +1 -1
  24. data/lib/flor/pcore/cond.rb +1 -1
  25. data/lib/flor/pcore/cursor.rb +2 -2
  26. data/lib/flor/pcore/define.rb +1 -1
  27. data/lib/flor/pcore/fail.rb +1 -6
  28. data/lib/flor/pcore/if.rb +2 -2
  29. data/lib/flor/pcore/map.rb +1 -1
  30. data/lib/flor/pcore/matchr.rb +92 -0
  31. data/lib/flor/pcore/move.rb +2 -3
  32. data/lib/flor/pcore/noeval.rb +1 -1
  33. data/lib/flor/pcore/noret.rb +1 -1
  34. data/lib/flor/pcore/push.rb +1 -1
  35. data/lib/flor/pcore/rand.rb +1 -1
  36. data/lib/flor/pcore/set.rb +1 -1
  37. data/lib/flor/pcore/twig.rb +2 -2
  38. data/lib/flor/pcore/until.rb +4 -1
  39. data/lib/flor/pcore/val.rb +1 -1
  40. data/lib/flor/punit/cancel.rb +2 -3
  41. data/lib/flor/punit/cmap.rb +5 -6
  42. data/lib/flor/punit/concurrence.rb +3 -5
  43. data/lib/flor/punit/schedule.rb +20 -5
  44. data/lib/flor/punit/signal.rb +1 -1
  45. data/lib/flor/punit/sleep.rb +2 -2
  46. data/lib/flor/punit/task.rb +3 -3
  47. data/lib/flor/punit/trace.rb +1 -1
  48. data/lib/flor/punit/trap.rb +22 -6
  49. data/lib/flor/to_string.rb +2 -1
  50. data/lib/flor/unit/executor.rb +3 -5
  51. data/lib/flor/unit/hooker.rb +2 -3
  52. data/lib/flor/unit/models/timer.rb +9 -3
  53. data/lib/flor/unit/models/trap.rb +1 -0
  54. data/lib/flor/unit/scheduler.rb +40 -35
  55. data/lib/flor/unit/storage.rb +70 -59
  56. data/lib/flor/unit/waiter.rb +2 -3
  57. data/t.txt +4 -0
  58. metadata +6 -4
  59. data/fail.txt +0 -3
  60. data/lib/flor/pcore/match.rb +0 -46
data/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
  # flor CHANGELOG.md
3
3
 
4
4
 
5
+ ## flor 0.12.0 released 2017-04-14
6
+
7
+ - Implementation of 'flank' and application to "trap" and "schedule"
8
+ - Introduce `{ a : 0 } quote: 'keys'`
9
+ - Introduce `vars: copy` or `vars: '*'`
10
+
11
+
5
12
  ## flor 0.11.0 released 2017-03-17
6
13
 
7
14
  - Simplification of the tasker configuration files
data/Makefile CHANGED
@@ -55,6 +55,9 @@ start:
55
55
  backup_notes_and_todos:
56
56
  tar czvf flor_notes_$(shell date "+%Y%m%d_%H%M").tgz .notes.md .todo.md && mv flor_notes_*.tgz ~/Dropbox/backup/
57
57
  ba: backup_notes_and_todos
58
+ backup_src:
59
+ cd .. && tar czvf flor_$(shell date "+%Y%m%d_%H%M").tgz flor && mv flor_*.tgz ~/Dropbox/backup/
60
+ bak: backup_src
58
61
 
59
62
  t:
60
63
  tree spec/unit/loader
data/lib/flor.rb CHANGED
@@ -12,7 +12,7 @@ require 'raabro'
12
12
 
13
13
  module Flor
14
14
 
15
- VERSION = '0.11.0'
15
+ VERSION = '0.12.0'
16
16
  end
17
17
 
18
18
  require 'flor/colours'
data/lib/flor/colours.rb CHANGED
@@ -69,12 +69,16 @@ module Flor
69
69
 
70
70
  o = opts[:out] || $stdout
71
71
 
72
- (o.respond_to?(:log_colours?) ? o.log_colours? : o.tty?) ?
73
- @colours :
74
- @no_colours
72
+ col =
73
+ (o.respond_to?(:log_colours?) ? o.log_colours? : o.tty?) ||
74
+ ($0[-6..-1] == '/rspec' &&
75
+ (ARGV.include?('--tty') || ARGV.include?('--color')))
76
+
77
+ col ? @colours : @no_colours
75
78
  end
76
79
 
77
80
  def self.decolour(s)
81
+
78
82
  s.gsub(/\x1b\[\d+(;\d+)?m/, '')
79
83
  end
80
84
 
data/lib/flor/conf.rb CHANGED
@@ -67,22 +67,24 @@ module Flor
67
67
  #
68
68
  # For example `debug: 'msg,stdout'`
69
69
 
70
- def self.read(s)
70
+ def self.prepare(conf, over_conf)
71
71
 
72
- h = {}
73
- h.merge!(Flor::ConfExecutor.interpret(s))
74
- h.merge!(interpret_flor_debug(h['flor_debug'] || h['debug']))
72
+ c = conf
73
+ c = Flor::ConfExecutor.interpret(c) if c.is_a?(String)
75
74
 
76
- h
77
- end
75
+ fail ArgumentError.new(
76
+ "cannot extract conf out of #{c.inspect} (#{conf.class})"
77
+ ) unless c.is_a?(Hash)
78
78
 
79
- def self.read_env
79
+ unless c['conf'] == true
80
+ #
81
+ # don't read FLOR_DEBUG if this executor is only meant to read the conf
80
82
 
81
- h = {}
82
- h.merge!(interpret_env)
83
- h.merge!(interpret_flor_debug(ENV['FLOR_DEBUG']))
83
+ c.merge!(interpret_flor_debug(c))
84
+ c.merge!(interpret_env)
85
+ end
84
86
 
85
- h
87
+ c.merge!(over_conf)
86
88
  end
87
89
 
88
90
  def self.get_class(conf, key)
@@ -99,11 +101,15 @@ module Flor
99
101
  LOG_DBG_KEYS = %w[ dbg msg err src tree tree_rw run ]
100
102
  LOG_ALL_KEYS = %w[ all log sto ] + LOG_DBG_KEYS
101
103
 
102
- def self.interpret_flor_debug(v)
104
+ def self.interpret_flor_debug(c)
103
105
 
104
- a = v || ''
105
- a = a.split(',') if a.is_a?(String)
106
- a = a.collect(&:strip)
106
+ plus, minus = [ c['flor_debug'], c['debug'], ENV['FLOR_DEBUG'] ]
107
+ .collect { |v| (v || '').split(/\s*,\s*/) }
108
+ .flatten(1)
109
+ .partition { |v| v[0, 1] != '-' }
110
+ plus = plus.collect { |v| v[0, 1] == '+' ? v[1..-1] : v }
111
+ minus = minus.collect { |v| v[0, 1] == '-' ? v[1..-1] : v }
112
+ a = plus - minus
107
113
 
108
114
  h =
109
115
  a.inject({}) { |h, kv|
@@ -94,14 +94,16 @@ module Flor
94
94
  (n['vars'] || {})
95
95
  .each { |k, v| vs[k] = Flor.dup(v) unless vs.has_key?(k) }
96
96
 
97
- if @unit.loader && n['parent'] == nil && n['vdomain'] != false
97
+ pnid = n['parent']
98
+
99
+ if @unit.loader && pnid == nil && n['vdomain'] != false
98
100
 
99
101
  @unit.loader.variables(n['vdomain'] || Flor.domain(@exid))
100
102
  .each { |k, v| vs[k] = Flor.dup(v) unless vs.has_key?(k) }
101
103
  end
102
104
 
103
105
  if cn = n['cnid']; vars(cn, vs); end
104
- if pa = n['parent']; vars(pa, vs); end
106
+ vars(pnid, vs) if pnid
105
107
 
106
108
  vs
107
109
  end
@@ -132,7 +134,7 @@ module Flor
132
134
  'ctime' => now,
133
135
  'mtime' => now }
134
136
 
135
- %w[ vars vdomain cnid noreply dbg ].each do |k|
137
+ %w[ vars vdomain cnid dbg ].each do |k|
136
138
  v = message[k]
137
139
  node[k] = v if v != nil
138
140
  end
@@ -140,7 +142,6 @@ module Flor
140
142
  # vars: variables
141
143
  # vdomain: variable domain (used in conjuction with the loader)
142
144
  # cnid: closure nid
143
- # noreply: this new node has a parent but shouldn't reply to it
144
145
  # dbg: used to debug messages (useful @node['dbg'] when 'receive')
145
146
 
146
147
  @execution['nodes'][nid] = node
@@ -179,7 +180,22 @@ module Flor
179
180
  node['heat'] = heat = n.deref(t0)
180
181
  node['heap'] = heap = n.reheap(tree, heat)
181
182
 
182
- if heap == 'task' && heat[0] == '_task'
183
+ # "exceptions"
184
+
185
+ # TODO could those two ifs go upstream (top of this method)
186
+ # and thus become smaller
187
+ #
188
+ if message['accept_symbol'] && node['heat'] == nil
189
+ #
190
+ # tag: et al
191
+
192
+ tree = node['tree'] = message['tree'] = [ '_dqs', tree[0], tree[2] ]
193
+
194
+ node['heat0'] = tree[0]
195
+ node['heat'] = heat = n.deref(tree[0])
196
+ node['heap'] = heap = n.reheap(tree, heat)
197
+
198
+ elsif heap == 'task' && heat[0] == '_task'
183
199
  #
184
200
  # rewrite `alpha` into `task alpha`
185
201
 
@@ -208,13 +224,6 @@ module Flor
208
224
  node['failure'] ? '_err' : nil
209
225
  end
210
226
 
211
- return ([{
212
- 'point' => 'receive',
213
- 'nid' => message['from'], 'from' => message['nid'],
214
- 'exid' => message['exid'],
215
- 'payload' => Flor.dupm(message['payload'], 'ret' => node['heat0'])
216
- }]) if heap == nil && message['accept_symbol'] == true
217
-
218
227
  return error_reply(
219
228
  node, message, "don't know how to apply #{node['heat0'].inspect}"
220
229
  ) if heap == nil
@@ -224,99 +233,85 @@ module Flor
224
233
 
225
234
  head = heac.new(self, node, message)
226
235
 
227
- #return process(head.rewrite) if head.is_a?(Flor::Macro)
228
236
  return [ head.rewrite ] if head.is_a?(Flor::Macro)
229
237
 
230
- nid = message['nid']
231
- pt = message['point']
232
- pt = "do_#{pt}" if pt == 'receive' || pt == 'cancel'
233
-
234
- if pt == 'execute'
235
- head.pre_execute
236
- pnode = @execution['nodes'][node['parent']]
237
- cnodes = pnode && (pnode['cnodes'] ||= [])
238
- cnodes << nid if cnodes && ( ! cnodes.include?(nid))
239
- end
240
- head.send(pt)
238
+ head.send("do_#{message['point']}")
241
239
  end
242
240
 
243
- def remove_node(n)
241
+ def toc_messages(message)
244
242
 
245
- return unless n
243
+ return [] if message['flavour'] == 'flank'
246
244
 
247
- n['removed'] = true # or should I use "status" => "removed" ?
245
+ m = message.select { |k, v| %w[ exid nid from payload ].include?(k) }
246
+ m['sm'] = message['m']
247
+ m['point'] = message['from'] == '0' ? 'terminated' : 'ceased'
248
248
 
249
- @unit.remove_node(exid, n)
250
- # remove timers/waiters for this node, if any
249
+ [ m ]
250
+ end
251
251
 
252
- return if (n['closures'] || []).any?
253
- # don't remove the node if it's a closure for some other nodes
252
+ def receive(message)
254
253
 
255
- nid = n['nid']
254
+ messages = leave_node(message)
256
255
 
257
- return if nid == '0'
258
- # don't remove if it's the "root" node
256
+ nid = message['nid']
259
257
 
260
- @execution['nodes'].delete(nid)
261
- end
258
+ return messages + toc_messages(message) unless nid
259
+ # 'terminated' or 'ceased'
262
260
 
263
- def leave(node, message)
261
+ node = @execution['nodes'][nid]
264
262
 
265
- ts = node && node['tags']
266
- return [] unless ts && ts.any?
263
+ return messages unless node
264
+ # node gone...
267
265
 
268
- [
269
- { 'point' => 'left',
270
- 'tags' => ts,
271
- 'exid' => exid,
272
- 'nid' => node['nid'],
273
- 'payload' => message['payload'] }
274
- ]
266
+ messages + apply(node, message)
275
267
  end
276
268
 
277
- # "receive_terminated_or_ceased"
278
- #
279
- def receive_toc(message, fnode)
269
+ def leave_node(message)
280
270
 
281
- msg =
282
- %w[
283
- exid nid from payload
284
- ].inject({}) { |h, k| h[k] = message[k] if message.has_key?(k); h }
271
+ fnid = message['from']; return [] unless fnid
272
+ fnode = @execution['nodes'][fnid]; return [] unless fnode
285
273
 
286
- msg['sm'] = message['m']
274
+ return [] if message['flavour'] == 'flank'
287
275
 
288
- msg['point'] =
289
- if message['from'] == '0' || @execution['nodes'].empty? # termination?
290
- 'terminated'
291
- else
292
- 'ceased'
293
- end
294
-
295
- [ msg ]
276
+ remove_node(message, fnode) +
277
+ leave_tags(message, fnode)
296
278
  end
297
279
 
298
- def receive(message)
280
+ def remove_node(message, node)
299
281
 
300
- from = message['from']
301
- fnode = @execution['nodes'][from]
282
+ nid = node['nid']
283
+ cls = node['closures']
302
284
 
303
- if fnode && fnode.has_key?('aret')
304
- message['payload']['ret'] = fnode['aret']
305
- end
285
+ pro = Flor::Procedure.make(self, node, message)
286
+ pro.end
306
287
 
307
- remove_node(fnode)
308
- messages = leave(fnode, message)
288
+ cancels = pro.send(:wrap_cancel_children, 'cancel_trailing' => true)
309
289
 
310
- nid = message['nid']
311
- nid = nil if fnode && fnode['noreply']
290
+ return cancels if cls && cls.any?
291
+ # don't remove the node if it's a closure for some other nodes
312
292
 
313
- return messages + receive_toc(message, fnode) unless nid
293
+ return cancels if nid == '0'
294
+ # don't remove if it's the "root" node
314
295
 
315
- node = @execution['nodes'][nid]
296
+ @unit.archive_node(message['exid'], node)
297
+ # archiving is only active during testing
316
298
 
317
- return messages unless node
299
+ @execution['nodes'].delete(nid)
318
300
 
319
- messages + apply(node, message)
301
+ cancels
302
+ end
303
+
304
+ def leave_tags(message, node)
305
+
306
+ ts = node['tags']; return [] unless ts && ts.any?
307
+
308
+ [
309
+ { 'point' => 'left',
310
+ 'tags' => ts,
311
+ 'exid' => exid,
312
+ 'nid' => node['nid'],
313
+ 'payload' => message['payload'] }
314
+ ]
320
315
  end
321
316
 
322
317
  def error_reply(node, message, err)
@@ -439,7 +434,6 @@ module Flor
439
434
  []
440
435
  end
441
436
 
442
-
443
437
  def failed(message)
444
438
 
445
439
  n = node(message['nid'])
@@ -73,6 +73,9 @@ class Flor::Node
73
73
  def point; @message['point']; end
74
74
  def from; @message['from']; end
75
75
 
76
+ def cnodes; @node['cnodes']; end
77
+ def cnodes_any?; cnodes && cnodes.any?; end
78
+
76
79
  def payload
77
80
  @message_payload ||= Payload.new(self, :message)
78
81
  end
@@ -354,10 +357,12 @@ class Flor::Node
354
357
 
355
358
  return vars[key] if vars && vars.has_key?(key)
356
359
 
357
- if cnid = node['cnid'] # look into closure
360
+ if cnid = node['cnid']
358
361
  cvars = (@execution['nodes'][cnid] || {})['vars']
359
362
  return cvars[key] if cvars && cvars.has_key?(key)
360
363
  end
364
+ #
365
+ # look into closure, just one level deep...
361
366
 
362
367
  lookup_var(pnode, mod, key)
363
368
  end
@@ -1,17 +1,17 @@
1
1
 
2
2
  class Flor::Procedure < Flor::Node
3
3
 
4
- def self.inherited(subclass)
4
+ class << self
5
5
 
6
- (@@inherited ||= []) << subclass
7
- end
6
+ def inherited(subclass)
8
7
 
9
- def self.[](name)
8
+ (@@inherited ||= []) << subclass
9
+ end
10
10
 
11
- @@inherited.find { |k| k.names && k.names.include?(name) }
12
- end
11
+ def [](name)
13
12
 
14
- class << self
13
+ @@inherited.find { |k| k.names && k.names.include?(name) }
14
+ end
15
15
 
16
16
  def names(*names)
17
17
 
@@ -22,6 +22,24 @@ class Flor::Procedure < Flor::Node
22
22
  end
23
23
 
24
24
  alias :name :names
25
+
26
+ def make(executor, node, message)
27
+
28
+ heap = node['heat'] ? node['heap'] : nil
29
+
30
+ fail ArgumentError.new(
31
+ "cannot determine procedure " +
32
+ "#{{ heat: node['heat'], heap: node['heap'] }.inspect}"
33
+ ) unless heap
34
+
35
+ heac = self[heap]
36
+
37
+ fail NameError.new(
38
+ "unknown procedure #{heap.inspect}"
39
+ ) unless heac
40
+
41
+ heac.new(executor, node, message)
42
+ end
25
43
  end
26
44
 
27
45
  def pre_execute
@@ -38,13 +56,8 @@ class Flor::Procedure < Flor::Node
38
56
  @node['on_receive_last'] =
39
57
  apply(@node['on_error'].shift, [ @message ], tree[2])
40
58
 
41
- nids = @node['cnodes']
42
-
43
- if nids && nids.any?
44
- cancel_children
45
- else
46
- do_receive # which should trigger 'on_receive_last'
47
- end
59
+ do_wrap_cancel_children ||
60
+ do_receive # which should trigger 'on_receive_last'
48
61
  end
49
62
 
50
63
  def debug_tree(nid=nil)
@@ -60,6 +73,19 @@ class Flor::Procedure < Flor::Node
60
73
  puts Flor.detail_msg(@executor, msg)
61
74
  end
62
75
 
76
+ def end
77
+
78
+ end_node
79
+ end
80
+
81
+ def flank
82
+
83
+ @node['tree'] = Flor.dup(tree)
84
+ @node['noreply'] = true
85
+
86
+ wrap('nid' => parent, 'flavour' => 'flank')
87
+ end
88
+
63
89
  protected
64
90
 
65
91
  def counter_next(k)
@@ -162,7 +188,7 @@ class Flor::Procedure < Flor::Node
162
188
 
163
189
  def execute_child(index=0, sub=nil, h=nil)
164
190
 
165
- return reply \
191
+ return wrap_reply \
166
192
  if index < 0 || ( ! tree[1].is_a?(Array)) || tree[1][index] == nil
167
193
 
168
194
  sub = counter_next('subs') if sub == true
@@ -176,7 +202,7 @@ class Flor::Procedure < Flor::Node
176
202
  'payload' => payload.current }
177
203
  hh.merge!(h) if h
178
204
 
179
- reply(hh)
205
+ wrap(hh)
180
206
  end
181
207
 
182
208
  def unatt_unkeyed_children(first_only=false)
@@ -221,6 +247,17 @@ class Flor::Procedure < Flor::Node
221
247
  @node['tree'] = [ tree[0], cn, tree[2] ]
222
248
  end
223
249
 
250
+ def do_execute
251
+
252
+ pre_execute
253
+
254
+ pnode = @execution['nodes'][parent]
255
+ cnodes = pnode && (pnode['cnodes'] ||= [])
256
+ cnodes << nid if cnodes && ( ! cnodes.include?(nid))
257
+
258
+ execute
259
+ end
260
+
224
261
  def execute
225
262
 
226
263
  receive
@@ -231,12 +268,10 @@ class Flor::Procedure < Flor::Node
231
268
  #
232
269
  def do_receive
233
270
 
234
- from_child =
235
- if ns = @node['cnodes']
236
- ns.delete(from)
237
- else
238
- nil
239
- end
271
+ remove = @message['flavour'] != 'flank'
272
+
273
+ from_child = nil
274
+ from_child = cnodes.delete(from) if cnodes_any? && remove
240
275
 
241
276
  if node_closed?
242
277
  return receive_from_child_when_closed if from_child
@@ -273,7 +308,7 @@ class Flor::Procedure < Flor::Node
273
308
 
274
309
  def receive_from_child_when_closed
275
310
 
276
- (@node['cnodes'].empty? && pop_on_receive_last) || reply
311
+ (cnodes.empty? && pop_on_receive_last) || wrap_reply
277
312
  end
278
313
 
279
314
  def receive_when_closed
@@ -333,7 +368,7 @@ class Flor::Procedure < Flor::Node
333
368
 
334
369
  def receive_last
335
370
 
336
- reply
371
+ wrap_reply
337
372
  end
338
373
 
339
374
  # Used by 'cursor' (and 'loop') when
@@ -356,21 +391,27 @@ class Flor::Procedure < Flor::Node
356
391
 
357
392
  (@node['tags'] ||= []).concat(ret)
358
393
 
359
- reply('point' => 'entered', 'nid' => nid, 'tags' => ret)
394
+ wrap('point' => 'entered', 'nid' => nid, 'tags' => ret)
360
395
  end
361
396
 
362
- def reply(h={})
397
+ def wrap(h={})
363
398
 
364
399
  m = {}
365
400
  m['point'] = 'receive'
366
401
  m['exid'] = exid
367
- m['nid'] = parent
402
+ m['nid'] = @node['noreply'] ? nil : parent
368
403
  m['from'] = nid
369
404
 
370
405
  m['sm'] = @message['m']
371
406
 
372
- ret = :no
373
- ret = h.delete('ret') if h.has_key?('ret')
407
+ ret =
408
+ if @node.has_key?('aret') # from the 'ret' common attribute
409
+ @node['aret']
410
+ elsif h.has_key?('ret')
411
+ h.delete('ret')
412
+ else
413
+ :no
414
+ end
374
415
 
375
416
  m['payload'] = payload.current
376
417
 
@@ -378,25 +419,32 @@ class Flor::Procedure < Flor::Node
378
419
 
379
420
  m['payload']['ret'] = ret if ret != :no
380
421
 
381
- end_node if m['nid'] == parent && m['point'] == 'receive'
382
-
383
422
  [ m ]
384
423
  end
385
424
 
386
- def queue(h); reply(h); end
425
+ alias wrap_reply wrap
426
+
427
+ def wrap_error(o)
428
+
429
+ wrap('point' => 'failed', 'error' => Flor.to_error(o))
430
+ end
431
+
432
+ def wrap_cancel(h)
387
433
 
388
- def error_reply(o)
434
+ h['point'] ||= 'cancel'
435
+ h['nid'] ||= nid
436
+ #h['flavour'] ||= 'xxx'
389
437
 
390
- reply('point' => 'failed', 'error' => Flor.to_error(o))
438
+ wrap(h)
391
439
  end
392
440
 
393
- def schedule(h)
441
+ def wrap_schedule(h)
394
442
 
395
443
  h['point'] ||= 'schedule'
396
444
  h['payload'] ||= {}
397
445
  h['nid'] ||= nid
398
446
 
399
- reply(h)
447
+ wrap(h)
400
448
  end
401
449
 
402
450
  def lookup_var_node(node, mode, k=nil)
@@ -483,7 +531,7 @@ class Flor::Procedure < Flor::Node
483
531
  vars[key] = args[i]
484
532
  end
485
533
 
486
- ms = reply(
534
+ ms = wrap(
487
535
  'point' => 'execute',
488
536
  'nid' => ani,
489
537
  'tree' => [ '_apply', t[1], line ],
@@ -497,23 +545,28 @@ class Flor::Procedure < Flor::Node
497
545
  ms
498
546
  end
499
547
 
500
- def cancel_nodes(nids)
548
+ def wrap_cancel_nodes(nids, h)
501
549
 
502
550
  (nids || [])
503
- .collect { |i| reply('point' => 'cancel', 'nid' => i, 'from' => nid) }
551
+ .collect { |i| wrap_cancel(h.merge('nid' => i, 'from' => nid)) }
504
552
  .flatten(1)
505
553
  end
506
554
 
507
- def cancel_reply # "cancel" as a noun
555
+ def wrap_cancelled
508
556
 
509
- reply(
557
+ wrap(
510
558
  'cause' => 'cancel',
511
559
  'payload' => @message['payload'] || @node['payload'])
512
560
  end
513
561
 
514
- def cancel_children
562
+ def wrap_cancel_children(h={})
563
+
564
+ wrap_cancel_nodes(cnodes, h)
565
+ end
566
+
567
+ def do_wrap_cancel_children(h={})
515
568
 
516
- cancel_nodes(@node['cnodes'])
569
+ wrap_cancel_children(h).instance_eval { |ms| ms.any? ? ms : nil }
517
570
  end
518
571
 
519
572
  # The executor calls #do_cancel, while most procedure implementations
@@ -521,15 +574,20 @@ class Flor::Procedure < Flor::Node
521
574
  #
522
575
  def do_cancel
523
576
 
524
- return kill if @message['flavour'] == 'kill'
577
+ if @message['flavour'] == 'kill'
578
+
579
+ return [] if node_ended?
580
+ kill
525
581
 
526
- orl = @message['on_receive_last']
527
- @node['on_receive_last'] = orl if orl
582
+ else
528
583
 
529
- return cancel_when_ended if node_ended?
530
- return cancel_when_closed if node_closed?
584
+ orl = @message['on_receive_last']
585
+ @node['on_receive_last'] = orl if orl
531
586
 
532
- cancel
587
+ return cancel_when_ended if node_ended?
588
+ return cancel_when_closed if node_closed?
589
+ cancel
590
+ end
533
591
  end
534
592
 
535
593
  def cancel_when_ended
@@ -546,20 +604,16 @@ class Flor::Procedure < Flor::Node
546
604
 
547
605
  close_node
548
606
 
549
- nids = @node['cnodes']
550
-
551
- if nids && nids.any?
552
- cancel_children
553
- else
554
- cancel_reply
555
- end
607
+ do_wrap_cancel_children ||
608
+ wrap_cancelled
556
609
  end
557
610
 
558
611
  def kill
559
612
 
560
- return [] if node_ended?
613
+ close_node
561
614
 
562
- reply + cancel_children
615
+ wrap_cancel_children('flavour' => 'kill') +
616
+ wrap_cancelled
563
617
  end
564
618
  end
565
619