flor 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +14 -1
  3. data/CREDITS.md +1 -0
  4. data/LICENSE.txt +1 -1
  5. data/Makefile +6 -2
  6. data/README.md +2 -1
  7. data/flor.gemspec +12 -2
  8. data/lib/flor.rb +3 -3
  9. data/lib/flor/colours.rb +1 -1
  10. data/lib/flor/conf.rb +3 -4
  11. data/lib/flor/core/executor.rb +31 -61
  12. data/lib/flor/core/node.rb +213 -96
  13. data/lib/flor/core/procedure.rb +194 -75
  14. data/lib/flor/core/texecutor.rb +6 -7
  15. data/lib/flor/djan.rb +41 -22
  16. data/lib/flor/flor.rb +137 -42
  17. data/lib/flor/id.rb +77 -59
  18. data/lib/flor/log.rb +43 -22
  19. data/lib/flor/migrations/0001_tables.rb +7 -7
  20. data/lib/flor/parser.rb +271 -74
  21. data/lib/flor/pcore/_apply.rb +108 -0
  22. data/lib/flor/pcore/_atom.rb +2 -4
  23. data/lib/flor/pcore/_att.rb +54 -37
  24. data/lib/flor/pcore/_dmute.rb +18 -0
  25. data/lib/flor/pcore/_dol.rb +17 -0
  26. data/lib/flor/pcore/_dqs.rb +35 -0
  27. data/lib/flor/pcore/_head.rb +25 -0
  28. data/lib/flor/pcore/_obj.rb +1 -3
  29. data/lib/flor/pcore/_pat_guard.rb +1 -1
  30. data/lib/flor/pcore/_pat_obj.rb +11 -3
  31. data/lib/flor/pcore/_pat_regex.rb +16 -2
  32. data/lib/flor/pcore/_ref.rb +51 -0
  33. data/lib/flor/pcore/_rxs.rb +27 -0
  34. data/lib/flor/pcore/_val.rb +11 -6
  35. data/lib/flor/pcore/{logo.rb → andor.rb} +4 -6
  36. data/lib/flor/pcore/apply.rb +72 -2
  37. data/lib/flor/pcore/arith.rb +16 -4
  38. data/lib/flor/pcore/array_qmark.rb +100 -0
  39. data/lib/flor/pcore/break.rb +1 -2
  40. data/lib/flor/pcore/case.rb +1 -1
  41. data/lib/flor/pcore/cmp.rb +3 -2
  42. data/lib/flor/pcore/collect.rb +2 -2
  43. data/lib/flor/pcore/cond.rb +19 -1
  44. data/lib/flor/pcore/cursor.rb +12 -11
  45. data/lib/flor/pcore/define.rb +30 -4
  46. data/lib/flor/pcore/do_return.rb +3 -0
  47. data/lib/flor/pcore/flatten.rb +39 -0
  48. data/lib/flor/pcore/if.rb +15 -5
  49. data/lib/flor/pcore/includes.rb +5 -2
  50. data/lib/flor/pcore/inject.rb +1 -1
  51. data/lib/flor/pcore/iterator.rb +28 -18
  52. data/lib/flor/pcore/keys.rb +2 -2
  53. data/lib/flor/pcore/map.rb +19 -1
  54. data/lib/flor/pcore/match.rb +2 -2
  55. data/lib/flor/pcore/matchr.rb +18 -5
  56. data/lib/flor/pcore/max.rb +51 -0
  57. data/lib/flor/pcore/merge.rb +134 -0
  58. data/lib/flor/pcore/move.rb +1 -1
  59. data/lib/flor/pcore/noret.rb +1 -1
  60. data/lib/flor/pcore/not.rb +15 -1
  61. data/lib/flor/pcore/on.rb +11 -0
  62. data/lib/flor/pcore/on_cancel.rb +5 -1
  63. data/lib/flor/pcore/on_error.rb +69 -4
  64. data/lib/flor/pcore/push.rb +4 -9
  65. data/lib/flor/pcore/range.rb +5 -5
  66. data/lib/flor/pcore/reduce.rb +5 -18
  67. data/lib/flor/pcore/return.rb +26 -0
  68. data/lib/flor/pcore/reverse.rb +4 -0
  69. data/lib/flor/pcore/sequence.rb +8 -1
  70. data/lib/flor/pcore/set.rb +74 -15
  71. data/lib/flor/pcore/shuffle.rb +71 -0
  72. data/lib/flor/pcore/slice.rb +137 -0
  73. data/lib/flor/pcore/sort.rb +244 -0
  74. data/lib/flor/pcore/sort_by.rb +67 -0
  75. data/lib/flor/pcore/split.rb +39 -0
  76. data/lib/flor/pcore/stall.rb +1 -1
  77. data/lib/flor/pcore/strings.rb +123 -0
  78. data/lib/flor/pcore/timestamp.rb +34 -0
  79. data/lib/flor/pcore/to_array.rb +2 -3
  80. data/lib/flor/pcore/twig.rb +1 -1
  81. data/lib/flor/pcore/type_of.rb +37 -0
  82. data/lib/flor/pcore/until.rb +3 -3
  83. data/lib/flor/punit/cancel.rb +3 -3
  84. data/lib/flor/punit/ccollect.rb +29 -0
  85. data/lib/flor/punit/cmap.rb +76 -20
  86. data/lib/flor/punit/concurrence.rb +440 -33
  87. data/lib/flor/punit/cron.rb +1 -1
  88. data/lib/flor/punit/every.rb +1 -1
  89. data/lib/flor/punit/graft.rb +2 -3
  90. data/lib/flor/punit/on_timeout.rb +5 -1
  91. data/lib/flor/punit/part.rb +63 -0
  92. data/lib/flor/punit/schedule.rb +1 -1
  93. data/lib/flor/punit/task.rb +52 -10
  94. data/lib/flor/punit/trap.rb +4 -5
  95. data/lib/flor/tools/shell.rb +37 -18
  96. data/lib/flor/unit/caller.rb +23 -11
  97. data/lib/flor/unit/executor.rb +33 -12
  98. data/lib/flor/unit/ganger.rb +10 -1
  99. data/lib/flor/unit/hook.rb +2 -1
  100. data/lib/flor/unit/hooker.rb +13 -2
  101. data/lib/flor/unit/loader.rb +7 -7
  102. data/lib/flor/unit/logger.rb +15 -17
  103. data/lib/flor/unit/models.rb +4 -2
  104. data/lib/flor/unit/models/execution.rb +83 -38
  105. data/lib/flor/unit/models/message.rb +16 -0
  106. data/lib/flor/unit/models/pointer.rb +24 -0
  107. data/lib/flor/unit/models/timer.rb +25 -4
  108. data/lib/flor/unit/models/trace.rb +14 -0
  109. data/lib/flor/unit/models/trap.rb +39 -14
  110. data/lib/flor/unit/scheduler.rb +11 -7
  111. data/lib/flor/unit/storage.rb +55 -39
  112. data/lib/flor/unit/taskers.rb +17 -14
  113. data/lib/flor/unit/waiter.rb +4 -3
  114. metadata +40 -10
  115. data/lib/flor/changes.rb +0 -26
  116. data/lib/flor/dollar.rb +0 -224
  117. data/lib/flor/unit/hooks.rb +0 -37
@@ -57,16 +57,16 @@ class Flor::Pro::Cursor < Flor::Procedure
57
57
 
58
58
  def receive_first
59
59
 
60
- @node['vars'] =
61
- {}
60
+ # break/continue/move are set as variables so that they can
61
+ # be aliases, it's useful in nested loops
62
62
 
63
- @node['vars']['break'] =
64
- [ '_proc', { 'proc' => 'break', 'nid' => nid }, tree[-1] ]
65
- @node['vars']['continue'] =
66
- [ '_proc', { 'proc' => 'continue', 'nid' => nid }, tree[-1] ]
67
-
68
- @node['vars']['move'] =
69
- [ '_proc', { 'proc' => 'move', 'nid' => nid }, tree[-1] ]
63
+ @node['vars'] = {
64
+ 'break' =>
65
+ [ '_proc', { 'proc' => 'break', 'nid' => nid }, tree[-1] ],
66
+ 'continue' =>
67
+ [ '_proc', { 'proc' => 'continue', 'nid' => nid }, tree[-1] ],
68
+ 'move' =>
69
+ [ '_proc', { 'proc' => 'move', 'nid' => nid }, tree[-1] ] }
70
70
 
71
71
  super
72
72
  end
@@ -92,7 +92,8 @@ class Flor::Pro::Cursor < Flor::Procedure
92
92
 
93
93
  def cancel_when_closed
94
94
 
95
- return [] unless @message['flavour'] == 'break'
95
+ return cancel if node_status_flavour == 'on-error'
96
+ return [] if @message['flavour'] != 'break'
96
97
 
97
98
  cancel
98
99
  end
@@ -117,7 +118,7 @@ class Flor::Pro::Cursor < Flor::Procedure
117
118
  @node['on_receive_last'] = nil
118
119
  end
119
120
 
120
- super#.tap { |ms| pp ms }
121
+ super
121
122
  end
122
123
 
123
124
  protected
@@ -32,6 +32,10 @@ class Flor::Pro::Define < Flor::Procedure
32
32
  # define "$(prefix)-sum" a b
33
33
  # + a b
34
34
  # ```
35
+ #
36
+ # ## see also
37
+ #
38
+ # apply.
35
39
 
36
40
  names %w[ def fun define ]
37
41
 
@@ -46,7 +50,7 @@ class Flor::Pro::Define < Flor::Procedure
46
50
 
47
51
  def receive_att
48
52
 
49
- t = tree
53
+ t = flatten_tree
50
54
  cnode = lookup_var_node(@node, 'l')
51
55
  cnid = cnode['nid']
52
56
  fun = counter_next('funs') - 1
@@ -58,7 +62,7 @@ class Flor::Pro::Define < Flor::Procedure
58
62
  { 'nid' => nid, 'tree' => t, 'cnid' => cnid, 'fun' => fun },
59
63
  t[2] ]
60
64
 
61
- if t[0] == 'define'
65
+ if heap == 'define'
62
66
  name =
63
67
  if @message['point'] == 'execute'
64
68
  t[1].first[1].first[0]
@@ -68,9 +72,31 @@ class Flor::Pro::Define < Flor::Procedure
68
72
  set_var('', name, val)
69
73
  end
70
74
 
71
- payload['ret'] = val
75
+ wrap('ret' => val)
76
+ end
77
+
78
+ protected
79
+
80
+ def flatten_tree
81
+
82
+ off = heap == 'define' ? 1 : 0
83
+ sig = tree[1][off..-1].select { |t| t[0] == '_att' }
84
+
85
+ return tree if sig.all? { |a| a[1][0][1] == [] }
86
+
87
+ # There is a parenthese around the parameters, let's unwrap that...
88
+
89
+ hed = Flor.dup(tree[1][0, off])
90
+ sig = Flor.dup(sig)
91
+ bdy = Flor.dup(tree[1][(off + sig.length)..-1])
92
+
93
+ att0 = sig[0][1][0]
94
+ att0atts = att0[1]
95
+ att0[1] = []
96
+
97
+ sig = sig + att0atts
72
98
 
73
- wrap_reply
99
+ [ heap, hed + sig + bdy, *tree[2..-1] ]
74
100
  end
75
101
  end
76
102
 
@@ -17,6 +17,9 @@ class Flor::Pro::DoReturn < Flor::Macro
17
17
  # do-this-failure-prone-thing _
18
18
  # ```
19
19
  #
20
+ # ## see also
21
+ #
22
+ # return
20
23
 
21
24
  name 'do-return'
22
25
 
@@ -0,0 +1,39 @@
1
+
2
+ class Flor::Pro::Flatten < Flor::Procedure
3
+ #
4
+ # Flattens the given array
5
+ #
6
+ # ```
7
+ # flatten [ 1, [ 2, [ 3 ], 4 ] ] # ==> [ 1, 2, 3, 4 ]
8
+ # flatten [ 1, [ 2, [ 3 ], 4 ] ], 1 # ==> [ 1, 2, [ 3 ], 4 ]
9
+ #
10
+ # [ 1, [ 2, [ 3 ], 4 ] ]
11
+ # flatten 1 # ==> [ 1, 2, [ 3 ], 4 ]
12
+ #
13
+ # [ 1, [ 2, [ 3 ], 4 ] ]
14
+ # flatten _ # ==> [ 1, 2, 3, 4 ]
15
+ # ```
16
+
17
+ name 'flatten'
18
+
19
+ def pre_execute
20
+
21
+ @node['rets'] = []
22
+
23
+ unatt_unkeyed_children
24
+ end
25
+
26
+ def receive_last
27
+
28
+ col = (@node['rets'] + [ node_payload_ret ])
29
+ .find { |r| r.is_a?(Array) }
30
+
31
+ lvl = @node['rets']
32
+ .find { |r| r.is_a?(Integer) } || -1
33
+
34
+ fail Flor::FlorError.new('missing collection', self) if col == nil
35
+
36
+ wrap('ret' => col.flatten(lvl))
37
+ end
38
+ end
39
+
@@ -1,7 +1,7 @@
1
1
 
2
2
  class Flor::Pro::If < Flor::Procedure
3
3
  #
4
- # The classical "if" (and its "unless" sidequick)
4
+ # The classical "if" (and its "unless" sidekick)
5
5
  #
6
6
  # ```
7
7
  # if
@@ -14,7 +14,7 @@ class Flor::Pro::If < Flor::Procedure
14
14
  # set f.designation 'child'
15
15
  # sequence # else
16
16
  # set f.designation 'baby'
17
- # order_baby_food
17
+ # order_baby_food _
18
18
  # ```
19
19
  #
20
20
  # Warning, the direct children are relevant. In the following snip,
@@ -22,7 +22,7 @@ class Flor::Pro::If < Flor::Procedure
22
22
  # ```
23
23
  # if (f.age > 3)
24
24
  # set f.designation 'child'
25
- # order_child_seat
25
+ # order_child_seat _
26
26
  # ```
27
27
  #
28
28
  # ## postfix `if` and `unless`
@@ -37,8 +37,17 @@ class Flor::Pro::If < Flor::Procedure
37
37
  # a > b
38
38
  # task 'bob'
39
39
  # ```
40
+ #
41
+ # ## else-if
42
+ #
43
+ # Currently, if an "else if" is needed, it's better to use [cond](cond.md).
44
+ #
45
+ #
46
+ # ## see also
47
+ #
48
+ # Cond, case, match.
40
49
 
41
- names %w[ if unless ife unlesse ]
50
+ names %w[ if unless ife unlesse _if _unless ]
42
51
  #
43
52
  # removing "ife" and "unlesse" leads to
44
53
  # LoadError: cannot load such file -- sequel/adapters/
@@ -56,7 +65,8 @@ class Flor::Pro::If < Flor::Procedure
56
65
  # "else" or "then" answered, replying to parent...
57
66
 
58
67
  off =
59
- if tree[0] == 'unless' || tree[0] == 'unlesse'
68
+ case heap
69
+ when 'unless', 'unlesse', '_unless'
60
70
  Flor.false?(payload['ret']) ? 1 : 2
61
71
  else # 'if' or 'ife'
62
72
  Flor.true?(payload['ret']) ? 1 : 2
@@ -16,17 +16,20 @@ class Flor::Pro::Includes < Flor::Procedure
16
16
  elt = :nil
17
17
 
18
18
  @node['rets'].each do |ret|
19
- if col == nil && (ret.is_a?(Array) || ret.is_a?(Hash))
19
+ if col == nil && Flor.is_collection?(ret)
20
20
  col = ret
21
21
  elsif elt == :nil
22
22
  elt = ret
23
23
  end
24
24
  end
25
25
 
26
+ ret = (col == nil) && node_payload_ret
27
+ col = ret if Flor.is_collection?(ret)
28
+
26
29
  fail Flor::FlorError.new('missing collection', self) if col == nil
27
30
  fail Flor::FlorError.new('missing element', self) if elt == :nil
28
31
 
29
- wrap_reply('ret' => col.include?(elt))
32
+ wrap('ret' => col.include?(elt))
30
33
  end
31
34
  end
32
35
 
@@ -4,7 +4,7 @@ require 'flor/pcore/iterator'
4
4
 
5
5
  class Flor::Pro::Inject < Flor::Macro::Iterator
6
6
  #
7
- # Inject is a simplified version of [reduce](reduce.md).
7
+ # A simplified version of [reduce](reduce.md).
8
8
  #
9
9
  # Inject takes a collection and a block. It reduces the collection
10
10
  # to a single result thanks to the block.
@@ -66,21 +66,20 @@ class Flor::Pro::Iterator < Flor::Procedure
66
66
  .each { |a|
67
67
  if Flor.is_func_tree?(a)
68
68
  @node['fun'] ||= a
69
- elsif a.is_a?(Array) || a.is_a?(Hash)
69
+ elsif Flor.is_collection?(a)
70
70
  @node['ocol'] ||= a
71
71
  end }
72
72
 
73
- @node['ocol'] ||= node_payload_ret
74
- ocol = @node['ocol']
73
+ ocol = (@node['ocol'] ||= node_payload_ret)
75
74
 
76
75
  fail Flor::FlorError.new(
77
76
  "function not given to #{heap.inspect}", self
78
77
  ) if function_mandatory? && ( ! @node['fun'])
79
78
  fail Flor::FlorError.new(
80
79
  "collection not given to #{heap.inspect}", self
81
- ) unless ocol.is_a?(Array) || ocol.is_a?(Hash)
80
+ ) unless Flor.is_collection?(ocol)
82
81
 
83
- @node['col'] = Flor.to_coll(@node['ocol']) if @node['fun']
82
+ @node['col'] = Flor.to_coll(ocol) if @node['fun']
84
83
  @node['args'] = nil
85
84
  end
86
85
 
@@ -91,25 +90,31 @@ class Flor::Pro::Iterator < Flor::Procedure
91
90
 
92
91
  def apply_iteration
93
92
 
94
- vars = determine_iteration_vars
93
+ #vars = determine_iteration_vars
94
+ #args = vars.values
95
+ #vars.each { |k, v| @node['vars'][k] = v }
96
+ #
97
+ #apply(@node['fun'], args, tree[2])
95
98
 
96
- args = vars.values
97
- vars.each { |k, v| @node['vars'][k] = v }
98
-
99
- apply(@node['fun'], args, tree[2])
99
+ apply(@node['fun'], determine_iteration_args, tree[2])
100
100
  end
101
101
 
102
- def determine_iteration_vars
102
+ def determine_iteration_args
103
103
 
104
104
  idx = @node['idx']
105
105
  elt = @node['col'][idx]
106
106
  len = @node['col'].length
107
107
 
108
- if @node['ocol'].is_a?(Array)
109
- { 'elt' => elt, 'idx' => idx, 'len' => len }
110
- else
111
- { 'key' => elt[0], 'val' => elt[1], 'idx' => idx, 'len' => len }
112
- end
108
+ args =
109
+ if @node['ocol'].is_a?(Array)
110
+ [ [ 'elt', elt ] ]
111
+ else
112
+ [ [ 'key', elt[0] ], [ 'val', elt[1] ] ]
113
+ end
114
+ args << [ 'idx', idx ]
115
+ args << [ 'len', len ]
116
+
117
+ args
113
118
  end
114
119
 
115
120
  def iterator_over?
@@ -138,8 +143,13 @@ class Flor::Macro::Iterator < Flor::Macro
138
143
  if non_att_children.any?
139
144
 
140
145
  td = [ 'def', [], l ]
141
- td[1] << [ '_att', [ [ 'res', [], l ] ], l ] if procedure_name == 'reduce'
142
- td[1] << [ '_att', [ [ 'elt', [], l ] ], l ]
146
+
147
+ #td[1] << [ '_att', [ [ 'res', [], l ] ], l ] \
148
+ # if procedure_name == 'reduce'
149
+ #td[1] << [ '_att', [ [ 'elt', [], l ] ], l ]
150
+ #
151
+ # the "_apply" does that work now and it distinguishes elt vs key/val
152
+
143
153
  non_att_children.each { |nac| td[1] << Flor.dup(nac) }
144
154
 
145
155
  th[1] << td
@@ -27,7 +27,7 @@ class Flor::Pro::Keys < Flor::Procedure
27
27
  #
28
28
  # length
29
29
 
30
- names %w{ keys values }
30
+ names %w[ keys values ]
31
31
 
32
32
  def pre_execute
33
33
 
@@ -45,7 +45,7 @@ class Flor::Pro::Keys < Flor::Procedure
45
45
  ) if ret.nil?
46
46
  fail Flor::FlorError.new(
47
47
  "received argument of class #{ret.class}, no #{heap}", self
48
- ) unless ret.is_a?(Array) || ret.is_a?(Hash)
48
+ ) unless Flor.is_collection?(ret)
49
49
 
50
50
  r =
51
51
  if ret.is_a?(Hash)
@@ -63,9 +63,17 @@ class Flor::Pro::Map < Flor::Pro::Iterator
63
63
  # The corresponding `key`, `val`, `idx` and `len` variables are also
64
64
  # set in the closure for the function call.
65
65
  #
66
+ # ## missing collection
67
+ #
68
+ # "map" fails if it is not given a collection.
69
+ #
70
+ # ## missing function
71
+ #
72
+ # "map" returns the collection as is if it is not given a function.
73
+ #
66
74
  # ## see also
67
75
  #
68
- # Collect.
76
+ # Collect, cmap.
69
77
 
70
78
  name 'map'
71
79
 
@@ -80,5 +88,15 @@ class Flor::Pro::Map < Flor::Pro::Iterator
80
88
 
81
89
  @node['res']
82
90
  end
91
+
92
+ def function_mandatory?
93
+
94
+ false
95
+ end
96
+
97
+ def no_iterate
98
+
99
+ wrap('ret' => @node['ocol'])
100
+ end
83
101
  end
84
102
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  class Flor::Pro::Match < Flor::Pro::Case
3
3
  #
4
- # "match" can be thought of as a "destructuring [case](case.md)".
4
+ # A kind of "destructuring [case](case.md)".
5
5
  #
6
6
  # "match", like "case", matches its first argument or the incoming `f.ret`.
7
7
  #
@@ -187,7 +187,7 @@ class Flor::Pro::Match < Flor::Pro::Case
187
187
  #
188
188
  # ## see also
189
189
  #
190
- # Case.
190
+ # Case, if, cond.
191
191
 
192
192
  name 'match'
193
193
 
@@ -9,6 +9,10 @@ class Flor::Pro::Matchr < Flor::Procedure
9
9
  # `match? s r` will return true if string `s` matches regular expression `r`.
10
10
  # It returns false else.
11
11
  #
12
+ # `pmatch s r` will return false it it doesn't match, it will return the
13
+ # string matched else. If there is a capture group (parentheses) in the
14
+ # pattern, it will return its content instead of the whole match.
15
+ #
12
16
  # ```
13
17
  # matchr "alpha", /bravo/
14
18
  # # yields an empty array []
@@ -42,8 +46,17 @@ class Flor::Pro::Matchr < Flor::Procedure
42
46
  # match? (/black/)
43
47
  # # => false
44
48
  # ```
49
+ #
50
+ # ```
51
+ # # pmatch
52
+ # pmatch 'string', /^str/ # ==> 'str'
53
+ # pmatch 'string', /^str(.+)$/ # ==> 'ing'
54
+ # pmatch 'string', /^str(?:.+)$/ # ==> 'string'
55
+ # pmatch 'strogonoff', /^str(?:.{0,3})(.*)$/ # ==> 'noff'
56
+ # pmatch 'sutoringu', /^str/ # ==> ''
57
+ # ```
45
58
 
46
- names %w[ matchr match? ]
59
+ names %w[ matchr match? pmatch ]
47
60
 
48
61
  def pre_execute
49
62
 
@@ -57,10 +70,10 @@ class Flor::Pro::Matchr < Flor::Procedure
57
70
  m = rex.match(str)
58
71
 
59
72
  payload['ret'] =
60
- if @node['heap'] == 'match?'
61
- !! m
62
- else
63
- m ? m.to_a : []
73
+ case heap
74
+ when 'match?' then !! m
75
+ when 'pmatch' then (m && (m[1] || m[0])) || ''
76
+ else m ? m.to_a : []
64
77
  end
65
78
 
66
79
  wrap_reply
@@ -0,0 +1,51 @@
1
+
2
+ class Flor::Pro::Max < Flor::Procedure
3
+
4
+ names %w[ max min ]
5
+
6
+ def pre_execute
7
+
8
+ @node['atts'] = []
9
+ @node['ret'] ||= receive_payload_ret
10
+
11
+ unatt_unkeyed_children
12
+ end
13
+
14
+ def receive_payload_ret
15
+
16
+ case ret = payload['ret']
17
+ when Array then ret
18
+ when Hash then ret.values
19
+ else false
20
+ end
21
+ end
22
+
23
+ def receive_last
24
+
25
+ ret = @node['ret']
26
+
27
+ fail Flor::FlorError.new(
28
+ "found no argument that can #{@node['heap']}", self
29
+ ) unless ret
30
+
31
+ lax = att('lax', 'loose') == true
32
+ types = ret.collect { |e| Flor.type(e) }
33
+
34
+ ret = ret.collect { |x| JSON.dump(x) } if lax && types != [ 'number' ]
35
+
36
+ r =
37
+ begin
38
+ ret.send(@node['heap'])
39
+ rescue
40
+ fail unless lax
41
+ nil
42
+ end
43
+ res =
44
+ r ?
45
+ @node['ret'][ret.index { |e| e == r }] :
46
+ nil
47
+
48
+ wrap_reply('ret' => res)
49
+ end
50
+ end
51
+