oflow 0.8.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|