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
@@ -0,0 +1,108 @@
1
+
2
+ class Flor::Pro::UnderscoreApply < Flor::Procedure
3
+
4
+ name '_apply'
5
+
6
+ def execute
7
+
8
+ #if oe = message['on_error']
9
+ # @node['in_on_error'] = oe
10
+ #end
11
+ #
12
+ # which is equivalent, for now, to
13
+ #
14
+ if message['on_error']
15
+ #@node['in_on_error'] = true
16
+ @node['in_on_error'] = from
17
+ end
18
+
19
+ vars = @node['vars'] = {}
20
+ args = message['arguments']
21
+
22
+ vars['arguments'] = args
23
+
24
+ tr = tree
25
+ retree = nil
26
+
27
+ atts = tr[1].inject([]) { |a, t| a << t[1] if t[0] == '_att'; a }
28
+ args = args.dup
29
+ #puts "\n---"
30
+ #puts "== atts (sig):"; pp atts; # signature
31
+ #puts "== args (given):"; pp args # passed arguments
32
+ #puts
33
+
34
+ # first, make 2 passes on atts
35
+ # 1). grab named args
36
+ # 2). grab remaining args
37
+ # then make 1 pass on still remaining args
38
+ # 1). set vars if not yet set
39
+
40
+ seen = []
41
+
42
+ atts
43
+ .each { |(att_key, _), _|
44
+ arg_i = args.index { |arg_key, arg_val| arg_key == att_key }
45
+ next unless arg_i
46
+ arg_key, arg_val = args.delete_at(arg_i)
47
+ seen << arg_key
48
+ vars[att_key] = arg_val }
49
+ #puts "== 0 vars:"; pp vars
50
+ atts
51
+ .each_with_index { |((att_key, _), att_val), att_i|
52
+ next if vars.has_key?(att_key)
53
+ seen << att_key
54
+ if att_i < args.length
55
+ arg_key, arg_val = args[att_i]
56
+ seen << arg_key
57
+ vars[att_key] = arg_val
58
+ elsif att_val
59
+ l = tree[2]
60
+ retree ||= Flor.dup(tr)
61
+ retree[1][att_i] = [ 'set', [ [ att_key, [], l ], att_val ], l ]
62
+ else
63
+ vars[att_key] = nil
64
+ end }
65
+ #puts "== seen:"; p seen
66
+ args
67
+ .each { |arg_key, arg_val|
68
+ vars[arg_key] = arg_val unless seen.include?(arg_key) }
69
+
70
+ #puts "\n== 1 vars: "; pp vars
71
+ #print "vars: "; pp vars.collect { |k, v| [ k, JSON.dump(v)[0, 20] + "..." ] }
72
+ #print "vars: "; vars.each { |k, v| print "#{k.inspect} --> "; pp v }
73
+
74
+ @node['tree'] = retree if retree
75
+ #puts "== retree:"; pp retree
76
+
77
+ super
78
+ end
79
+
80
+ def execute_child(index=0, sub=nil, h=nil)
81
+
82
+ t0 = tree[1][index] && tree[1][index][0]
83
+
84
+ if t0 && %w[ _att _name ].include?(t0) # skip those
85
+ execute_child(index + 1)
86
+ else
87
+ super
88
+ end
89
+ end
90
+
91
+ #def cancel_when_closed
92
+ # return cancel if node_status_flavour == 'on-error'
93
+ # []
94
+ #end
95
+ #
96
+ # as it was when "_apply" was an alias to "sequence"
97
+
98
+ def wrap_reply(h={})
99
+
100
+ ms = super
101
+
102
+ ioe = @node['in_on_error']
103
+ ms[0]['from_on_error'] = ioe if ioe
104
+
105
+ ms
106
+ end
107
+ end
108
+
@@ -1,15 +1,13 @@
1
1
 
2
2
  class Flor::Pro::Atom < Flor::Procedure
3
3
 
4
- names %w[ _num _boo _sqs _dqs _rxs _nul _func ]
4
+ names %w[ _num _boo _sqs _nul _func ]
5
5
 
6
6
  def execute
7
7
 
8
8
  payload['ret'] =
9
- case @node['heat0']
9
+ case heap
10
10
  when '_nul' then nil
11
- when '_dqs' then expand(tree[1])
12
- when '_rxs' then [ tree[0], expand(tree[1]), *tree[2..-1] ]
13
11
  when '_func' then tree
14
12
  else tree[1]
15
13
  end
@@ -31,6 +31,8 @@ class Flor::Pro::Att < Flor::Procedure
31
31
  #
32
32
  # execute phase
33
33
 
34
+ # For example, turns `sequence flank` into `sequence flank: true`
35
+ #
34
36
  def pre_execute_boolean_attribute
35
37
 
36
38
  return unless children.size == 1
@@ -39,7 +41,10 @@ class Flor::Pro::Att < Flor::Procedure
39
41
  t[1] << [ '_boo', true, @node['tree'][2] ]
40
42
  end
41
43
 
42
- alias pre_execute_flank pre_execute_boolean_attribute
44
+ TRUE_ATTS
45
+ .each do |k|
46
+ alias_method "pre_execute_#{k}", :pre_execute_boolean_attribute
47
+ end
43
48
 
44
49
  def pre_execute_vars
45
50
 
@@ -49,6 +54,8 @@ class Flor::Pro::Att < Flor::Procedure
49
54
 
50
55
  return if t[1][1][1] == 0 # [ '_obj', 0, 123 ]
51
56
 
57
+ # add `quote: 'keys'` to the _obj so that they may be `k0:` or `'k0':`
58
+
52
59
  t = @node['tree'] = Flor.dup(t)
53
60
 
54
61
  t[1][1][1].unshift([
@@ -79,16 +86,13 @@ class Flor::Pro::Att < Flor::Procedure
79
86
 
80
87
  def unref(k, flavour=:key)
81
88
 
82
- #return lookup_var_name(@node, k) if Flor.is_func_tree?(k)
83
- # old style
84
-
85
89
  return k unless Flor.is_tree?(k)
86
90
  return k unless k[1].is_a?(Hash)
87
- return k unless %w[ _proc _task _func ].include?(k[0])
91
+ return k unless %w[ _proc _tasker _func ].include?(k[0])
88
92
 
89
93
  (flavour == :key ? nil : k[1]['oref']) ||
90
94
  k[1]['ref'] ||
91
- k[1]['proc'] || k[1]['task']
95
+ k[1]['proc'] || k[1]['tasker']
92
96
  end
93
97
 
94
98
  def receive_att(key)
@@ -112,27 +116,32 @@ class Flor::Pro::Att < Flor::Procedure
112
116
  #
113
117
  def receive_vars
114
118
 
115
- vars =
116
- case (vs = payload['ret'])
117
- when 'copy', '*' then copy_vars
118
- when Array then wlist_vars(vs)
119
- else vs
120
- end
121
-
122
- (parent_node['vars'] ||= {}).merge!(vars)
119
+ vs = payload['ret']
123
120
 
124
- payload['ret'] = @node['ret']
121
+ if vs.is_a?(Array)
122
+ key, list = vlist(vs) # 'vwlist' var white iist, 'vblist' black list
123
+ parent_node[key] = list
124
+ else
125
+ (parent_node['vars'] ||= {}).merge!(vdict(vs))
126
+ end
125
127
 
126
- wrap_reply
128
+ wrap('ret' => @node['ret'])
127
129
  end
128
130
 
129
- def copy_vars
131
+ def vdict(vs)
130
132
 
131
- @executor.vars(nid)
132
- # Returns a hash of all the vars known at point `nid` of the execution
133
+ case vs
134
+ when Hash
135
+ vs
136
+ when 'copy', '*'
137
+ @executor.vars(nid) # all the vars known at that point
138
+ else
139
+ fail Flor::FlorError.new(
140
+ "vars: doesn't know how to deal with #{vs.inspect}", self)
141
+ end
133
142
  end
134
143
 
135
- def wlist_vars(vs)
144
+ def vlist(vs)
136
145
 
137
146
  mode =
138
147
  case vs.first
@@ -142,24 +151,20 @@ class Flor::Pro::Att < Flor::Procedure
142
151
  end
143
152
  vs.shift if mode
144
153
 
145
- vs = vs.collect { |v| Flor.is_regex_tree?(v) ? Flor.to_regex(v) : v }
146
- vars = copy_vars
154
+ vs = vs
155
+ .collect { |v|
156
+ if Flor.is_regex_tree?(v)
157
+ Flor.to_regex(v)
158
+ else
159
+ fail Flor::FlorError.new(
160
+ "vars: is limited to 1st level, #{v.inspect} doesn't comply", self
161
+ ) if v.index('.')
162
+ v
163
+ end }
147
164
 
148
- if mode == '-'
149
- Hash[vars.map { |k, v| [ k, var_match?(vs, k) ? nil : v ] }]
150
- else
151
- Hash[vars.map { |k, v| [ k, var_match?(vs, k) ? v : nil ] }]
152
- end
153
- end
154
-
155
- def var_match?(vs, key)
156
-
157
- vs.each do |v|
158
- return true if v == key
159
- return true if v.is_a?(Regexp) && v =~ key
160
- end
165
+ mode = (mode || '+') == '+' ? 'vwlist' : 'vblist'
161
166
 
162
- false
167
+ [ mode, vs ]
163
168
  end
164
169
 
165
170
  def parent_is_trap?
@@ -217,8 +222,20 @@ class Flor::Pro::Att < Flor::Procedure
217
222
  return wrap_reply unless Flor.true?(payload['ret'])
218
223
  return wrap_reply unless parent_node
219
224
 
220
- Flor::Procedure.make(@executor, parent_node, @message).flank +
225
+ parent_node_procedure.flank +
221
226
  wrap_reply
222
227
  end
228
+
229
+ # Might turn the "disable" flag to true, which forces the parent node
230
+ # (the node bearing the att under evaluation right now) to terminate
231
+ # immediately (by replying to its own parent node).
232
+ #
233
+ def receive_disabled
234
+
235
+ wrap_reply('disable' => Flor.true?(payload['ret']))
236
+ end
237
+
238
+ alias receive_off receive_disabled
239
+ alias receive_disable receive_disabled
223
240
  end
224
241
 
@@ -0,0 +1,18 @@
1
+
2
+ class Flor::Pro::Dmute < Flor::Procedure
3
+
4
+ name '_dmute'
5
+
6
+ def pre_execute
7
+
8
+ @node['on_error'] = [
9
+ [ [ '*' ],
10
+ { 'point' => 'receive',
11
+ 'nid' => nid,
12
+ 'from' => Flor.child_nid(nid, 999 + tree[1].size),
13
+ # "#{nid}_#{999 + child.count}"
14
+ 'exid' => exid,
15
+ 'payload' => @message['payload'].merge('ret' => '') } ] ]
16
+ end
17
+ end
18
+
@@ -0,0 +1,17 @@
1
+
2
+ class Flor::Pro::Dol < Flor::Procedure
3
+
4
+ name '_dol'
5
+
6
+ def receive
7
+
8
+ return super unless @message['point'] == 'receive'
9
+
10
+ ret = payload['ret']
11
+
12
+ return super if (ret.is_a?(String) && ret.length == 0) || ret == false
13
+
14
+ wrap
15
+ end
16
+ end
17
+
@@ -0,0 +1,35 @@
1
+
2
+ class Flor::Pro::DoubleQuoteString < Flor::Procedure
3
+
4
+ name '_dqs'
5
+
6
+ def pre_execute
7
+
8
+ @node['rets'] = []
9
+ end
10
+
11
+ def execute_child(index=0, sub=nil, h=nil)
12
+
13
+ payload['ret'] = node_payload_ret
14
+ # always pass the noe_payload_ret to children
15
+
16
+ super
17
+ end
18
+
19
+ def receive_last
20
+
21
+ wrap('ret' => @node['rets'].collect { |e| to_string(e) }.join)
22
+ end
23
+
24
+ protected
25
+
26
+ def to_string(result)
27
+
28
+ case result
29
+ when String then result
30
+ when nil then ''
31
+ else JSON.dump(result)
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,25 @@
1
+
2
+ class Flor::Pro::Head < Flor::Procedure
3
+
4
+ name '_head'
5
+
6
+ def receive
7
+
8
+ return execute_child(1) \
9
+ if @message['point'] == 'execute'
10
+ #
11
+ # notice how it skips the first _sqs child
12
+
13
+ h = [ tree[1][0][1], payload['ret'] ]
14
+ h[1] = node_payload_ret if h[0].match(/\Af(ld|ield)?\.ret\z/)
15
+
16
+ fail Flor::FlorError.new("don't know how to apply #{h[0].inspect}") \
17
+ if h[1] == nil
18
+
19
+ return execute_child(2, nil, '__head' => h) \
20
+ if @message['from'].match(/_1\z/)
21
+
22
+ super
23
+ end
24
+ end
25
+
@@ -25,7 +25,6 @@ class Flor::Pro::Obj < Flor::Pro::Coll
25
25
  def pre_execute
26
26
 
27
27
  @node['rets'] = []
28
- @node['atts'] = []
29
28
  end
30
29
 
31
30
  def execute_child(index=0, sub=nil, h=nil)
@@ -33,9 +32,8 @@ class Flor::Pro::Obj < Flor::Pro::Coll
33
32
  return super if @node['rets'].size.odd?
34
33
 
35
34
  ct = children[index]
36
- q = (att('quote') == 'keys')
37
35
 
38
- return super unless ct[1] == [] && (deref(ct[0]) == nil || q)
36
+ return super unless ct[1] == []
39
37
 
40
38
  t = tree
41
39
  t[1][index] = [ '_sqs', ct[0], *ct[2..-1] ]
@@ -67,7 +67,7 @@ class Flor::Pro::PatGuard < Flor::Pro::PatContainer
67
67
 
68
68
  def execute_child(index=0, sub=nil, h=nil)
69
69
 
70
- if (key = @node['key']) && child_type(index) == nil
70
+ if @node['key'] && child_type(index) == nil
71
71
  h ||= {}
72
72
  (h['vars'] ||= {}).merge!(@node['binding'])
73
73
  end
@@ -26,6 +26,15 @@ class Flor::Pro::PatObj < Flor::Pro::PatContainer
26
26
  @node['tree'] = [ t[0], t[1], *t[1][2..-1] ]
27
27
  end
28
28
 
29
+ t = tree
30
+ changed = false
31
+ t[1].each_with_index do |ct, j|
32
+ next if j.odd? || ct[0] != '_ref'
33
+ ct[0] = '_rep'
34
+ changed = true
35
+ end
36
+ @node['tree'] = t if changed
37
+
29
38
  super
30
39
  end
31
40
 
@@ -52,8 +61,7 @@ class Flor::Pro::PatObj < Flor::Pro::PatContainer
52
61
  ret = payload['ret']
53
62
 
54
63
  unless key
55
- ret = ret.to_s
56
- return wrap_no_match_reply unless Dense.has_key?(val, ret)
64
+ return wrap_no_match_reply unless Dense.has_key?(val, Array(ret))
57
65
  @node['key'] = ret
58
66
  @node['keys'] << ret if @node['keys']
59
67
  return super
@@ -132,7 +140,7 @@ class Flor::Pro::PatObj < Flor::Pro::PatContainer
132
140
  def lookup_and_quote_key(t)
133
141
 
134
142
  return t unless t[1] == []
135
- [ '_sqs', lookup(t[0], true) || t[0], t[2] ]
143
+ [ '_sqs', (lookup_value(t[0]) rescue t[0]), t[2] ]
136
144
  end
137
145
 
138
146
  def sub_val(child_index)
@@ -6,11 +6,25 @@ class Flor::Pro::PatRegex < Flor::Pro::PatContainer
6
6
 
7
7
  name '_pat_regex'
8
8
 
9
- def execute
9
+ def pre_execute
10
+
11
+ @node['rets'] = []
12
+ @node['atts'] = []
13
+ end
14
+
15
+ def execute_child(index=0, sub=nil, h=nil)
16
+
17
+ payload['ret'] = node_payload_ret
18
+ # always pass the noe_payload_ret to children
19
+
20
+ super
21
+ end
22
+
23
+ def receive_last
10
24
 
11
25
  return wrap_no_match_reply unless val.is_a?(String)
12
26
 
13
- rex = Flor.to_regex(tree[1])
27
+ rex = Flor.to_regex(@node['rets'] + [ att('rxopts') ])
14
28
  m = rex.match(val)
15
29
 
16
30
  return wrap_no_match_reply unless m