oflow 0.8.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/README.md +14 -12
- data/lib/oflow/actor.rb +4 -0
- data/lib/oflow/actors.rb +2 -0
- data/lib/oflow/actors/shellone.rb +79 -0
- data/lib/oflow/actors/shellrepeat.rb +110 -0
- data/lib/oflow/task.rb +1 -1
- data/lib/oflow/test/actorwrap.rb +14 -1
- data/lib/oflow/version.rb +1 -1
- data/test/actors/bad.rb +6 -0
- data/test/actors/doubler.rb +16 -0
- data/test/actors/shellone_test.rb +47 -0
- data/test/actors/shellrepeat_test.rb +42 -0
- data/test/actors/timer_test.rb +2 -2
- data/test/actors/tripler.rb +21 -0
- data/test/all_tests.rb +1 -0
- data/test/d2.rb +15 -0
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a972ca61c61251a79b699cce7cab0bd3a3810e9
|
4
|
+
data.tar.gz: 8a995d9f63fcd512f802520cf5097491d6edfbff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a31cb845ae3322e83fdcb51e8dead9f12991d6f4b4fdf3daa6f9c60ae04618fde0e220339c4a047370c482a2026d23c4901986ce5c0b4fffc3908c019655245
|
7
|
+
data.tar.gz: e8bca27d81e86ed6c390146fcc80a2071451f7fb2b0a73269d3a9443267910b382050aad46595560c7b1092684e769a5355d72ccef6b64f8334d559dfdd62cc3
|
data/README.md
CHANGED
@@ -25,13 +25,21 @@ Follow [@peterohler on Twitter](http://twitter.com/#!/peterohler) for announceme
|
|
25
25
|
|
26
26
|
## Release Notes
|
27
27
|
|
28
|
-
###
|
28
|
+
### Current Release 1.0
|
29
|
+
|
30
|
+
- Add an Actors/Task that starts a application and exchanges data using stdout
|
31
|
+
and stdin.
|
32
|
+
|
33
|
+
- Add an Actors/Task that callout to a remote application and exchange data
|
34
|
+
using JSON over stdin and stdout.
|
35
|
+
|
36
|
+
### Release 0.8
|
29
37
|
|
30
38
|
- A somewhat non trivial example. GemChart collects statistics on my gems and
|
31
39
|
stores those statistics. It also provides a web interface to view the
|
32
40
|
statistics as a graph.
|
33
41
|
|
34
|
-
###
|
42
|
+
### Release 0.7
|
35
43
|
|
36
44
|
- Simplified the APIs and structure.
|
37
45
|
|
@@ -139,22 +147,16 @@ Hello World!
|
|
139
147
|
|
140
148
|
## Future Features
|
141
149
|
|
142
|
-
- .svg file input for configuration.
|
143
|
-
|
144
|
-
- Visio file input for configuration.
|
145
|
-
|
146
|
-
- CallOut Actor that uses pipes and fork to use a non-Ruby actor.
|
147
|
-
|
148
|
-
- Cross linking Tasks and Flows.
|
149
|
-
|
150
|
-
- Dynamic links to Tasks and Flows.
|
151
|
-
|
152
150
|
- High performance C version. Proof of concept puts the performance range at
|
153
151
|
around 10M operations per second where an operation is one task execution per
|
154
152
|
thread.
|
155
153
|
|
156
154
|
- HTTP/Websockets based inpector.
|
157
155
|
|
156
|
+
- .svg file input for configuration.
|
157
|
+
|
158
|
+
- Visio file input for configuration.
|
159
|
+
|
158
160
|
# Links
|
159
161
|
|
160
162
|
## Links of Interest
|
data/lib/oflow/actor.rb
CHANGED
data/lib/oflow/actors.rb
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
module OFlow
|
5
|
+
module Actors
|
6
|
+
|
7
|
+
#
|
8
|
+
class ShellOne < Actor
|
9
|
+
|
10
|
+
attr_reader :dir
|
11
|
+
attr_reader :cmd
|
12
|
+
attr_reader :timeout
|
13
|
+
|
14
|
+
def initialize(task, options)
|
15
|
+
super
|
16
|
+
@dir = options[:dir]
|
17
|
+
@dir = '.' if @dir.nil?
|
18
|
+
@dir = File.expand_path(@dir.strip)
|
19
|
+
|
20
|
+
@cmd = options[:cmd]
|
21
|
+
@timeout = options.fetch(:timeout, 1.0).to_f
|
22
|
+
@timeout = 0.001 if 0.001 > @timeout
|
23
|
+
end
|
24
|
+
|
25
|
+
def perform(op, box)
|
26
|
+
input = Oj.dump(box.contents, mode: :compat, indent: 0)
|
27
|
+
i, o, e, _ = Open3.popen3(@cmd, chdir: @dir)
|
28
|
+
i.write(input)
|
29
|
+
i.close
|
30
|
+
giveup = Time.now + @timeout
|
31
|
+
ra = [e, o]
|
32
|
+
|
33
|
+
out = ''
|
34
|
+
err = ''
|
35
|
+
ec = false # stderr closed flag
|
36
|
+
oc = false # stdout closed flag
|
37
|
+
while true
|
38
|
+
rem = giveup - Time.now
|
39
|
+
raise Exception.new("Timed out waiting for output.") if 0.0 > rem
|
40
|
+
rs, _, es = select(ra, nil, ra, rem)
|
41
|
+
unless es.nil?
|
42
|
+
es.each do |io|
|
43
|
+
ec |= io == e
|
44
|
+
oc |= io == o
|
45
|
+
end
|
46
|
+
end
|
47
|
+
break if ec && oc
|
48
|
+
unless rs.nil?
|
49
|
+
rs.each do |io|
|
50
|
+
if io == e && !ec
|
51
|
+
if io.closed? || io.eof?
|
52
|
+
ec = true
|
53
|
+
next
|
54
|
+
end
|
55
|
+
err += io.read_nonblock(1000)
|
56
|
+
elsif io == o && !oc
|
57
|
+
if io.closed? || io.eof?
|
58
|
+
oc = true
|
59
|
+
next
|
60
|
+
end
|
61
|
+
out += io.read_nonblock(1000)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
break if ec && oc
|
66
|
+
end
|
67
|
+
if 0 < err.length
|
68
|
+
raise Exception.new(err)
|
69
|
+
end
|
70
|
+
output = Oj.load(out, mode: :compat)
|
71
|
+
o.close
|
72
|
+
e.close
|
73
|
+
|
74
|
+
task.ship(nil, Box.new(output, box.tracker))
|
75
|
+
end
|
76
|
+
|
77
|
+
end # ShellOne
|
78
|
+
end # Actors
|
79
|
+
end # OFlow
|
@@ -0,0 +1,110 @@
|
|
1
|
+
|
2
|
+
require 'open3'
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module OFlow
|
6
|
+
module Actors
|
7
|
+
|
8
|
+
#
|
9
|
+
class ShellRepeat < Actor
|
10
|
+
|
11
|
+
attr_reader :dir
|
12
|
+
attr_reader :cmd
|
13
|
+
attr_reader :timeout
|
14
|
+
attr_reader :out
|
15
|
+
|
16
|
+
def initialize(task, options)
|
17
|
+
super
|
18
|
+
@dir = options[:dir]
|
19
|
+
@dir = '.' if @dir.nil?
|
20
|
+
@dir = File.expand_path(@dir.strip)
|
21
|
+
|
22
|
+
@cmd = options[:cmd]
|
23
|
+
@timeout = options.fetch(:timeout, 1.0).to_f
|
24
|
+
@timeout = 0.001 if 0.001 > @timeout
|
25
|
+
@in = nil
|
26
|
+
@out = nil
|
27
|
+
@err = nil
|
28
|
+
@pid = nil
|
29
|
+
@outThread = nil
|
30
|
+
@ctxs = {}
|
31
|
+
@ctxCnt = 0
|
32
|
+
@killLock = Mutex.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def perform(op, box)
|
36
|
+
if :kill == op
|
37
|
+
status = kill()
|
38
|
+
task.ship(:killed, Box.new(status, box.tracker))
|
39
|
+
return
|
40
|
+
end
|
41
|
+
if @pid.nil?
|
42
|
+
@in, @out, @err, wt = Open3.popen3(@cmd, chdir: @dir)
|
43
|
+
@pid = wt[:pid]
|
44
|
+
@outThread = Thread.start(self) do |me|
|
45
|
+
Thread.current[:name] = me.task.full_name() + "-out"
|
46
|
+
Oj.load(me.out, mode: :compat) do |o|
|
47
|
+
begin
|
48
|
+
k = o["ctx"]
|
49
|
+
raise Exception.new("missing context in #{cmd} reply") if k.nil?
|
50
|
+
raise Exception.new("context not found in #{cmd} reply for #{k}") unless me.hasCtx?(k)
|
51
|
+
ctx = me.clearCtx(k)
|
52
|
+
me.task.ship(nil, Box.new(o["out"], ctx))
|
53
|
+
rescue Exception => e
|
54
|
+
me.task.handle_error(e)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
@outThread = nil
|
58
|
+
kill()
|
59
|
+
end
|
60
|
+
end
|
61
|
+
if @in.closed?
|
62
|
+
kill()
|
63
|
+
return
|
64
|
+
end
|
65
|
+
@ctxCnt += 1
|
66
|
+
@ctxs[@ctxCnt] = box.tracker
|
67
|
+
wrap = { "ctx" => @ctxCnt, "in" => box.contents }
|
68
|
+
input = Oj.dump(wrap, mode: :compat, indent: 0)
|
69
|
+
@in.write(input + "\n")
|
70
|
+
@in.flush
|
71
|
+
end
|
72
|
+
|
73
|
+
def busy?()
|
74
|
+
!@ctxs.empty?
|
75
|
+
end
|
76
|
+
|
77
|
+
def getCtx(ctx)
|
78
|
+
@ctxs[ctx]
|
79
|
+
end
|
80
|
+
|
81
|
+
def hasCtx?(ctx)
|
82
|
+
@ctxs.has_key?(ctx)
|
83
|
+
end
|
84
|
+
|
85
|
+
def clearCtx(ctx)
|
86
|
+
@ctxs.delete(ctx)
|
87
|
+
end
|
88
|
+
|
89
|
+
def kill()
|
90
|
+
status = nil
|
91
|
+
@killLock.synchronize do
|
92
|
+
# kill but don't wait for an exit. Leave it orphaned so a new app can be
|
93
|
+
# started.
|
94
|
+
status = Process.kill("HUP", @pid) unless @pid.nil?
|
95
|
+
@in.close() unless @in.nil?
|
96
|
+
@out.close() unless @out.nil?
|
97
|
+
@err.close() unless @err.nil?
|
98
|
+
Thread.kill(@outThread) unless @outThread.nil?
|
99
|
+
@in = nil
|
100
|
+
@out = nil
|
101
|
+
@err = nil
|
102
|
+
@pid = nil
|
103
|
+
@outThread = nil
|
104
|
+
end
|
105
|
+
status
|
106
|
+
end
|
107
|
+
|
108
|
+
end # ShellRepeat
|
109
|
+
end # Actors
|
110
|
+
end # OFlow
|
data/lib/oflow/task.rb
CHANGED
@@ -241,7 +241,7 @@ module OFlow
|
|
241
241
|
# Returns the true if any requests are queued or a request is being processed.
|
242
242
|
# @return [true|false] true if busy, false otherwise
|
243
243
|
def busy?()
|
244
|
-
!@current_req.nil? || !@queue.empty?
|
244
|
+
!@current_req.nil? || !@queue.empty? || @actor.busy?
|
245
245
|
end
|
246
246
|
|
247
247
|
# Returns the default timeout for the time to wait for the Task to be
|
data/lib/oflow/test/actorwrap.rb
CHANGED
@@ -52,12 +52,25 @@ module OFlow
|
|
52
52
|
begin
|
53
53
|
@actor.perform(op, box)
|
54
54
|
rescue Exception => e
|
55
|
-
|
55
|
+
handle_error(e)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
nil
|
59
59
|
end
|
60
60
|
|
61
|
+
def handle_error(e)
|
62
|
+
#puts "*** #{e.class}: #{e.message}"
|
63
|
+
@history << Action.new(:error, Box.new([e, full_name()]))
|
64
|
+
end
|
65
|
+
|
66
|
+
def join(timeout)
|
67
|
+
giveup = Time.now + timeout
|
68
|
+
while @actor.busy?
|
69
|
+
raise Exception.new("Timed out") if giveup < Time.now
|
70
|
+
sleep(0.1)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
61
74
|
# Task API that adds entry to history.
|
62
75
|
def ship(dest, box)
|
63
76
|
@history << Action.new(dest, box)
|
data/lib/oflow/version.rb
CHANGED
data/test/actors/bad.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.dirname(File.dirname(__FILE__)) unless $:.include? File.dirname(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
[ File.dirname(__FILE__),
|
7
|
+
File.join(File.dirname(__FILE__), "../../lib"),
|
8
|
+
File.join(File.dirname(__FILE__), "../../../oj/ext"),
|
9
|
+
File.join(File.dirname(__FILE__), "../../../oj/lib"),
|
10
|
+
].each { |path| $: << path unless $:.include?(path) }
|
11
|
+
|
12
|
+
require 'oj'
|
13
|
+
|
14
|
+
input = Oj.load(STDIN, mode: :compat)
|
15
|
+
input.map! { |v| v * 2 }
|
16
|
+
puts Oj.dump(input, mode: :compat, indent: 0)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.dirname(File.dirname(__FILE__)) unless $:.include? File.dirname(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
require 'oflow'
|
8
|
+
require 'oflow/test'
|
9
|
+
|
10
|
+
class ShellOneTest < ::MiniTest::Test
|
11
|
+
|
12
|
+
def test_shellone_config
|
13
|
+
root_dir = File.expand_path(File.dirname(File.dirname(__FILE__)))
|
14
|
+
t = ::OFlow::Test::ActorWrap.new('test', ::OFlow::Actors::ShellOne, state: ::OFlow::Task::BLOCKED,
|
15
|
+
dir: 'somewhere',
|
16
|
+
cmd: 'pwd',
|
17
|
+
timeout: 0.5)
|
18
|
+
assert_equal(File.join(root_dir, 'somewhere'), t.actor.dir, 'dir set from options')
|
19
|
+
assert_equal('pwd', t.actor.cmd, 'cmd set from options')
|
20
|
+
assert_equal(0.5, t.actor.timeout, 'timeout set from options')
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_shellone_simple
|
24
|
+
t = ::OFlow::Test::ActorWrap.new('test', ::OFlow::Actors::ShellOne, state: ::OFlow::Task::BLOCKED,
|
25
|
+
dir: 'actors',
|
26
|
+
cmd: './doubler.rb',
|
27
|
+
timeout: 0.5)
|
28
|
+
t.receive(nil, ::OFlow::Box.new([1,2,3]))
|
29
|
+
assert_equal(1, t.history.size, 'one entry should be in the history')
|
30
|
+
|
31
|
+
assert_equal([2,4,6], t.history[0].box.contents, 'should have correct contents in shipment')
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_shellone_bad
|
35
|
+
t = ::OFlow::Test::ActorWrap.new('test', ::OFlow::Actors::ShellOne, state: ::OFlow::Task::BLOCKED,
|
36
|
+
dir: 'actors',
|
37
|
+
cmd: './bad.rb',
|
38
|
+
timeout: 0.5)
|
39
|
+
t.receive(nil, ::OFlow::Box.new([1,2,3]))
|
40
|
+
assert_equal(1, t.history.size, 'one entry should be in the history')
|
41
|
+
|
42
|
+
assert_equal("Array", t.history[0].box.contents.class.name, 'should have an Array in shipment')
|
43
|
+
assert_equal("Exception", t.history[0].box.contents[0].class.name, 'should have an error in shipment')
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.dirname(File.dirname(__FILE__)) unless $:.include? File.dirname(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
require 'oflow'
|
8
|
+
require 'oflow/test'
|
9
|
+
|
10
|
+
class ShellRepeatTest < ::MiniTest::Test
|
11
|
+
|
12
|
+
def test_shellrepeat_config
|
13
|
+
root_dir = File.expand_path(File.dirname(File.dirname(__FILE__)))
|
14
|
+
t = ::OFlow::Test::ActorWrap.new('test', ::OFlow::Actors::ShellRepeat, state: ::OFlow::Task::BLOCKED,
|
15
|
+
dir: 'somewhere',
|
16
|
+
cmd: 'tripler.rb',
|
17
|
+
timeout: 0.5)
|
18
|
+
assert_equal(File.join(root_dir, 'somewhere'), t.actor.dir, 'dir set from options')
|
19
|
+
assert_equal('tripler.rb', t.actor.cmd, 'cmd set from options')
|
20
|
+
assert_equal(0.5, t.actor.timeout, 'timeout set from options')
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_shellrepeat_simple
|
24
|
+
t = ::OFlow::Test::ActorWrap.new('test', ::OFlow::Actors::ShellRepeat, state: ::OFlow::Task::BLOCKED,
|
25
|
+
dir: 'actors',
|
26
|
+
cmd: './tripler.rb',
|
27
|
+
timeout: 0.5)
|
28
|
+
t.receive(nil, ::OFlow::Box.new([1,2,3]))
|
29
|
+
t.join(1.0)
|
30
|
+
assert_equal(1, t.history.size, 'one entry should be in the history')
|
31
|
+
|
32
|
+
assert_equal([3,6,9], t.history[0].box.contents, 'should have correct contents in shipment')
|
33
|
+
t.receive(nil, ::OFlow::Box.new([3,2,1]))
|
34
|
+
t.join(1.0)
|
35
|
+
assert_equal(2, t.history.size, 'two entries should be in the history')
|
36
|
+
# optional
|
37
|
+
t.receive(:kill, ::OFlow::Box.new([1,2,3]))
|
38
|
+
t.join(1.0)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
data/test/actors/timer_test.rb
CHANGED
@@ -66,7 +66,7 @@ class TimerTest < ::MiniTest::Test
|
|
66
66
|
assert_equal(Time, t.actor.start.class, 'is the start time a Time?')
|
67
67
|
assert(0.1 > (Time.now() + 2 - t.actor.start), 'is the start time now + 2?')
|
68
68
|
|
69
|
-
assert_raises(
|
69
|
+
assert_raises(ArgumentError) do
|
70
70
|
::OFlow::Test::ActorWrap.new('test', ::OFlow::Actors::Timer, start: 'now')
|
71
71
|
end
|
72
72
|
end
|
@@ -83,7 +83,7 @@ class TimerTest < ::MiniTest::Test
|
|
83
83
|
assert_equal(Time, t.actor.stop.class, 'is the stop time a Time?')
|
84
84
|
assert(0.1 > (Time.now() + 2 - t.actor.stop), 'is the stop time now + 2?')
|
85
85
|
|
86
|
-
assert_raises(
|
86
|
+
assert_raises(ArgumentError) do
|
87
87
|
::OFlow::Test::ActorWrap.new('test', ::OFlow::Actors::Timer, stop: 'now')
|
88
88
|
end
|
89
89
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.dirname(File.dirname(__FILE__)) unless $:.include? File.dirname(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
[ File.dirname(__FILE__),
|
7
|
+
File.join(File.dirname(__FILE__), "../../lib"),
|
8
|
+
File.join(File.dirname(__FILE__), "../../../oj/ext"),
|
9
|
+
File.join(File.dirname(__FILE__), "../../../oj/lib"),
|
10
|
+
].each { |path| $: << path unless $:.include?(path) }
|
11
|
+
|
12
|
+
require 'oj'
|
13
|
+
|
14
|
+
Oj.load(STDIN, mode: :compat) do |input|
|
15
|
+
ctx = input["ctx"]
|
16
|
+
a = input["in"]
|
17
|
+
a.map! { |v| v * 3 }
|
18
|
+
out = { "ctx" => ctx, "out" => a }
|
19
|
+
puts Oj.dump(out, mode: :compat, indent: 0)
|
20
|
+
STDOUT.flush
|
21
|
+
end
|
data/test/all_tests.rb
CHANGED
data/test/d2.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
$: << File.dirname(File.dirname(__FILE__)) unless $:.include? File.dirname(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
[ File.dirname(__FILE__),
|
7
|
+
File.join(File.dirname(__FILE__), "../../lib"),
|
8
|
+
File.join(File.dirname(__FILE__), "../../../oj/ext"),
|
9
|
+
File.join(File.dirname(__FILE__), "../../../oj/lib"),
|
10
|
+
].each { |path| $: << path unless $:.include?(path) }
|
11
|
+
|
12
|
+
#input = gets()
|
13
|
+
|
14
|
+
#puts "*** input: #{input}"
|
15
|
+
puts "*** #{`pwd`}"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Operations Workflow in Ruby. This implements a workflow/process flow
|
14
14
|
using multiple task nodes that each have their own queues and execution thread.
|
@@ -31,6 +31,8 @@ files:
|
|
31
31
|
- lib/oflow/actors/merger.rb
|
32
32
|
- lib/oflow/actors/persister.rb
|
33
33
|
- lib/oflow/actors/relay.rb
|
34
|
+
- lib/oflow/actors/shellone.rb
|
35
|
+
- lib/oflow/actors/shellrepeat.rb
|
34
36
|
- lib/oflow/actors/timer.rb
|
35
37
|
- lib/oflow/actors/trigger.rb
|
36
38
|
- lib/oflow/box.rb
|
@@ -50,16 +52,22 @@ files:
|
|
50
52
|
- lib/oflow/test/actorwrap.rb
|
51
53
|
- lib/oflow/tracker.rb
|
52
54
|
- lib/oflow/version.rb
|
55
|
+
- test/actors/bad.rb
|
53
56
|
- test/actors/balancer_test.rb
|
57
|
+
- test/actors/doubler.rb
|
54
58
|
- test/actors/httpserver_test.rb
|
55
59
|
- test/actors/log_test.rb
|
56
60
|
- test/actors/merger_test.rb
|
57
61
|
- test/actors/persister_test.rb
|
62
|
+
- test/actors/shellone_test.rb
|
63
|
+
- test/actors/shellrepeat_test.rb
|
58
64
|
- test/actors/timer_test.rb
|
65
|
+
- test/actors/tripler.rb
|
59
66
|
- test/actorwrap_test.rb
|
60
67
|
- test/all_tests.rb
|
61
68
|
- test/box_test.rb
|
62
69
|
- test/collector.rb
|
70
|
+
- test/d2.rb
|
63
71
|
- test/flow_basic_test.rb
|
64
72
|
- test/flow_cfg_error_test.rb
|
65
73
|
- test/flow_linked_test.rb
|
@@ -92,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
100
|
version: '0'
|
93
101
|
requirements: []
|
94
102
|
rubyforge_project: oflow
|
95
|
-
rubygems_version: 2.
|
103
|
+
rubygems_version: 2.4.5
|
96
104
|
signing_key:
|
97
105
|
specification_version: 4
|
98
106
|
summary: Operations Workflow in Ruby
|