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
@@ -17,6 +17,10 @@ class Flor::Pro::Reverse < Flor::Procedure
17
17
  # ```
18
18
  #
19
19
  # Will fail if it finds nothing reversable.
20
+ #
21
+ # # see also
22
+ #
23
+ # shuffle, sort, and sort_by
20
24
 
21
25
  name 'reverse'
22
26
 
@@ -10,6 +10,13 @@ class Flor::Pro::Sequence < Flor::Procedure
10
10
  # task 'charly'
11
11
  # ```
12
12
 
13
- names %w[ sequence _apply begin ]
13
+ names %w[ sequence begin ]
14
+
15
+ def cancel_when_closed
16
+
17
+ return cancel if node_status_flavour == 'on-error'
18
+
19
+ []
20
+ end
14
21
  end
15
22
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  class Flor::Pro::Set < Flor::Procedure
3
3
  #
4
- # sets a field or a variable.
4
+ # Sets a field or a variable.
5
5
  #
6
6
  # ```
7
7
  # sequence
@@ -67,12 +67,11 @@ class Flor::Pro::Set < Flor::Procedure
67
67
  def pre_execute
68
68
 
69
69
  unatt_unkeyed_children
70
+ reref_children
70
71
 
71
- nacn = non_att_children.dup
72
- sc = @node['single_child'] = nacn.size == 1
73
- nacn = non_att_children[0..-2] unless sc
72
+ @node['single_child'] = (non_att_children.count == 1)
74
73
 
75
- nacn.each_with_index { |_, i| stringify_child(i) }
74
+ rep_children
76
75
 
77
76
  @node['refs'] = []
78
77
  end
@@ -87,32 +86,92 @@ class Flor::Pro::Set < Flor::Procedure
87
86
 
88
87
  def receive_non_att
89
88
 
90
- ret = payload['ret']
91
- last = ! @node['single_child'] && (@fcid + 1) == children.size
89
+ ft = tree[1][@fcid] || []
92
90
 
93
- @node['refs'] << ret if ! last && ret.is_a?(String)
91
+ if ft[0] == '_rep' || (Flor.is_string_tree?(ft) && ! last_receive?)
92
+ @node['refs'] << payload['ret']
93
+ elsif ft[0] == '_ref' &&
94
+ ft[1].size == 2 &&
95
+ ft[1][0][0, 2] == [ '_sqs', 'f' ] && ft[1][1][0, 2] == [ '_sqs', 'ret' ]
96
+ then
97
+ payload['ret'] = node_payload_ret
98
+ end
94
99
 
95
100
  super
96
101
  end
97
102
 
98
103
  def receive_last
99
104
 
100
- ret = @node['single_child'] ? node_payload_ret : payload['ret']
105
+ ret =
106
+ if @node['single_child']
107
+ node_payload_ret
108
+ else
109
+ payload['ret']
110
+ end
111
+
112
+ refs = @node['refs']
101
113
 
102
- if @node['refs'].size == 1
103
- set_value(@node['refs'].first, ret)
104
- else
105
- Flor.splat(@node['refs'], ret).each { |k, v| set_value(k, v) }
114
+ case refs.size
115
+ when 0 then 0
116
+ when 1 then set_value(refs.first, ret)
117
+ else splat_value(refs, ret)
106
118
  end
107
119
 
108
120
  payload['ret'] =
109
- if tree[0] == 'setr' || @node['refs'].last == 'f.ret'
121
+ if tree[0] == 'setr' || refs_include_f_ret?
110
122
  ret
111
123
  else
112
124
  node_payload_ret
113
125
  end
114
126
 
115
- wrap_reply
127
+ wrap
128
+ end
129
+
130
+ protected
131
+
132
+ def refs_include_f_ret?
133
+
134
+ !! @node['refs']
135
+ .find { |ref|
136
+ ref.length == 2 &&
137
+ ref[1] == 'ret' &&
138
+ ref[0].match(/\Af(ld|ield)?\z/) }
139
+ end
140
+
141
+ def reref_children
142
+
143
+ t = tree
144
+
145
+ cn = t[1]
146
+ .collect { |ct|
147
+ hd, cn, ln = ct
148
+ if hd == '_dqs'
149
+ [ '_ref', [ ct ], ln ]
150
+ elsif Flor.is_single_ref_tree?(ct)
151
+ [ '_ref', [ [ '_sqs', hd, ln ] ], ln ]
152
+ else
153
+ ct
154
+ end }
155
+
156
+ @node['tree'] = [ t[0], cn, t[2] ] if cn != t[1]
157
+ end
158
+
159
+ def rep_children
160
+
161
+ t = tree
162
+ li = t[1].length - 1
163
+
164
+ cn = t[1]
165
+ .each_with_index
166
+ .collect { |ct, i|
167
+ hd, cn, ln = ct
168
+ if hd == '_ref' && (@node['single_child'] || li != i)
169
+ [ '_rep', cn, ln ]
170
+ else
171
+ ct
172
+ end }
173
+
174
+ @node['tree'] = [ t[0], cn, t[2] ] if cn != t[1]
116
175
  end
117
176
  end
118
177
 
@@ -0,0 +1,71 @@
1
+
2
+ class Flor::Pro::Shuffle < Flor::Procedure
3
+ #
4
+ # Returns a shuffled version of an array.
5
+ #
6
+ # ## shuffle
7
+ #
8
+ # ```
9
+ # shuffle [ 0 1 2 3 4 ]
10
+ # # might set [ 3 2 0 1 4 ] in f.ret
11
+ # shuffle [ 0 1 2 3 4 ] 2
12
+ # # might set [ 4 2 ] in f.ret
13
+ # shuffle [ 0 1 2 3 4 ] count: 2
14
+ # # might set [ 4 2 ] in f.ret
15
+ #
16
+ # [ 0 1 2 3 4 ]
17
+ # shuffle _
18
+ # # might set [ 4 0 2 1 3 ] in f.ret
19
+ # ```
20
+ #
21
+ # ## sample
22
+ #
23
+ # When given a count integer, "sample" behaves exactly like "shuffle".
24
+ # When not given a count, it returns a single, random, element of the given
25
+ # array.
26
+ #
27
+ # ```
28
+ # sample [ 'a' 'b' 'c' ]
29
+ # # might set 'b' in f.ret
30
+ #
31
+ # [ 'a' 'b' 'c' ]
32
+ # sample _
33
+ # # might set 'b' in f.ret
34
+ #
35
+ # sample [ 'a' 'b' 'c' ] 2
36
+ # # might set [ 'c', 'b' ] in f.ret
37
+ # ```
38
+ #
39
+ # ## see also
40
+ #
41
+ # slice, index, reverse, and length
42
+
43
+ names %w[ shuffle sample ]
44
+
45
+ def pre_execute
46
+
47
+ unatt_unkeyed_children
48
+
49
+ @node['atts'] = []
50
+ @node['rets'] = []
51
+ end
52
+
53
+ def receive_last
54
+
55
+ arr =
56
+ (@node['rets'] + [ node_payload_ret ])
57
+ .find { |r| r.is_a?(Array) }
58
+
59
+ fail Flor::FlorError.new("no array to #{heap}") unless arr
60
+
61
+ cnt =
62
+ att('count', nil) ||
63
+ @node['rets'].find { |r| r.is_a?(Integer) }
64
+
65
+ ret = arr.sample(cnt || arr.size)
66
+ ret = ret.first if cnt == nil && heap == 'sample'
67
+
68
+ wrap('ret' => ret)
69
+ end
70
+ end
71
+
@@ -0,0 +1,137 @@
1
+
2
+ class Flor::Pro::Slice < Flor::Procedure
3
+ #
4
+ # Takes an array or a string and returns a slice of it (a new
5
+ # array or a new string).
6
+ #
7
+ # "index" takes an array or a string and returns the element (character)
8
+ # at the given index.
9
+ #
10
+ # ## slice
11
+ #
12
+ # ```
13
+ # set a [ 'alpha' 'bravo' 'charly' ]
14
+ #
15
+ # slice a 1 -1 # sets [ 'bravo', 'charly' ] into the field 'ret'
16
+ # slice a from: 1 to: -1 # same as above
17
+ #
18
+ # a
19
+ # slice 1 -1 # sets [ 'bravo', 'charly' ] into the field 'ret'
20
+ # slice 1 -1 # sets [ 'charly' ] into the field 'ret'
21
+ # ```
22
+ #
23
+ # It slices the content of `f.ret` by default:
24
+ # ```
25
+ # set a [ 0 1 2 3 ]
26
+ # # ...
27
+ # a # (copy content of a into f.ret)
28
+ # slice 1 count: 2 # sets [ 1, 2 ] into the field 'ret'
29
+ # ```
30
+ #
31
+ # ## index
32
+ #
33
+ # ```
34
+ # set a [ 'alpha' 'bravo' 'charly' ]
35
+ #
36
+ # index a (-2) # sets 'bravo' into the field 'ret'
37
+ # index a at: -2 # sets 'bravo' into the field 'ret'
38
+ # ```
39
+ #
40
+ # It indexes the content of `f.ret` by default:
41
+ # ```
42
+ # set a [ 0 1 2 3 4 ]
43
+ # # ...
44
+ # a # (copy content of a into f.ret)
45
+ # index (-2) # sets 3 into the field 'ret'
46
+ # ```
47
+ #
48
+ # ## see also
49
+ #
50
+ # length
51
+
52
+ names 'slice', 'index'
53
+
54
+ # three cases: [ start, count ], [ start, end ], and [ start, end, step ]
55
+
56
+ def pre_execute
57
+
58
+ unatt_unkeyed_children
59
+
60
+ @node['atts'] = []
61
+ @node['rets'] = []
62
+ end
63
+
64
+ def receive_last
65
+
66
+ send(heap)
67
+ end
68
+
69
+ protected
70
+
71
+ def collection
72
+
73
+ coll =
74
+ @node['rets'].find { |e| e.respond_to?(:slice) } ||
75
+ node_payload_ret
76
+
77
+ fail Flor::FlorError.new(
78
+ "cannot slice instance of #{coll.class}", self
79
+ ) unless coll.respond_to?(:slice)
80
+
81
+ coll
82
+ end
83
+
84
+ def slice
85
+
86
+ coll = collection
87
+
88
+ ints = @node['rets'].select { |e| e.is_a?(Integer) }
89
+
90
+ st = att('from', 'start') || ints.shift || 0
91
+ en = att('to', 'end') || ints.shift
92
+ co = att('count')
93
+ sp = att('step') || 1
94
+
95
+ en ||= (st + co - 1)
96
+ en = coll.length + en if en < 0
97
+
98
+ ret =
99
+ case coll
100
+ when String
101
+ do_slice(coll.chars, st, en, sp, true)
102
+ when Array
103
+ do_slice(coll, st, en, sp)
104
+ else
105
+ fail Flor::FlorError.new("cannot slice instance of #{coll.class}", self)
106
+ end
107
+
108
+ ret ||= ''
109
+
110
+ wrap('ret' => ret)
111
+ end
112
+
113
+ def do_slice(coll, st, en, sp, join=false)
114
+
115
+ l = coll.length
116
+
117
+ return nil if st >= l
118
+
119
+ r = []
120
+
121
+ while st <= en && st < l
122
+ r << coll[st]
123
+ st = st + sp
124
+ end
125
+
126
+ join ? r.join : r
127
+ end
128
+
129
+ def index
130
+
131
+ coll = collection
132
+ index = att('at') || @node['rets'].find { |e| e.is_a?(Integer) }
133
+
134
+ wrap('ret' => coll[index] || '')
135
+ end
136
+ end
137
+
@@ -0,0 +1,244 @@
1
+
2
+ class Flor::Pro::Sort < Flor::Procedure
3
+ #
4
+ # Sorts an array or an object.
5
+ #
6
+ # "sort" takes an array or an object and sorts its content.
7
+ #
8
+ # ```
9
+ # sort [ 0 7 1 5 3 4 2 6 ]
10
+ # # => [ 0 1 2 3 4 5 6 7 ]
11
+ # ```
12
+ #
13
+ # Without a function, "sort" uses the underlying (Ruby) sort methods.
14
+ #
15
+ # One can use a function to sort in specific ways:
16
+ # ```
17
+ # [ { name: 'Alice', age: 33, function: 'ceo' }
18
+ # { name: 'Bob', age: 44, function: 'cfo' }
19
+ # { name: 'Charly', age: 27, function: 'cto' } ]
20
+ # sort (def a b \ - a.age b.age)
21
+ # ```
22
+ #
23
+ # The function should return a boolean or a number. `true` or a negative
24
+ # number indicates `a` comes before `b`, anything else indicates `a`
25
+ # comes after `b`.
26
+ #
27
+ # ## behind the scenes
28
+ #
29
+ # Sorting an array results in a sorted array stored in `f.ret`, sorting
30
+ # an object results in a sorted (entries) object stored in `f.ret`.
31
+ #
32
+ # Using a function to sort is quite slow. Behind the scene a quicksort is
33
+ # used, to lower the number of calls to the sort function, but since
34
+ # the function is a flor function, calls are quite costly.
35
+ # By default, "sort" will cache the call results. For example, upon
36
+ # comparing 1 with 7, the results will be cached (the 7 vs 1 will be cached
37
+ # as well).
38
+ #
39
+ # It's OK to disable this caching:
40
+ # ```
41
+ # sort memo: false a (def a b \ < a b)
42
+ # ```
43
+ # (but why should we need that?)
44
+ #
45
+ # ## see also
46
+ #
47
+ # sort_by, reverse, and shuffle
48
+
49
+ name 'sort'
50
+
51
+ def pre_execute
52
+
53
+ @node['atts'] = []
54
+
55
+ @node['col'] = nil # collection
56
+ @node['fun'] = nil # function
57
+
58
+ unatt_unkeyed_children
59
+ end
60
+
61
+ def receive_non_att
62
+
63
+ if @node['ranges']
64
+
65
+ quick_partition_receive
66
+
67
+ else
68
+
69
+ r = payload['ret']
70
+
71
+ if Flor.is_func_tree?(r)
72
+ @node['fun'] ||= r
73
+ elsif Flor.is_collection?(r)
74
+ @node['col'] ||= r
75
+ end
76
+
77
+ super
78
+ end
79
+ end
80
+
81
+ def receive_last
82
+
83
+ @node['col'] ||= node_payload_ret
84
+
85
+ if @node['col'].empty?
86
+ wrap('ret' => @node['col'])
87
+ elsif @node['fun']
88
+ quick_sort
89
+ else
90
+ default_sort
91
+ end
92
+ end
93
+
94
+ protected
95
+
96
+ def receive_argument
97
+
98
+ @node['args'] << payload['ret']
99
+
100
+ if children[@ncid]
101
+ execute_child(@ncid)
102
+ else
103
+ iterate
104
+ end
105
+ end
106
+
107
+ #
108
+ # default_sort
109
+ #
110
+ # When no function is given, turns to a collection of string
111
+ # (or JSON representations) and sorts
112
+
113
+ def default_sort
114
+
115
+ col =
116
+ @node['col']
117
+ classes =
118
+ col.collect(&:class).uniq
119
+ f =
120
+ (classes.count > 1 || [ Hash ].include?(classes[0])) ?
121
+ lambda { |e| e.is_a?(String) ? e : JSON.dump(e) } :
122
+ lambda { |e| e }
123
+
124
+ ret = col.sort_by(&f)
125
+ ret = col.inject({}) { |h, (k, v)| h[k] = v; h } if col.is_a?(Hash)
126
+
127
+ wrap('ret' => ret)
128
+ end
129
+
130
+ #
131
+ # quick_sort
132
+ #
133
+ # A quicksort drives the game
134
+
135
+ def quick_sort
136
+
137
+ col = @node['col']
138
+ @node['colk'] = col.is_a?(Hash) ? 'object' : 'array'
139
+ @node['col'] = col.to_a
140
+
141
+ @node['ranges'] = {}
142
+
143
+ @node['memo'] =
144
+ att('memo', 'cache') == false ?
145
+ nil :
146
+ {}
147
+
148
+ quick_partition_execute(0, col.length - 1)
149
+ end
150
+
151
+ def quick_swap(a, b)
152
+
153
+ return if a == b
154
+
155
+ col = @node['col']
156
+ col[a], col[b] = col[b], col[a]
157
+ end
158
+
159
+ def quick_kab(va, vb)
160
+
161
+ return [] unless @node['memo']
162
+
163
+ kab = [ va, vb ]
164
+ .collect { |e|
165
+ case e
166
+ when Array, Hash, String then Digest::SHA256.hexdigest(JSON.dump(e))
167
+ else JSON.dump(e)
168
+ end }
169
+
170
+ [ kab.join('__'), kab.reverse.join('__') ]
171
+ end
172
+
173
+ def quick_compare(ra, a, b)
174
+
175
+ col = @node['col']
176
+ va, vb = col[a], col[b]
177
+
178
+ ra['kab'], ra['kba'] = quick_kab(va, vb)
179
+ kab = ra['kab']
180
+
181
+ if kab && @node['memo'].has_key?(kab)
182
+ quick_partition_receive(ra['sub'], @node['memo'][kab])
183
+ else
184
+ apply(@node['fun'], [ [ 'a', va ], [ 'b', vb ] ], tree[2])
185
+ .tap { |ms| ra['sub'] = Flor.sub_nid(ms.first['nid']) }
186
+ end
187
+ end
188
+
189
+ def quick_partition_execute(lo, hi)
190
+
191
+ return [] if lo >= hi
192
+
193
+ ra = @node['ranges']["#{lo}_#{hi}"] ||= { 'i' => lo, 'j' => lo }
194
+
195
+ quick_compare(ra, ra['j'], hi)
196
+ # compare element at j with pivot (element at hi)
197
+ end
198
+
199
+ def quick_partition_receive(sn=from_sub_nid, r=:none)
200
+
201
+ rk, ra = @node['ranges'].find { |_, v| v['sub'] == sn }
202
+ lo, hi = rk.split('_').collect(&:to_i)
203
+ i, j = ra['i'], ra['j']
204
+
205
+ if r == :none
206
+ ret = payload_ret
207
+ r = ret == true || (ret.is_a?(Numeric) && ret < 0)
208
+ if m = @node['memo']
209
+ m[ra['kab']], m[ra['kba']] = r, ! r
210
+ end
211
+ end
212
+
213
+ if r
214
+ quick_swap(i, j)
215
+ ra['i'] = i = (i + 1)
216
+ end
217
+
218
+ ra['j'] = j = (j + 1)
219
+
220
+ return quick_partition_execute(lo, hi) if j < hi # loop on
221
+
222
+ # partition loop is over...
223
+
224
+ quick_swap(i, hi)
225
+
226
+ @node['ranges'].delete(rk)
227
+
228
+ # partition at i...
229
+
230
+ ms =
231
+ quick_partition_execute(lo, i - 1) +
232
+ quick_partition_execute(i + 1, hi)
233
+
234
+ if ms.any?
235
+ ms
236
+ elsif @node['ranges'].any?
237
+ []
238
+ else # quicksort is over
239
+ col = @node['col']
240
+ wrap('ret' => (@node['colk'] === 'object' ? Hash[col] : col))
241
+ end
242
+ end
243
+ end
244
+