flor 0.16.1 → 0.16.2

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/CREDITS.md +1 -0
  4. data/Makefile +1 -1
  5. data/README.md +82 -6
  6. data/lib/flor.rb +1 -1
  7. data/lib/flor/conf.rb +19 -6
  8. data/lib/flor/core/executor.rb +45 -16
  9. data/lib/flor/core/node.rb +4 -4
  10. data/lib/flor/core/procedure.rb +40 -0
  11. data/lib/flor/djan.rb +5 -2
  12. data/lib/flor/flor.rb +92 -7
  13. data/lib/flor/id.rb +19 -0
  14. data/lib/flor/migrations/0001_tables.rb +6 -6
  15. data/lib/flor/migrations/0005_pointer_content.rb +20 -0
  16. data/lib/flor/pcore/_apply.rb +103 -57
  17. data/lib/flor/pcore/_att.rb +15 -1
  18. data/lib/flor/pcore/_ref.rb +2 -1
  19. data/lib/flor/pcore/arith.rb +46 -9
  20. data/lib/flor/pcore/break.rb +1 -1
  21. data/lib/flor/pcore/case.rb +41 -0
  22. data/lib/flor/pcore/collect.rb +1 -1
  23. data/lib/flor/pcore/cursor.rb +1 -1
  24. data/lib/flor/pcore/define.rb +32 -6
  25. data/lib/flor/pcore/iterator.rb +12 -0
  26. data/lib/flor/pcore/on_cancel.rb +1 -1
  27. data/lib/flor/pcore/set.rb +14 -4
  28. data/lib/flor/punit/{ccollect.rb → c_collect.rb} +2 -2
  29. data/lib/flor/punit/c_each.rb +11 -0
  30. data/lib/flor/punit/c_for_each.rb +41 -0
  31. data/lib/flor/punit/c_iterator.rb +160 -0
  32. data/lib/flor/punit/c_map.rb +43 -0
  33. data/lib/flor/punit/concurrence.rb +43 -200
  34. data/lib/flor/punit/graft.rb +3 -2
  35. data/lib/flor/punit/m_ram.rb +281 -0
  36. data/lib/flor/unit.rb +1 -0
  37. data/lib/flor/unit/caller.rb +6 -1
  38. data/lib/flor/unit/executor.rb +17 -4
  39. data/lib/flor/unit/ganger.rb +12 -1
  40. data/lib/flor/unit/hloader.rb +251 -0
  41. data/lib/flor/unit/hook.rb +74 -15
  42. data/lib/flor/unit/hooker.rb +9 -12
  43. data/lib/flor/unit/loader.rb +41 -17
  44. data/lib/flor/unit/models.rb +54 -18
  45. data/lib/flor/unit/models/execution.rb +15 -4
  46. data/lib/flor/unit/models/pointer.rb +11 -0
  47. data/lib/flor/unit/scheduler.rb +126 -30
  48. data/lib/flor/unit/spooler.rb +5 -3
  49. data/lib/flor/unit/storage.rb +40 -13
  50. data/lib/flor/unit/waiter.rb +165 -26
  51. data/lib/flor/unit/wlist.rb +98 -5
  52. metadata +10 -4
  53. data/lib/flor/punit/cmap.rb +0 -112
@@ -76,6 +76,7 @@ module Flor
76
76
 
77
77
  "#{nid}_#{i}#{subnid ? "-#{subnid}" : ''}"
78
78
  end
79
+ alias make_child_nid child_nid
79
80
 
80
81
  def parent_id(nid)
81
82
 
@@ -100,6 +101,24 @@ module Flor
100
101
  !! (s.is_a?(String) && s.match(/\A[0-9]+(?:_[0-9]+)*(?:-[0-9]+)?\z/))
101
102
  end
102
103
 
104
+ def split_exid(s)
105
+
106
+ return nil unless s.is_a?(String)
107
+
108
+ _, d, u, t = s
109
+ .match(/\A([^-\s]+)-([^-\s]+)-(\d{8,9}\.\d{4}\.[a-z]+)\z/)
110
+ .to_a
111
+
112
+ return nil unless d && u && t
113
+
114
+ [ d, u, t ]
115
+ end
116
+
117
+ def is_exid?(s)
118
+
119
+ !! split_exid(s)
120
+ end
121
+
103
122
  # Returns [ exid, nid ]
104
123
  #
105
124
  def extract_exid_and_nid(s)
@@ -5,7 +5,7 @@ Sequel.migration do
5
5
 
6
6
  create_table :flor_messages do
7
7
 
8
- primary_key :id, type: :Integer
8
+ primary_key :id
9
9
  String :domain, null: false
10
10
  String :exid, null: false
11
11
  String :point, null: false # 'execute', 'task', 'receive', 'schedule', ...
@@ -19,7 +19,7 @@ Sequel.migration do
19
19
 
20
20
  create_table :flor_executions do
21
21
 
22
- primary_key :id, type: :Integer
22
+ primary_key :id
23
23
  String :domain, null: false
24
24
  String :exid, null: false
25
25
  File :content # JSON
@@ -32,7 +32,7 @@ Sequel.migration do
32
32
 
33
33
  create_table :flor_timers do
34
34
 
35
- primary_key :id, type: :Integer
35
+ primary_key :id
36
36
  String :domain, null: false
37
37
  String :exid, null: false
38
38
  String :nid, null: false
@@ -51,7 +51,7 @@ Sequel.migration do
51
51
 
52
52
  create_table :flor_traps do
53
53
 
54
- primary_key :id, type: :Integer
54
+ primary_key :id
55
55
  String :domain, null: false
56
56
  String :exid, null: false
57
57
  String :onid, null: false
@@ -76,7 +76,7 @@ Sequel.migration do
76
76
 
77
77
  create_table :flor_pointers do
78
78
 
79
- primary_key :id, type: :Integer
79
+ primary_key :id
80
80
  String :domain, null: false
81
81
  String :exid, null: false
82
82
  String :nid, null: false
@@ -97,7 +97,7 @@ Sequel.migration do
97
97
 
98
98
  create_table :flor_traces do
99
99
 
100
- primary_key :id, type: :Integer
100
+ primary_key :id
101
101
  String :domain, null: false
102
102
  String :exid, null: false
103
103
  String :nid, null: true
@@ -0,0 +1,20 @@
1
+
2
+ Sequel.migration do
3
+
4
+ up do
5
+
6
+ alter_table :flor_pointers do
7
+
8
+ add_column :content, File
9
+ end
10
+ end
11
+
12
+ down do
13
+
14
+ alter_table :flor_pointers do
15
+
16
+ drop_column :content
17
+ end
18
+ end
19
+ end
20
+
@@ -16,63 +16,7 @@ class Flor::Pro::UnderscoreApply < Flor::Procedure
16
16
  @node['in_on_error'] = from
17
17
  end
18
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
19
+ map_arguments_to_parameters
76
20
 
77
21
  super
78
22
  end
@@ -104,5 +48,107 @@ class Flor::Pro::UnderscoreApply < Flor::Procedure
104
48
 
105
49
  ms
106
50
  end
51
+
52
+ protected
53
+
54
+ def compute_param_key(t)
55
+
56
+ t0 = t[0]
57
+ k = t0[0]
58
+
59
+ if k == '_ref' && t0[1].is_a?(Array) && t0[1].length > 0
60
+ t[0][1].collect { |tt| tt[1].to_s }.join('.')
61
+ else
62
+ k
63
+ end
64
+ end
65
+
66
+ def map_arguments_to_parameters
67
+
68
+ @node['vars'] = {}
69
+
70
+ args = message['arguments']
71
+
72
+ @node['vars']['arguments'] = args
73
+
74
+ tr = tree
75
+ retree = nil
76
+
77
+ params = tr[1]
78
+ .select { |t| t[0] == '_att' }
79
+ .inject([]) { |a, t|
80
+ t1 = t[1]
81
+ a << [ compute_param_key(t1), t[1][0], t[1][1] ]
82
+ a }
83
+ args = args.dup
84
+ #puts "\n---"
85
+ #puts "== params:"
86
+ #params.each_with_index { |a, i| printf "%2d: %s\n", i, a.inspect }
87
+ #puts "== args:"
88
+ #args.each_with_index { |a, i| printf "%2d: %s\n", i, a.inspect }
89
+ #puts
90
+
91
+ # first, make 2 passes on params
92
+ # 1). grab named args
93
+ # 2). grab remaining args
94
+ # then make 1 pass on still remaining args
95
+ # 1). set vars if not yet set
96
+
97
+ seen = []
98
+
99
+ params.each do |param_key, param_tree|
100
+ next if param_tree[0] == '_ref'
101
+ arg_i = args.index { |arg_key, arg_val| arg_key == param_key }
102
+ next unless arg_i
103
+ arg_key, arg_val = args.delete_at(arg_i)
104
+ seen << arg_key
105
+ set_param(param_key, arg_val)
106
+ end
107
+ #puts "== 0 vars:"; pp @node['vars']
108
+ params.each_with_index do |(param_key, param_tree, param_val), param_i|
109
+ ref = param_tree[0] == '_ref'
110
+ next if ! ref && @node['vars'].has_key?(param_key)
111
+ seen << param_key
112
+ if param_i < args.length
113
+ arg_key, arg_val = args[param_i]
114
+ seen << arg_key
115
+ set_param(param_key, arg_val)
116
+ elsif param_val
117
+ l = tree[2]
118
+ retree ||= Flor.dup(tr)
119
+ retree[1][param_i] = [ 'set', [ [ param_key, [], l ], param_val ], l ]
120
+ else
121
+ set_param(param_key, nil) unless ref
122
+ end
123
+ end
124
+ #puts "== seen:"; p seen
125
+ args.each do |arg_key, arg_val|
126
+ set_param(arg_key, arg_val) unless seen.include?(arg_key)
127
+ end
128
+
129
+ #puts "\n== 1 vars: "; pp @node['vars']
130
+ #puts "\n== 1 fields: "; pp payload.current
131
+ #
132
+ #print "vars: "
133
+ #pp @node['vars'].collect { |k, v| [ k, JSON.dump(v)[0, 20] + "..." ] }
134
+ #print "vars: "
135
+ #@node['vars'].each { |k, v| print "#{k.inspect} --> "; pp v }
136
+
137
+ #puts "== retree:"; pp retree; puts
138
+ @node['tree'] = retree if retree
139
+ end
140
+
141
+ def set_param(key, val)
142
+
143
+ return unless key
144
+
145
+ if m = key.match(/\A(?:field|fld|f)\.(.+)\z/)
146
+ Dense.set(payload.copy, m[1], val)
147
+ elsif m = key.match(/\A(?:variable|var|v)\.(.+)\z/)
148
+ Dense.set(@node['vars'], m[1], val)
149
+ else
150
+ Dense.set(@node['vars'], key, val)
151
+ end
152
+ end
107
153
  end
108
154
 
@@ -234,8 +234,22 @@ class Flor::Pro::Att < Flor::Procedure
234
234
 
235
235
  wrap_reply('disable' => Flor.true?(payload['ret']))
236
236
  end
237
-
237
+ #
238
238
  alias receive_off receive_disabled
239
239
  alias receive_disable receive_disabled
240
+
241
+ def receive_child_on_error
242
+ if pn = parent_node; pn['child_on_error'] = payload_ret; end; wrap_reply
243
+ end
244
+ def receive_child_on_cancel
245
+ if pn = parent_node; pn['child_on_cancel'] = payload_ret; end; wrap_reply
246
+ end
247
+ def receive_child_on_timeout
248
+ if pn = parent_node; pn['child_on_timeout'] = payload_ret; end; wrap_reply
249
+ end
250
+ #
251
+ alias receive_children_on_error receive_child_on_error
252
+ alias receive_children_on_cancel receive_child_on_cancel
253
+ alias receive_children_on_timeout receive_child_on_timeout
240
254
  end
241
255
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  class Flor::Pro::Ref < Flor::Procedure
3
3
 
4
- names %w[ _ref _rep ]
4
+ names %w[ _ref _rep _reff ]
5
5
 
6
6
  def pre_execute
7
7
 
@@ -44,6 +44,7 @@ class Flor::Pro::Ref < Flor::Procedure
44
44
  return nil if field?(ke.work_path)
45
45
  return nil if child_id == 1 && (n = parent_node) && n['heat0'] == '_head'
46
46
  return nil if ke.miss[1].any? && ke.miss[4].empty?
47
+ return nil if tree[0] == '_reff'
47
48
 
48
49
  raise
49
50
  end
@@ -23,7 +23,19 @@ class Flor::Pro::Arith < Flor::Procedure
23
23
  # 3 # ==> -4
24
24
  # ```
25
25
  #
26
- # ...
26
+ # ```
27
+ # [ 1 2 3 ]
28
+ # + _ # ==> 6
29
+ #
30
+ # [ 2 3 4 ]
31
+ # * _ # ==> 24
32
+ # ```
33
+ #
34
+ # ```
35
+ # + "hell" "o"
36
+ # "hel" + "lo"
37
+ # # both yield "hello"
38
+ # ```
27
39
 
28
40
  names %w[ + - * / % ]
29
41
 
@@ -32,26 +44,41 @@ class Flor::Pro::Arith < Flor::Procedure
32
44
  def pre_execute
33
45
 
34
46
  @node['rets'] = []
47
+ @node['atts'] = []
48
+
49
+ unatt_unkeyed_children
35
50
  end
36
51
 
37
52
  def receive_last
38
53
 
39
54
  sign = tree.first.to_sym
40
- count = @node['rets'].size
55
+
56
+ rets = @node['rets']
57
+ rets << node_payload_ret \
58
+ if rets.empty? && node_payload_ret.is_a?(Array)
59
+ rets = rets[0] \
60
+ if rets.size == 1 && rets[0].is_a?(Array)
41
61
 
42
62
  fail Flor::FlorError.new('modulo % requires at least 2 arguments', self) \
43
- if sign == :% && count < 2
63
+ if sign == :% && rets.size < 2
64
+
65
+ if j = att('join')
66
+ max = rets.size - 1
67
+ rets = rets.each_with_index.inject([]) { |a, (e, i)|
68
+ a << e
69
+ a << j if i < max
70
+ a }
71
+ rets[0] = stringify(rets[0]) \
72
+ if rets.any? && j.is_a?(String)
73
+ end
44
74
 
45
75
  ret =
46
- if @node['rets'].compact.empty?
76
+ if rets.compact.empty?
47
77
  DEFAULTS[sign]
48
78
  elsif sign == :+
49
- @node['rets'].reduce { |r, e|
50
- # TODO use djan instead of #to_s?
51
- # TODO use JSON instead of #to_s or djan?
52
- r + (r.is_a?(String) ? e.to_s : e) }
79
+ rets.reduce { |r, e|
80
+ r + (r.is_a?(String) ? stringify(e) : e) }
53
81
  else
54
- rets = @node['rets']
55
82
  rets = rets.collect(&:to_f) \
56
83
  if sign == :/ || rets.find { |r| r.is_a?(Float) }
57
84
  rets.reduce(&sign)
@@ -65,5 +92,15 @@ class Flor::Pro::Arith < Flor::Procedure
65
92
 
66
93
  wrap_reply('ret' => ret)
67
94
  end
95
+
96
+ protected
97
+
98
+ def stringify(o)
99
+
100
+ # TODO use djan instead of #to_s?
101
+ # TODO use JSON instead of #to_s or djan?
102
+
103
+ o.to_s
104
+ end
68
105
  end
69
106
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  class Flor::Pro::Break < Flor::Procedure
3
3
  #
4
- # Breaks or continues a "while", "until", "loop" or an "cursor".
4
+ # Breaks or continues a "while", "until", "loop" or a "cursor".
5
5
  #
6
6
  # ```
7
7
  # until false
@@ -85,6 +85,47 @@ class Flor::Pro::Case < Flor::Procedure
85
85
  # # yields "matched:molzin"
86
86
  # ```
87
87
  #
88
+ # ### defaulting to f.ret
89
+ #
90
+ # When nothing is explicitely provided for consideration by "case", the
91
+ # incoming `f.ret` is used.
92
+ #
93
+ # ```
94
+ # 2
95
+ # case
96
+ # [ 0 1 2 ]; 'low'
97
+ # 6; 'high'
98
+ # else; 'over'
99
+ # # yields 'low'
100
+ # ```
101
+ #
102
+ # ### incoming f.ret is preserved
103
+ #
104
+ # "case" makes sure `f.ret` gets to its upon-entering-"case" value
105
+ # when considered inside:
106
+ #
107
+ # ```
108
+ # 7
109
+ # case (+ 3 4)
110
+ # 5; 'cinq'
111
+ # [ f.ret ]; 'sept'
112
+ # 6; 'six'
113
+ # else; 'whatever...'
114
+ #
115
+ # # yields 'sept'
116
+ # ```
117
+ #
118
+ # ```
119
+ # "six"
120
+ # case 6
121
+ # 5; 'cinq'
122
+ # 7; 'sept'
123
+ # 6; "six $( f.ret | upcase _ )"
124
+ # else; 'je ne sais pas'
125
+ #
126
+ # # yields "six SIX"
127
+ # ```
128
+ #
88
129
  # ## see also
89
130
  #
90
131
  # Match, cond, if.