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
@@ -57,7 +57,7 @@ class Flor::Pro::Cursor < Flor::Procedure
57
57
  @node['subs'] << counter_next('subs')
58
58
  execute_child(first_non_att_child_id, @node['subs'].last)
59
59
  else
60
- reply
60
+ wrap_reply
61
61
  end
62
62
  else
63
63
  execute_child(@ncid, @node['subs'].last)
@@ -105,7 +105,7 @@ class Flor::Pro::Cursor < Flor::Procedure
105
105
  if fla == 'continue'
106
106
 
107
107
  @node['on_receive_last'] =
108
- reply(
108
+ wrap(
109
109
  'nid' => nid, 'from' => "#{nid}_#{children.size + 1}",
110
110
  'orl' => fla,
111
111
  'payload' => Flor.dup(message['payload']))
@@ -66,7 +66,7 @@ class Flor::Pro::Define < Flor::Procedure
66
66
 
67
67
  payload['ret'] = val
68
68
 
69
- reply
69
+ wrap_reply
70
70
  end
71
71
  end
72
72
 
@@ -20,12 +20,7 @@ class Flor::Pro::Fail < Flor::Procedure
20
20
  (payload['ret'] || 'error').to_s,
21
21
  Flor::Node.new(@executor, @node, @message))
22
22
 
23
- #fail err
24
- #
25
- # let's reply with the failed message directly,
26
- # no need for a Ruby backtrace, it's an error at the Flor level.
27
- #
28
- reply('point' => 'failed', 'error' => Flor.to_error(err))
23
+ wrap_error(err)
29
24
  end
30
25
  end
31
26
 
data/lib/flor/pcore/if.rb CHANGED
@@ -52,7 +52,7 @@ class Flor::Pro::If < Flor::Procedure
52
52
 
53
53
  def receive_non_att
54
54
 
55
- return reply if @fcid > first_unkeyed_child_id
55
+ return wrap_reply if @fcid > first_unkeyed_child_id
56
56
  # "else" or "then" answered, replying to parent...
57
57
 
58
58
  off =
@@ -65,7 +65,7 @@ class Flor::Pro::If < Flor::Procedure
65
65
  nxt = @fcid + off
66
66
 
67
67
  if nxt >= children.size
68
- reply('ret' => node_payload_ret)
68
+ wrap_reply('ret' => node_payload_ret)
69
69
  else
70
70
  execute_child(nxt)
71
71
  end
@@ -40,7 +40,7 @@ class Flor::Pro::Map < Flor::Procedure
40
40
  @node['idx'] += 1
41
41
  @node['mtime'] = Flor.tstamp
42
42
 
43
- return reply('ret' => @node['res']) \
43
+ return wrap_reply('ret' => @node['res']) \
44
44
  if @node['idx'] == @node['col'].size
45
45
 
46
46
  @node['vars']['idx'] = @node['idx']
@@ -0,0 +1,92 @@
1
+
2
+ class Flor::Pro::Matchr < Flor::Procedure
3
+ #
4
+ # Matches a string against a regular expression.
5
+ #
6
+ # `matchr s r` will return an array of matching strings in `s` from regular
7
+ # expression `r`.
8
+ #
9
+ # `match? s r` will return true if string `s` matches regular expression `r`.
10
+ # It returns false else.
11
+ #
12
+ # ```
13
+ # matchr "alpha", /bravo/
14
+ # # yields an empty array []
15
+ #
16
+ # match? "alpha", /bravo/ # => false
17
+ # match? "alpha", /alp/ # => true
18
+ # ```
19
+ #
20
+ # The second argument to `match?` and `matchr` is turned into a
21
+ # regular expression.
22
+ # ```
23
+ # match? "alpha", 'alp' # => true
24
+ # ```
25
+ #
26
+ # When there is a single argument, `matchr` and `match?` will try
27
+ # to take the string out of `$(f.ret)`.
28
+ # ```
29
+ # "blue moon"
30
+ # match? (/blue/)
31
+ # # => true
32
+ #
33
+ # "blue moon"
34
+ # match? 'blue'
35
+ # # => true
36
+ #
37
+ # /blue/
38
+ # match? 'blue moon'
39
+ # # => true
40
+ #
41
+ # 'blue'
42
+ # match? (/black/)
43
+ # # => false
44
+ # ```
45
+
46
+ names %w[ matchr match? ]
47
+
48
+ def pre_execute
49
+
50
+ @node['rets'] = []
51
+ end
52
+
53
+ def receive_last
54
+
55
+ rex, str = arguments
56
+
57
+ m = rex.match(str)
58
+
59
+ payload['ret'] =
60
+ if @node['heap'] == 'match?'
61
+ !! m
62
+ else
63
+ m ? m.to_a : []
64
+ end
65
+
66
+ wrap_reply
67
+ end
68
+
69
+ protected
70
+
71
+ def arguments
72
+
73
+ rets = @node['rets'].dup
74
+ rets.unshift(node_payload_ret) if rets.size < 2
75
+
76
+ fail ArgumentError.new(
77
+ "'#{tree[0]}' needs 1 or 2 arguments"
78
+ ) if rets.size < 2
79
+
80
+ rex =
81
+ rets.find { |r| r.is_a?(Array) && r[0] == '_rxs' } ||
82
+ rets.last
83
+
84
+ str = (rets - [ rex ]).first
85
+
86
+ rex = rex.is_a?(String) ? rex : rex[1].to_s
87
+ rex = rex.match(/\A\/[^\/]*\/[a-z]*\z/) ? Kernel.eval(rex) : Regexp.new(rex)
88
+
89
+ [ rex, str ]
90
+ end
91
+ end
92
+
@@ -27,10 +27,9 @@ class Flor::Pro::Move < Flor::Procedure
27
27
 
28
28
  to = att('to')
29
29
 
30
- rep = is_ancestor_node?(nid) ? [] : reply
30
+ rep = is_ancestor_node?(nid) ? [] : wrap_reply
31
31
 
32
- reply(
33
- 'point' => 'cancel',
32
+ wrap_cancel(
34
33
  'nid' => nid,
35
34
  'flavour' => @node['heap'], # "move"
36
35
  'payload' => rep.any? ? payload.copy_current : payload.current,
@@ -16,7 +16,7 @@ class Flor::Pro::NoEval < Flor::Procedure
16
16
 
17
17
  def execute
18
18
 
19
- reply
19
+ wrap
20
20
  end
21
21
  end
22
22
 
@@ -17,7 +17,7 @@ class Flor::Pro::NoRet < Flor::Procedure
17
17
 
18
18
  payload['ret'] = node_payload_ret
19
19
 
20
- reply
20
+ wrap
21
21
  end
22
22
  end
23
23
 
@@ -39,7 +39,7 @@ class Flor::Pro::Push < Flor::Procedure
39
39
  payload['ret'] = node_payload_ret \
40
40
  unless tree[0] == 'pushr'
41
41
 
42
- reply
42
+ wrap_reply
43
43
  end
44
44
  end
45
45
 
@@ -36,7 +36,7 @@ class Flor::Pro::Rand < Flor::Procedure
36
36
 
37
37
  payload['ret'] = Random.rand(a...b)
38
38
 
39
- reply
39
+ wrap
40
40
  end
41
41
 
42
42
  protected
@@ -27,7 +27,7 @@ class Flor::Pro::Set < Flor::Procedure
27
27
  node_payload_ret
28
28
  end
29
29
 
30
- reply
30
+ wrap_reply
31
31
  end
32
32
  end
33
33
 
@@ -14,7 +14,7 @@ class Flor::Pro::Twig < Flor::Procedure
14
14
  nac = non_att_children
15
15
 
16
16
  if nac.size == 1
17
- reply('ret' => nac.first)
17
+ wrap_reply('ret' => nac.first)
18
18
  else
19
19
  super
20
20
  end
@@ -26,7 +26,7 @@ class Flor::Pro::Twig < Flor::Procedure
26
26
 
27
27
  set_value(payload['ret'], t)
28
28
 
29
- reply
29
+ wrap
30
30
  end
31
31
  end
32
32
 
@@ -36,13 +36,15 @@ class Flor::Pro::Until < Flor::Procedure
36
36
  # over
37
37
 
38
38
  ret = @node.has_key?('cret') ? @node['cret'] : node_payload_ret
39
- reply('ret' => ret)
39
+
40
+ wrap_reply('ret' => ret)
40
41
 
41
42
  else
42
43
  #
43
44
  # condition yield false, enter "block"
44
45
 
45
46
  payload['ret'] = node_payload_ret
47
+
46
48
  execute_child(@ncid, @node['subs'].last)
47
49
  end
48
50
 
@@ -54,6 +56,7 @@ class Flor::Pro::Until < Flor::Procedure
54
56
 
55
57
  @node['cret'] = payload['ret']
56
58
  payload['ret'] = node_payload_ret
59
+
57
60
  execute_child(first_unkeyed_child_id, @node['subs'].last)
58
61
 
59
62
  else
@@ -10,7 +10,7 @@ class Flor::Pro::Val < Flor::Procedure
10
10
 
11
11
  payload['ret'] = heat
12
12
 
13
- reply
13
+ wrap_reply
14
14
  end
15
15
  end
16
16
 
@@ -37,9 +37,8 @@ class Flor::Pro::Cancel < Flor::Procedure
37
37
 
38
38
  fla = @node['heap']
39
39
 
40
- nids.uniq.collect { |nid|
41
- reply('point' => 'cancel', 'nid' => nid, 'flavour' => fla).first
42
- } + reply
40
+ nids.uniq.map { |nid| wrap_cancel('nid' => nid, 'flavour' => fla)[0] } +
41
+ wrap_reply
43
42
  end
44
43
  end
45
44
 
@@ -30,23 +30,22 @@ class Flor::Pro::Cmap < Flor::Procedure
30
30
  "cmap expects a function"
31
31
  ) unless Flor.is_func_tree?(fun)
32
32
 
33
- col = att(nil)
34
33
  @node['fun'] = fun
35
34
 
36
- col.collect.with_index do |e, i|
37
- apply(@node['fun'], [ e, i ], tree[2])
38
- end.flatten(1)
35
+ att(nil)
36
+ .collect.with_index { |e, i| apply(fun, [ e, i ], tree[2]) }
37
+ .flatten(1)
39
38
  end
40
39
 
41
40
  def receive_elt
42
41
 
43
42
  @node['col'] << payload['ret']
44
43
 
45
- return [] if @node['cnodes'].any?
44
+ return [] if cnodes_any?
46
45
 
47
46
  payload['ret'] = @node['col']
48
47
 
49
- reply
48
+ wrap
50
49
  end
51
50
  end
52
51
 
@@ -64,7 +64,7 @@ class Flor::Pro::Concurrence < Flor::Procedure
64
64
 
65
65
  def receive_last_att
66
66
 
67
- return reply unless children[@ncid]
67
+ return wrap_reply unless children[@ncid]
68
68
 
69
69
  (@ncid..children.size - 1)
70
70
  .map { |i| execute_child(i, 0, 'payload' => payload.copy_current) }
@@ -78,8 +78,6 @@ class Flor::Pro::Concurrence < Flor::Procedure
78
78
  @node['receiver'] ||= determine_receiver
79
79
  @node['merger'] ||= determine_merger
80
80
 
81
- (@node['cnodes'] || []).delete(from)
82
-
83
81
  return [] if @node['over']
84
82
 
85
83
  over = invoke_receiver
@@ -93,7 +91,7 @@ class Flor::Pro::Concurrence < Flor::Procedure
93
91
  # determine post-concurrence payload
94
92
 
95
93
  cancel_remaining +
96
- reply('payload' => pld)
94
+ wrap_reply('payload' => pld)
97
95
  end
98
96
 
99
97
  def receive_from_child_when_closed
@@ -132,7 +130,7 @@ class Flor::Pro::Concurrence < Flor::Procedure
132
130
 
133
131
  return [] if rem == 'forget'
134
132
 
135
- cancel_nodes(@node['cnodes'])
133
+ wrap_cancel_children
136
134
  end
137
135
 
138
136
  def invoke_receiver
@@ -26,19 +26,34 @@ class Flor::Pro::Schedule < Flor::Procedure
26
26
  "missing a function to call when the scheduler triggers"
27
27
  ) unless fun
28
28
 
29
- msg = apply(fun, [], tree[2], false).first.merge('noreply' => true)
29
+ m = apply(fun, [], tree[2], false).first
30
30
 
31
- type, string =
31
+ t, s =
32
32
  @node['atts'].find { |k, v| %w[ cron at in every ].include?(k) } ||
33
33
  @node['atts'].find { |k, v| k == nil }
34
34
 
35
35
  fail ArgumentError.new(
36
36
  "missing a schedule"
37
- ) unless string
37
+ ) unless s
38
38
 
39
- #m = reply('point' => 'receive').first
39
+ @node['scheduled'] = true
40
40
 
41
- schedule('type' => type, 'string' => string, 'message' => msg)
41
+ wrap_schedule('type' => t, 'string' => s, 'message' => m) +
42
+ flank
43
+ end
44
+
45
+ def receive
46
+
47
+ return [] if @node['scheduled']
48
+ super
49
+ end
50
+
51
+ # "schedule" keeps track of its children, but does not cascade 'cancel'
52
+ # to them, unless the cancel flavour is 'kill'.
53
+ #
54
+ def wrap_cancel_children(h={})
55
+
56
+ h['flavour'] == 'kill' ? super : []
42
57
  end
43
58
  end
44
59
 
@@ -14,7 +14,7 @@ class Flor::Pro::Signal < Flor::Procedure
14
14
 
15
15
  return super unless name
16
16
 
17
- reply(
17
+ wrap(
18
18
  'point' => 'signal', 'nid' => nid, 'name' => name,
19
19
  'payload' => payload.copy_current
20
20
  ) + super
@@ -21,9 +21,9 @@ class Flor::Pro::Sleep < Flor::Procedure
21
21
  t = att('for', nil)
22
22
  fail ArgumentError.new("missing a sleep time duration") unless t
23
23
 
24
- m = reply('point' => 'receive').first
24
+ m = wrap('point' => 'receive').first
25
25
 
26
- schedule('type' => 'in', 'string' => t, 'message' => m)
26
+ wrap_schedule('type' => 'in', 'string' => t, 'message' => m)
27
27
  end
28
28
  end
29
29
 
@@ -10,7 +10,7 @@ class Flor::Pro::Task < Flor::Procedure
10
10
 
11
11
  def do_receive
12
12
 
13
- return reply('payload' => determine_reply_payload) \
13
+ return wrap_reply('payload' => determine_reply_payload) \
14
14
  if point == 'receive' && from == nil
15
15
 
16
16
  super
@@ -38,7 +38,7 @@ class Flor::Pro::Task < Flor::Procedure
38
38
 
39
39
  attl, attd = determine_atts
40
40
 
41
- queue(
41
+ wrap(
42
42
  'point' => 'task',
43
43
  'exid' => exid, 'nid' => nid,
44
44
  'tasker' => tasker,
@@ -52,7 +52,7 @@ class Flor::Pro::Task < Flor::Procedure
52
52
 
53
53
  attl, attd = determine_atts
54
54
 
55
- queue(
55
+ wrap(
56
56
  'point' => 'detask',
57
57
  'exid' => exid, 'nid' => nid,
58
58
  'tasker' => att(nil),