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
@@ -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),