flor 1.4.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 298a6b2c9d3752b561ee8933ae00ed7a3f63682fb758dbe899097c6f7f56c00d
4
- data.tar.gz: 3e2602737b9de7a452549d0f8ed34752618b1322a5508d178abe6559d549c045
3
+ metadata.gz: b28e7de7c950544c32279d8a63917911ae9d12be4154a1bcc0539c8ae343b6d6
4
+ data.tar.gz: 1838e6d66710983c5adce4dc19b799bed0a34bf5427ee8156c516749d740e703
5
5
  SHA512:
6
- metadata.gz: 28ae10c78676391537dde7cd7e0082338650c6aeba60fbcffa2ca5a4cb2dd2f168d7ff61019472c5f6f3d2216cabfe6e9bccb7cdae4856b513e0663f4d4ec362
7
- data.tar.gz: 6379738cddfc5b74d37a30fa23260924649866b49dc670f37a0540a47a5079062288851ce07306350e227d73d0fd873f2199c3ea01b3399bce61572b8cebe497
6
+ metadata.gz: f75fd74bd118784e7cf3285bff5f55d4e97c67f4666332712dc9b878c267690247468372ec3970d6cff570f90f235b31ae182279aec87f77d442d7cfa1c6536a
7
+ data.tar.gz: 8c4b251c6bd1cc514580aae6430dcc70489ca046940e8a9e23104260f48be0a5049ac70310bcecfa3fdb62d00a8e603c644e177ab1db080e38bea04c1c538fa7
data/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
  # CHANGELOG.md
3
3
 
4
4
 
5
+ ## flor 1.6.0 released 2023-01-13
6
+
7
+ * Add #fei to Message, Pointer, Timer, Trace and Trap models
8
+ * Allow for // comments in Flor language
9
+ * Call post_task when tasker hands back task
10
+
11
+
12
+ ## flor 1.5.0 released 2021-11-24
13
+
14
+ * Add storage callbacks `on(:pointers, :any) { do_that }`
15
+ * Add `on_receive` (and `on receive`)
16
+
17
+
5
18
  ## flor 1.4.0 released 2021-11-10
6
19
 
7
20
  * Add :tree to Execution#to_h
data/LICENSE.txt CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- Copyright (c) 2015-2021, John Mettraux, jmettraux+flor@gmail.com
2
+ Copyright (c) 2015-2023, John Mettraux, jmettraux+flor@gmail.com
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
data/Makefile CHANGED
@@ -1,10 +1,10 @@
1
1
 
2
2
  ## gem tasks ##
3
3
 
4
- NAME = \
5
- $(shell ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.name")
6
- VERSION = \
7
- $(shell ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.version")
4
+ NAME != \
5
+ ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.name"
6
+ VERSION != \
7
+ ruby -e "s = eval(File.read(Dir['*.gemspec'][0])); puts s.version"
8
8
 
9
9
  count_lines:
10
10
  find lib -name "*.rb" | xargs cat | ruby -e "p STDIN.readlines.count { |l| l = l.strip; l[0, 1] != '#' && l != '' }"
data/README.md CHANGED
@@ -47,7 +47,7 @@ require 'flor/unit'
47
47
  # uncomment to see the flor activity
48
48
 
49
49
  sto_uri = 'sqlite://flor_qs.db'
50
- sto_uri = 'jdbc:sqlite://flor_qs.db' if RUBY_PLATFORM.match(/java/)
50
+ sto_uri = 'jdbc:sqlite://flor_qs.db' if RUBY_PLATFORM.match?(/java/)
51
51
 
52
52
  flor = Flor::Unit.new(loader: Flor::HashLoader, sto_uri: sto_uri)
53
53
  # instantiate flor unit
data/lib/flor/colours.rb CHANGED
@@ -27,7 +27,7 @@ module Flor
27
27
  class Colours
28
28
 
29
29
  Flor::COLS.each do |k, v|
30
- if v.match(/\A\d/)
30
+ if v.match(/\A\d/) # Ruby 2.3 doesn't have String#match?
31
31
  class_eval(%{
32
32
  def #{k}(s=nil)
33
33
  s ? "[#{v}m" + s + "" : "[#{v}m"
@@ -42,7 +42,7 @@ module Flor
42
42
  class NoColours
43
43
 
44
44
  Flor::COLS.each do |k, v|
45
- if v.match(/\A\d/)
45
+ if v.match(/\A\d/) # Ruby 2.3 doesn't have String#match?
46
46
  class_eval("def #{k}(s=''); s; end")
47
47
  else
48
48
  class_eval("alias #{k} #{v}")
@@ -88,7 +88,7 @@ class Flor::Node
88
88
  def domain; Flor.domain(@execution['exid']); end
89
89
 
90
90
  def point; @message['point']; end
91
- def from; @message['from']; end
91
+ def from; @from || @message['from']; end
92
92
 
93
93
  def cnodes; @node['cnodes']; end
94
94
  def cnodes_any?; cnodes && cnodes.any?; end
@@ -381,8 +381,17 @@ class Flor::Procedure < Flor::Node
381
381
 
382
382
  receive_when_ended
383
383
 
384
+ elsif should_apply_on_receive?
385
+
386
+ apply_on_receive
387
+
384
388
  else
385
389
 
390
+ orn = @node['on_receive_nid']
391
+ @from = orn[1] if orn && orn[0] == from
392
+ #
393
+ # in order to move on to the next child...
394
+
386
395
  receive
387
396
  end
388
397
  end
@@ -982,6 +991,36 @@ class Flor::Procedure < Flor::Node
982
991
 
983
992
  []
984
993
  end
994
+
995
+ def should_apply_on_receive?
996
+
997
+ return false if @message['from_on'] == 'receive'
998
+ #
999
+ # no, since the message comes from an on_receive...
1000
+ # how about nested on_receives?
1001
+
1002
+ orc = @node['on_receive']
1003
+ return false if orc.nil? || orc.empty?
1004
+
1005
+ orn = @node['on_receive_nid']
1006
+ return false if orn && orn[0] == from
1007
+
1008
+ true
1009
+ end
1010
+
1011
+ def apply_on_receive
1012
+
1013
+ determine_fcid_and_ncid
1014
+
1015
+ args = [
1016
+ [ 'msg', @message ],
1017
+ [ 'fcid', @fcid ] ]
1018
+
1019
+ ms = apply(@node['on_receive'][0][1], args, tree[2])
1020
+ @node['on_receive_nid'] = [ ms[0]['nid'], from ]
1021
+
1022
+ ms
1023
+ end
985
1024
  end
986
1025
 
987
1026
 
data/lib/flor/flor.rb CHANGED
@@ -199,7 +199,7 @@ module Flor
199
199
  def is_array_of_messages?(o)
200
200
 
201
201
  o.is_a?(Array) &&
202
- o.all? { |e| is_message?(o) }
202
+ o.all? { |e| is_message?(e) }
203
203
  end
204
204
 
205
205
  def h_fetch(h, *keys)
data/lib/flor/parser.rb CHANGED
@@ -6,6 +6,9 @@ module Flor
6
6
 
7
7
  #Raabro.pp(Flor::Parser.parse(input, debug: 2), colours: true)
8
8
  #Raabro.pp(Flor::Parser.parse(input, debug: 3), colours: true)
9
+ #
10
+ # turn one or the other when debugging the parser...
11
+
9
12
  opts = fname if fname.is_a?(Hash) && opts.empty?
10
13
 
11
14
  if r = Flor::Parser.parse(input, opts)
@@ -49,7 +52,7 @@ module Flor
49
52
  def semicolon(i); str(nil, i, ';'); end
50
53
  def comma(i); str(nil, i, ','); end
51
54
  def dquote(i); str(nil, i, '"'); end
52
- def slash(i); str(nil, i, '/'); end
55
+ def slash(i); rex(nil, i, /\/(?!\/)/); end
53
56
  def dollar(i); str(nil, i, '$'); end
54
57
  def pipepipe(i); str(nil, i, '||'); end
55
58
 
@@ -95,7 +98,11 @@ module Flor
95
98
  seq(nil, i, :dot, :rf_symbol)
96
99
  end
97
100
  def rf_index(i); alt(nil, i, :rf_dot_idx, :rf_sqa_idx); end
98
- def rf_symbol(i); rex(:refsym, i, /[^.:;| \b\f\n\r\t"',()\[\]{}#\\]+/); end
101
+ #
102
+ def rf_symbol(i)
103
+ rex(:refsym, i, /([^.:;| \b\f\n\r\t"',()\[\]{}#\\\/]|\/(?!\/))+/)
104
+ # anything but... a slash is ok, but not a double slash...
105
+ end
99
106
  #
100
107
  def reference(i); seq(:ref, i, :rf_symbol, :rf_index, '*'); end
101
108
 
@@ -165,7 +172,7 @@ module Flor
165
172
  }x)
166
173
  end
167
174
 
168
- def comment(i); rex(nil, i, /#[^\r\n]*/); end
175
+ def comment(i); rex(nil, i, /(#|\/\/)[^\r\n]*/); end
169
176
 
170
177
  def eol(i); seq(nil, i, :wstar, :comment, '?', :rnstar); end
171
178
  def eol_wstar(i); seq(nil, i, :wstar, :comment, '?', :rnstar, :wstar); end
@@ -210,7 +217,7 @@ module Flor
210
217
  # %w[ equ == != <> ], %w[ lgt < > <= >= ], %w[ sum + - ], %w[ prd * / % ],
211
218
 
212
219
  def ssmod(i); str(:sop, i, /%/); end
213
- def ssprd(i); rex(:sop, i, /[\*\/]/); end
220
+ def ssprd(i); rex(:sop, i, /(\*|\/(?!\/))/); end
214
221
  def sssum(i); rex(:sop, i, /[+-]/); end
215
222
  def sslgt(i); rex(:sop, i, /(<=?|>=?)/); end
216
223
  def ssequ(i); rex(:sop, i, /(==?|!=|<>)/); end
@@ -99,7 +99,7 @@ class Flor::Pro::UnderscoreApply < Flor::Procedure
99
99
 
100
100
  params.each do |param_key, param_tree|
101
101
  next if param_tree[0] == '_ref'
102
- arg_i = args.index { |arg_key, arg_val| arg_key == param_key }
102
+ arg_i = args.index { |arg_key, _| arg_key == param_key }
103
103
  next unless arg_i
104
104
  arg_key, arg_val = args.delete_at(arg_i)
105
105
  seen << arg_key
data/lib/flor/pcore/on.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+
3
4
  class Flor::Pro::On < Flor::Macro
4
5
  #
5
6
  # Catches signals or errors.
@@ -132,7 +133,7 @@ class Flor::Pro::On < Flor::Macro
132
133
 
133
134
  protected
134
135
 
135
- CATCHES = %w[ error cancel timeout ].freeze
136
+ CATCHES = %w[ error cancel timeout receive ].freeze
136
137
 
137
138
  def find_catch
138
139
 
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+
4
+ class Flor::Pro::OnReceive < Flor::Procedure
5
+ #
6
+ # Binds a function to the parent node, the function will be called each time
7
+ # the parent node "receives".
8
+ #
9
+ # ```
10
+ # set l []
11
+ # sequence
12
+ # on_receive (def msg \ push l 'a')
13
+ # push l 0
14
+ # push l 1
15
+ # push l 2
16
+ # ```
17
+ # will result in the variable `l` holding `[ 0, 'a', 1, 'a', 2, 'a' ]`.
18
+ #
19
+ # ```
20
+ # set l []
21
+ # sequence
22
+ # push l 0
23
+ # on_receive (def msg \ push l 'a')
24
+ # push l 1
25
+ # push l 2
26
+ # ```
27
+ # will result in the variable `l` holding `[ 0, 1, 'a', 2, 'a' ]`.
28
+ #
29
+ # It's meant to play well with a cursor:
30
+ # ```
31
+ # set l []
32
+ # cursor
33
+ # on_receive (def \ break _ if l[-1] == 1)
34
+ # push l 0
35
+ # push l 1
36
+ # push l 2
37
+ # push l 'z'
38
+ # ```
39
+ # will result in the variable `l` holding `[ 0, 1, 'z' ]`.
40
+ #
41
+ #
42
+ # ## arguments to the on_receive function
43
+ #
44
+ # `msg` and `fcid` (from child id) are passed to the function
45
+ # ```
46
+ # set l []
47
+ # cursor
48
+ # on_receive (def msg, fcid \ push l [ msg.from, fcid ])
49
+ # push l 0
50
+ # push l 1
51
+ # push l 2
52
+ # ```
53
+ # will result in the variable `l` holding
54
+ # `[ 0, [ '0_1_1', 1 ], 1, [ '0_1_2', 2 ], 2, [ '0_1_3', 3 ] ]`.
55
+ #
56
+ #
57
+ # ## on_receive and on receive
58
+ #
59
+ # A "lighter" notation is available (it's translated automatically to a
60
+ # `on_receive`):
61
+ # ```
62
+ # set l []
63
+ # cursor
64
+ # on receive
65
+ # push l $msg.from
66
+ # break _ if l.-1 == 1
67
+ # push l 0
68
+ # push l 1
69
+ # push l 2
70
+ # ```
71
+ #
72
+ # Please note the `$msg` variable made available to the `on receive` block.
73
+ #
74
+ #
75
+ # ## concurrence and on_receive
76
+ #
77
+ # Please not that `concurrence` has its own `on_receive` with a slightly
78
+ # different behaviour.
79
+
80
+ name 'on_receive'
81
+
82
+ def pre_execute
83
+
84
+ unatt_unkeyed_children
85
+
86
+ @node['rets'] = []
87
+ end
88
+
89
+ def receive_last
90
+
91
+ prc = @node['rets'].find { |r| Flor.is_func_tree?(r) }
92
+
93
+ store_on(:receive, prc)
94
+
95
+ ms = super
96
+
97
+ ms.first['from_on'] = 'receive'
98
+
99
+ ms
100
+ end
101
+ end
102
+
@@ -139,7 +139,7 @@ class Flor::Pro::Concurrence < Flor::Procedure
139
139
  # + 12 34
140
140
  # + 56 78
141
141
  # ```
142
- # One can even express the function has a 'block':
142
+ # One can even express the function as a 'block':
143
143
  # ```
144
144
  # concurrence tag: 'x'
145
145
  # on_receive
@@ -16,7 +16,16 @@ if (ARGV & [ '-h', '--help']).any?
16
16
  puts " turns a flor .flo process definition to its tree representation"
17
17
  puts
18
18
  puts " flags:"
19
- puts " --pp pretty prints instead of dumping as JSON"
19
+ puts " --pp pretty prints instead of dumping as JSON"
20
+ puts
21
+ puts " --pj"
22
+ puts " --jp pretty prints the JSON output"
23
+ puts
24
+ puts " -y"
25
+ puts " -yaml dumps as YAML"
26
+ puts
27
+ puts " -h"
28
+ puts " --help prints this help message"
20
29
  puts
21
30
  exit 0
22
31
  end
@@ -53,11 +62,28 @@ end
53
62
  # end
54
63
 
55
64
  fname = files.first
56
- content = File.read(fname)
65
+
66
+ content =
67
+ if fname
68
+ abort("File #{fname.inspect} not found") unless File.exist?(fname)
69
+ File.read(fname)
70
+ else
71
+ STDIN.read
72
+ end
73
+
57
74
  tree = Flor.parse(content, fname, {})
58
75
 
59
76
  if flags['--pp']
60
77
  pp tree
78
+ elsif flags['--jp'] || flags['--pj']
79
+ puts(
80
+ JSON.pretty_generate(tree)
81
+ .gsub(/\[\s+/, '[ ')
82
+ .gsub(/\]\s+/, ']')
83
+ .gsub(/,\s+(\d+)\s+\]/, ', \1]')
84
+ )
85
+ elsif flags['-y'] || flags['--yaml']
86
+ puts YAML.dump(tree)
61
87
  else
62
88
  puts JSON.dump(tree)
63
89
  end
@@ -110,10 +110,16 @@ module Flor
110
110
  pt = message['point']
111
111
 
112
112
  ms = [ "call_#{pt}", "on_#{pt}", :on_message, :on, pt ]
113
- ms = ms + [ :on_cancel, :cancel ] if pt == 'detask'
113
+ case pt
114
+ when 'detask' then ms = ms + [ :on_cancel, :cancel ]
115
+ when 'return' then ms = [ :on_return, :return, :post_task ] # /!\
116
+ end
114
117
 
115
118
  m = ms.find { |mm| o.respond_to?(mm) }
116
119
 
120
+ return [ message ] if pt == 'return' && ! m
121
+ # don't call if :post_task not present
122
+
117
123
  fail(
118
124
  "#{k.class.to_s.downcase} #{k} doesn't respond to " +
119
125
  ms[0..-2].collect { |e| "##{e}" }.join(', ') + ", or ##{ms[-1]}"
@@ -316,10 +322,12 @@ module Flor
316
322
 
317
323
  def to_messages(o)
318
324
 
319
- case o
320
- when Hash then [ o ]
321
- when Array then o
322
- else []
325
+ if Flor.is_array_of_messages?(o)
326
+ o
327
+ elsif Flor.is_message?(o)
328
+ [ o ]
329
+ else
330
+ []
323
331
  end
324
332
  end
325
333
 
@@ -48,7 +48,7 @@ module Flor
48
48
 
49
49
  protected
50
50
 
51
- CLOSING_POINTS = %w[ task terminated ceased ]
51
+ CLOSING_POINTS = %w[ task terminated ceased ].freeze
52
52
  #
53
53
  # point for messages that, after consumption, are conserved
54
54
  # in the execution's "closing_messages" array
@@ -160,14 +160,18 @@ module Flor
160
160
  def return(message)
161
161
 
162
162
  n = @execution['nodes'][message['nid']] || {}
163
- m = n['message'] || {}
164
- c = m['cause']
163
+ c = (n['message'] || {})['cause']
165
164
 
166
- rm = message.dup
167
- rm['point'] = 'receive'
168
- rm['cause'] = c if c # preserve 'cause' for routing
165
+ ms =
166
+ if n['task']
167
+ @unit.ganger.task(self, message)
168
+ else
169
+ [ message.dup ]
170
+ end
169
171
 
170
- [ rm ]
172
+ ms.each { |m|
173
+ m['point'] = 'receive'
174
+ m['cause'] = c if c }
171
175
  end
172
176
 
173
177
  def schedule(message)
@@ -47,16 +47,14 @@ module Flor
47
47
  def task(executor, message)
48
48
 
49
49
  domain = message['exid'].split('-', 2).first
50
- tname = message['tasker']
50
+ #tname = message['tasker']
51
+ tname = determine_tasker_name(executor, message)
51
52
 
52
53
  tconf =
53
54
  ( ! message['routed'] &&
54
55
  (@unit.loader.tasker(domain, 'ganger', message) ||
55
56
  @unit.loader.tasker(domain, 'tasker', message))) ||
56
57
  @unit.loader.tasker(domain, tname, message)
57
- #puts "=" * 80
58
- #pp tconf
59
- #puts "=" * 80
60
58
 
61
59
  fail ArgumentError.new(
62
60
  "tasker #{tname.inspect} not found"
@@ -66,6 +64,7 @@ module Flor
66
64
 
67
65
  points = [ nil, message['point'] ]
68
66
  points << 'detask' if points.include?('cancel')
67
+ points << 'task' if points.include?('return')
69
68
 
70
69
  tconf = tconf.find { |h| points.include?(h['point']) }
71
70
  end
@@ -154,6 +153,17 @@ module Flor
154
153
 
155
154
  vars
156
155
  end
156
+
157
+ def determine_tasker_name(executor, message)
158
+
159
+ tname = message['tasker']
160
+
161
+ return tname if tname
162
+
163
+ n = executor.node(message)
164
+
165
+ n['task']['tasker']
166
+ end
157
167
  end
158
168
  end
159
169
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+
3
4
  module Flor
4
5
 
5
6
  # TODO ::Logger has a formatting callback
@@ -11,7 +12,7 @@ module Flor
11
12
 
12
13
  # NB: logger configuration entries start with "log_"
13
14
 
14
- LEVELS_I = %w[ DEBUG INFO WARN ERROR FATAL UNKNOWN ]
15
+ LEVELS_I = %w[ DEBUG INFO WARN ERROR FATAL UNKNOWN ].freeze
15
16
 
16
17
  def initialize(unit)
17
18
 
@@ -24,6 +24,8 @@ module Flor
24
24
  def nid; data['nid']; end
25
25
  def tasker; data['tasker']; end
26
26
  alias payload data
27
+
28
+ def fei; [ exid, nid ].join('-') rescue nil; end
27
29
  end
28
30
  end
29
31
 
@@ -29,6 +29,8 @@ module Flor
29
29
  # # we don't care, pointers are cleaned anyway when the flow dies
30
30
  #end
31
31
 
32
+ def fei; [ exid, nid ].join('-'); end
33
+
32
34
  # If the pointer is a "var" pointer, returns the full value
33
35
  # for the variable, as found in the execution's node "0".
34
36
  #
@@ -27,6 +27,8 @@ module Flor
27
27
  # index [ :exid, :nid ]
28
28
  #end
29
29
 
30
+ def fei; [ exid, nid ].join('-'); end
31
+
30
32
  def to_trigger_message
31
33
 
32
34
  d = self.data(false)
@@ -17,6 +17,8 @@ module Flor
17
17
  #
18
18
  # index :exid
19
19
  #end
20
+
21
+ def fei; [ exid, nid ].join('-') rescue nil; end
20
22
  end
21
23
  end
22
24
 
@@ -34,6 +34,8 @@ module Flor
34
34
  # index [ :exid, :nid ]
35
35
  #end
36
36
 
37
+ def fei; [ exid, nid ].join('-') rescue nil; end
38
+
37
39
  def to_hook
38
40
 
39
41
  opts = {}
@@ -113,27 +113,6 @@ module Flor
113
113
  @ganger.shutdown
114
114
  end
115
115
 
116
- def on_start_exc(e)
117
-
118
- io = StringIO.new
119
-
120
- head, kind =
121
- e.is_a?(StandardError) ? [ '=sch', 'error' ] : [ '!sch', 'exception' ]
122
- thr = Thread.current
123
-
124
- t = head[0, 2] + Time.now.to_f.to_s.split('.').last
125
- io.puts ' /' + t + ' ' + head * 17
126
- io.puts " |#{t} + in #{self.class}#start"
127
- io.puts " |#{t} db: #{@storage.db.class} #{@storage.db.object_id}"
128
- io.puts " |#{t} thread: t#{thr.object_id} #{thr.inspect}"
129
- io.puts " |#{t} #{kind}: #{e.inspect}"
130
- io.puts " |#{t} backtrace:"
131
- e.backtrace.each { |l| io.puts "|#{t} #{l}" }
132
- io.puts ' \\' + t + ' ' + (head * 17) + ' .'
133
-
134
- io.string
135
- end
136
-
137
116
  def start
138
117
 
139
118
  # TODO heartbeat, every x minutes, when idle, log something
@@ -557,6 +536,27 @@ module Flor
557
536
 
558
537
  protected
559
538
 
539
+ def on_start_exc(e)
540
+
541
+ io = StringIO.new
542
+
543
+ head, kind =
544
+ e.is_a?(StandardError) ? [ '=sch', 'error' ] : [ '!sch', 'exception' ]
545
+ thr = Thread.current
546
+
547
+ t = head[0, 2] + Time.now.to_f.to_s.split('.').last
548
+ io.puts ' /' + t + ' ' + head * 17
549
+ io.puts " |#{t} + in #{self.class}#start"
550
+ io.puts " |#{t} db: #{@storage.db.class} #{@storage.db.object_id}"
551
+ io.puts " |#{t} thread: t#{thr.object_id} #{thr.inspect}"
552
+ io.puts " |#{t} #{kind}: #{e.inspect}"
553
+ io.puts " |#{t} backtrace:"
554
+ e.backtrace.each { |l| io.puts "|#{t} #{l}" }
555
+ io.puts ' \\' + t + ' ' + (head * 17) + ' .'
556
+
557
+ io.string
558
+ end
559
+
560
560
  def extract_dump_and_load_filters(opts)
561
561
 
562
562
  o = lambda { |k| v = opts[k] || opts["#{k}s".to_sym]; v ? Array(v) : nil }
@@ -16,7 +16,7 @@ module Flor
16
16
  :content
17
17
  ].freeze
18
18
 
19
- attr_reader :unit, :db, :models
19
+ attr_reader :unit, :db, :models, :callbacks
20
20
 
21
21
  attr_reader :mutex
22
22
  # might be useful for some implementations
@@ -31,6 +31,8 @@ module Flor
31
31
  @archive = @unit.conf['sto_archive']
32
32
  @mutex = @unit.conf['sto_sync'] ? Mutex.new : nil
33
33
 
34
+ @callbacks = {}
35
+
34
36
  connect
35
37
  end
36
38
 
@@ -191,6 +193,8 @@ module Flor
191
193
  mtime: now,
192
194
  munit: u)
193
195
 
196
+ callback(:executions, :update, id)
197
+
194
198
  else
195
199
 
196
200
  exe['id'] =
@@ -205,6 +209,8 @@ module Flor
205
209
  cunit: u,
206
210
  munit: u)
207
211
  .to_i
212
+
213
+ callback(:executions, :insert, exe['id'])
208
214
  end
209
215
 
210
216
  remove_nodes(exe, status, now)
@@ -418,26 +424,29 @@ module Flor
418
424
  now = Flor.tstamp
419
425
  u = @unit.identifier
420
426
 
421
- synchronize do
427
+ id =
428
+ synchronize do
422
429
 
423
- @db[:flor_timers]
424
- .insert(
425
- domain: Flor.domain(message['exid']),
426
- exid: message['exid'],
427
- nid: message['nid'],
428
- onid: message['onid'] || message['nid'],
429
- bnid: message['nid'],
430
- type: type,
431
- schedule: string,
432
- ntime: next_time,
433
- content: to_blob(message),
434
- count: 0,
435
- status: 'active',
436
- ctime: now,
437
- mtime: now,
438
- cunit: u,
439
- munit: u)
440
- end
430
+ @db[:flor_timers]
431
+ .insert(
432
+ domain: Flor.domain(message['exid']),
433
+ exid: message['exid'],
434
+ nid: message['nid'],
435
+ onid: message['onid'] || message['nid'],
436
+ bnid: message['nid'],
437
+ type: type,
438
+ schedule: string,
439
+ ntime: next_time,
440
+ content: to_blob(message),
441
+ count: 0,
442
+ status: 'active',
443
+ ctime: now,
444
+ mtime: now,
445
+ cunit: u,
446
+ munit: u)
447
+ end
448
+
449
+ callback(:timers, :insert, id)
441
450
 
442
451
  @unit.wake_up
443
452
 
@@ -502,6 +511,8 @@ module Flor
502
511
  munit: u)
503
512
  end
504
513
 
514
+ callback(:traps, :insert, id)
515
+
505
516
  traps[id]
506
517
 
507
518
  rescue => err
@@ -548,6 +559,21 @@ module Flor
548
559
  nil
549
560
  end
550
561
 
562
+ def on(key, actions=[], &block)
563
+
564
+ as =
565
+ case actions
566
+ when :any, 'any' then []
567
+ when Array then actions
568
+ when Symbol then [ actions ]
569
+ when String then actions.split(/\s*[;,]\s*/)
570
+ else []
571
+ end
572
+ .collect(&:to_sym)
573
+
574
+ (@callbacks[key] ||= []) << [ as, block ]
575
+ end
576
+
551
577
  protected
552
578
 
553
579
  def migration_table_and_column(opts={})
@@ -640,10 +666,11 @@ module Flor
640
666
  def reschedule_timer(t)
641
667
 
642
668
  w = { id: t.id.to_i, status: 'active', mtime: t.mtime, munit: t.munit }
669
+ r = nil
643
670
 
644
671
  if t.type != 'at' && t.type != 'in'
645
672
 
646
- @db[:flor_timers]
673
+ r = @db[:flor_timers]
647
674
  .where(w)
648
675
  .update(
649
676
  count: t.count.to_i + 1,
@@ -652,9 +679,11 @@ module Flor
652
679
  mtime: Flor.tstamp,
653
680
  munit: @unit.identifier)
654
681
 
682
+ callback(:timers, :update, w, t)
683
+
655
684
  elsif @archive
656
685
 
657
- @db[:flor_timers]
686
+ r = @db[:flor_timers]
658
687
  .where(w)
659
688
  .update(
660
689
  count: t.count.to_i + 1,
@@ -662,12 +691,18 @@ module Flor
662
691
  mtime: Flor.tstamp,
663
692
  munit: @unit.identifier)
664
693
 
694
+ callback(:timers, :update, w, t)
695
+
665
696
  else
666
697
 
667
- @db[:flor_timers]
698
+ r = @db[:flor_timers]
668
699
  .where(w)
669
700
  .delete
701
+
702
+ callback(:timers, :delete, w, t)
670
703
  end
704
+
705
+ r
671
706
  end
672
707
 
673
708
  def remove_nodes(exe, status, now)
@@ -787,6 +822,8 @@ module Flor
787
822
  .import(
788
823
  POINTER_COLUMNS,
789
824
  pointers)
825
+
826
+ callback(:pointers, :update, exid)
790
827
  end
791
828
 
792
829
  #def pointer_columns
@@ -835,6 +872,23 @@ module Flor
835
872
  .inject([]) { |a, elt| a << [ a.last, elt ].compact.join('.'); a }
836
873
  end
837
874
 
875
+ def callback(table, action, *rest)
876
+
877
+ (@callbacks[table] || [])
878
+ .each { |as, block|
879
+ call_back(block, table, action, *rest) \
880
+ if as.empty? || as.include?(action) }
881
+ end
882
+
883
+ def call_back(block, table, action, *rest)
884
+
885
+ block.call(
886
+ *(
887
+ block.arity < 0 ?
888
+ [ table, action, *rest ] :
889
+ [ table, action, *rest ][0, block.arity]))
890
+ end
891
+
838
892
  class DbLogger
839
893
 
840
894
  def initialize(unit); @unit = unit; end
@@ -854,11 +908,11 @@ module Flor
854
908
  fail ArgumentError.new("no 'sto_uri' conf, cannot connect to db") \
855
909
  unless uri
856
910
 
857
- return Kernel.const_get(uri) \
858
- if uri.is_a?(String) && uri.match(/\A[A-Z]+\z/)
859
- # for cases where uri == 'DB'
860
-
861
- Sequel.connect(uri)
911
+ begin
912
+ Kernel.const_get(uri)
913
+ rescue NameError
914
+ Sequel.connect(uri)
915
+ end
862
916
  end
863
917
 
864
918
  def connect
@@ -169,9 +169,12 @@ module Flor
169
169
 
170
170
  pt = @message['point']
171
171
 
172
- ms = [ "post_#{pt}" ]; ms << :post_cancel if pt == 'detask'
172
+ #ms = [ "post_#{pt}" ]; ms << :post_cancel if pt == 'detask'
173
+ #call_one_of(ms)
173
174
  #
174
- call_one_of(ms)
175
+ # :post_task is called by, well, the caller
176
+ #
177
+ call_one_of([ :post_detask, :post_cancel ]) if pt == 'detask'
175
178
 
176
179
  msg = derive_message(message)
177
180
 
data/lib/flor.rb CHANGED
@@ -16,7 +16,7 @@ require 'dense'
16
16
 
17
17
  module Flor
18
18
 
19
- VERSION = '1.4.0'
19
+ VERSION = '1.6.0'
20
20
  end
21
21
 
22
22
  require 'flor/colours'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Mettraux
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-10 00:00:00.000000000 Z
11
+ date: 2023-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: munemo
@@ -204,6 +204,7 @@ files:
204
204
  - lib/flor/pcore/on.rb
205
205
  - lib/flor/pcore/on_cancel.rb
206
206
  - lib/flor/pcore/on_error.rb
207
+ - lib/flor/pcore/on_receive.rb
207
208
  - lib/flor/pcore/push.rb
208
209
  - lib/flor/pcore/rand.rb
209
210
  - lib/flor/pcore/range.rb
@@ -289,7 +290,7 @@ metadata:
289
290
  mailing_list_uri: https://groups.google.com/forum/#!forum/floraison
290
291
  homepage_uri: https://github.com/floraison/flor
291
292
  source_code_uri: https://github.com/floraison/flor
292
- post_install_message:
293
+ post_install_message:
293
294
  rdoc_options: []
294
295
  require_paths:
295
296
  - lib
@@ -304,8 +305,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
304
305
  - !ruby/object:Gem::Version
305
306
  version: '0'
306
307
  requirements: []
307
- rubygems_version: 3.0.3
308
- signing_key:
308
+ rubygems_version: 3.1.6
309
+ signing_key:
309
310
  specification_version: 4
310
311
  summary: A Ruby workflow engine
311
312
  test_files: []