flor 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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