standard-procedure-plumbing 0.4.3 → 0.4.4
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/lib/plumbing/actor/async.rb +1 -1
- data/lib/plumbing/actor/inline.rb +1 -1
- data/lib/plumbing/actor/kernel.rb +11 -0
- data/lib/plumbing/actor/threaded.rb +20 -14
- data/lib/plumbing/actor.rb +1 -1
- data/lib/plumbing/config.rb +2 -2
- data/{spec → lib/plumbing/spec}/become_equal_to_matcher.rb +5 -8
- data/lib/plumbing/version.rb +1 -1
- metadata +4 -20
- data/spec/examples/actor_spec.rb +0 -86
- data/spec/examples/await_spec.rb +0 -43
- data/spec/examples/pipe_spec.rb +0 -145
- data/spec/examples/pipeline_spec.rb +0 -89
- data/spec/examples/rubber_duck_spec.rb +0 -109
- data/spec/plumbing/a_pipe.rb +0 -110
- data/spec/plumbing/actor/transporter_spec.rb +0 -159
- data/spec/plumbing/actor_spec.rb +0 -386
- data/spec/plumbing/custom_filter_spec.rb +0 -29
- data/spec/plumbing/filter_spec.rb +0 -32
- data/spec/plumbing/junction_spec.rb +0 -67
- data/spec/plumbing/pipe_spec.rb +0 -31
- data/spec/plumbing/pipeline_spec.rb +0 -208
- data/spec/plumbing/rubber_duck_spec.rb +0 -74
- data/spec/plumbing_spec.rb +0 -7
- data/spec/spec_helper.rb +0 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b9f1970e25364d95a6ec7ad423514cb7b58060eeb756b1a0522f54f8b2cb2b4a
|
|
4
|
+
data.tar.gz: 0e6eaa9583b24265285528f37e23d97109839fadbd7c48486fe621e22b5321a3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4672d2ce39d68ac74325c2c23e87e66e66eb97735d69681c115b0190203d178966283a432566164d4a5624202ec0fb2935af83ff338876b550ff542fc7ff5bdc
|
|
7
|
+
data.tar.gz: 52dfe371b1f12fab3040e3270c496403b06ee6d9331380e630dee481ef90653e939de544f77e177ed9f45378aa08a090e3f48275b66e1dcdd3442c4c9a824f15
|
data/lib/plumbing/actor/async.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require "timeout"
|
|
2
|
+
|
|
1
3
|
module Plumbing
|
|
2
4
|
module Actor
|
|
3
5
|
::Kernel.class_eval do
|
|
@@ -5,6 +7,15 @@ module Plumbing
|
|
|
5
7
|
result = block.call
|
|
6
8
|
result.respond_to?(:value) ? result.send(:value) : result
|
|
7
9
|
end
|
|
10
|
+
|
|
11
|
+
def wait_for timeout = nil, &block
|
|
12
|
+
Timeout.timeout(timeout || Plumbing.config.timeout) do
|
|
13
|
+
loop do
|
|
14
|
+
break if block.call
|
|
15
|
+
sleep 0.1
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
8
19
|
end
|
|
9
20
|
end
|
|
10
21
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "concurrent/array"
|
|
2
2
|
require "concurrent/mvar"
|
|
3
|
+
require "concurrent/scheduled_task"
|
|
3
4
|
require "concurrent/immutable_struct"
|
|
4
5
|
require "concurrent/promises"
|
|
5
6
|
require_relative "transporter"
|
|
@@ -17,7 +18,8 @@ module Plumbing
|
|
|
17
18
|
|
|
18
19
|
# Send the message to the target and wrap the result
|
|
19
20
|
def send_message(message_name, *args, **params, &block)
|
|
20
|
-
|
|
21
|
+
puts "->#{@target.class}##{message_name}(#{args.inspect}, #{params.inspect})\n#{Thread.current.name}" if Plumbing.config.debug
|
|
22
|
+
Message.new(@target, message_name, Plumbing::Actor.transporter.marshal(*args), Plumbing::Actor.transporter.marshal(params).first, block, Concurrent::MVar.new).tap do |message|
|
|
21
23
|
@queue << message
|
|
22
24
|
send_messages
|
|
23
25
|
end
|
|
@@ -28,37 +30,41 @@ module Plumbing
|
|
|
28
30
|
nil
|
|
29
31
|
end
|
|
30
32
|
|
|
31
|
-
def
|
|
33
|
+
def in_context? = @mutex.owned?
|
|
32
34
|
|
|
33
|
-
def stop
|
|
34
|
-
within_actor? ? @queue.clear : @mutex.synchronize { @queue.clear }
|
|
35
|
-
end
|
|
35
|
+
def stop = @queue.clear
|
|
36
36
|
|
|
37
37
|
protected
|
|
38
38
|
|
|
39
|
-
def
|
|
40
|
-
Concurrent::
|
|
41
|
-
@mutex.synchronize(&)
|
|
39
|
+
def in_actor_thread &block
|
|
40
|
+
Concurrent::ScheduledTask.execute(0.1) do
|
|
41
|
+
@mutex.synchronize(&block)
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
private
|
|
46
46
|
|
|
47
47
|
def send_messages
|
|
48
|
-
in_context
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
in_context? ? dispatch_messages : in_actor_thread { dispatch_messages }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def dispatch_messages
|
|
52
|
+
while (message = @queue.shift)
|
|
53
|
+
message.call
|
|
52
54
|
end
|
|
53
55
|
end
|
|
54
56
|
|
|
55
|
-
class Message < Concurrent::ImmutableStruct.new(:target, :message_name, :packed_args, :unsafe_block, :result)
|
|
57
|
+
class Message < Concurrent::ImmutableStruct.new(:target, :message_name, :packed_args, :packed_params, :unsafe_block, :result)
|
|
56
58
|
def call
|
|
57
59
|
args = Plumbing::Actor.transporter.unmarshal(*packed_args)
|
|
58
|
-
|
|
60
|
+
params = Plumbing::Actor.transporter.unmarshal(packed_params)
|
|
61
|
+
puts "=> #{target.class}##{message_name}(#{args.first.inspect}, #{params.first.inspect}, &#{!unsafe_block.nil?})\n#{Thread.current.name}" if Plumbing.config.debug
|
|
62
|
+
value = target.send message_name, *args, **params.first, &unsafe_block
|
|
59
63
|
|
|
60
64
|
result.put Plumbing::Actor.transporter.marshal(value)
|
|
61
65
|
rescue => ex
|
|
66
|
+
puts ex
|
|
67
|
+
puts ex.backtrace
|
|
62
68
|
result.put ex
|
|
63
69
|
end
|
|
64
70
|
|
data/lib/plumbing/actor.rb
CHANGED
data/lib/plumbing/config.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pipes, pipelines, actors and rubber ducks
|
|
2
2
|
module Plumbing
|
|
3
|
-
Config = Data.define :mode, :actor_proxy_classes, :timeout do
|
|
3
|
+
Config = Data.define :mode, :actor_proxy_classes, :timeout, :debug do
|
|
4
4
|
def actor_proxy_class_for target_class
|
|
5
5
|
actor_proxy_classes[target_class]
|
|
6
6
|
end
|
|
@@ -45,7 +45,7 @@ module Plumbing
|
|
|
45
45
|
private_class_method :set_configuration_and_yield
|
|
46
46
|
|
|
47
47
|
def self.configs
|
|
48
|
-
@configs ||= [Config.new(mode: :inline, timeout: 30, actor_proxy_classes: {})]
|
|
48
|
+
@configs ||= [Config.new(mode: :inline, timeout: 30, actor_proxy_classes: {}, debug: false)]
|
|
49
49
|
end
|
|
50
50
|
private_class_method :configs
|
|
51
51
|
end
|
|
@@ -9,15 +9,12 @@ require "rspec/expectations"
|
|
|
9
9
|
#
|
|
10
10
|
RSpec::Matchers.define :become_equal_to do
|
|
11
11
|
match do |expected|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
matched = false
|
|
15
|
-
while (counter < max) && (matched == false)
|
|
16
|
-
sleep 0.1
|
|
17
|
-
counter += 1
|
|
18
|
-
matched = true if (@result = block_arg.call) == expected
|
|
12
|
+
wait_for do
|
|
13
|
+
block_arg.call == expected
|
|
19
14
|
end
|
|
20
|
-
|
|
15
|
+
true
|
|
16
|
+
rescue Timeout::Error
|
|
17
|
+
false
|
|
21
18
|
end
|
|
22
19
|
|
|
23
20
|
failure_message do |expected|
|
data/lib/plumbing/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: standard-procedure-plumbing
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rahoul Baruah
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-09-
|
|
11
|
+
date: 2024-09-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: globalid
|
|
@@ -55,25 +55,9 @@ files:
|
|
|
55
55
|
- lib/plumbing/rubber_duck/module.rb
|
|
56
56
|
- lib/plumbing/rubber_duck/object.rb
|
|
57
57
|
- lib/plumbing/rubber_duck/proxy.rb
|
|
58
|
+
- lib/plumbing/spec/become_equal_to_matcher.rb
|
|
58
59
|
- lib/plumbing/types.rb
|
|
59
60
|
- lib/plumbing/version.rb
|
|
60
|
-
- spec/become_equal_to_matcher.rb
|
|
61
|
-
- spec/examples/actor_spec.rb
|
|
62
|
-
- spec/examples/await_spec.rb
|
|
63
|
-
- spec/examples/pipe_spec.rb
|
|
64
|
-
- spec/examples/pipeline_spec.rb
|
|
65
|
-
- spec/examples/rubber_duck_spec.rb
|
|
66
|
-
- spec/plumbing/a_pipe.rb
|
|
67
|
-
- spec/plumbing/actor/transporter_spec.rb
|
|
68
|
-
- spec/plumbing/actor_spec.rb
|
|
69
|
-
- spec/plumbing/custom_filter_spec.rb
|
|
70
|
-
- spec/plumbing/filter_spec.rb
|
|
71
|
-
- spec/plumbing/junction_spec.rb
|
|
72
|
-
- spec/plumbing/pipe_spec.rb
|
|
73
|
-
- spec/plumbing/pipeline_spec.rb
|
|
74
|
-
- spec/plumbing/rubber_duck_spec.rb
|
|
75
|
-
- spec/plumbing_spec.rb
|
|
76
|
-
- spec/spec_helper.rb
|
|
77
61
|
homepage: https://github.com/standard-procedure/plumbing
|
|
78
62
|
licenses: []
|
|
79
63
|
metadata:
|
|
@@ -96,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
96
80
|
- !ruby/object:Gem::Version
|
|
97
81
|
version: '0'
|
|
98
82
|
requirements: []
|
|
99
|
-
rubygems_version: 3.5.
|
|
83
|
+
rubygems_version: 3.5.17
|
|
100
84
|
signing_key:
|
|
101
85
|
specification_version: 4
|
|
102
86
|
summary: Plumbing - various pipelines for your ruby application
|
data/spec/examples/actor_spec.rb
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
require "plumbing/actor/async"
|
|
3
|
-
require "plumbing/actor/threaded"
|
|
4
|
-
|
|
5
|
-
RSpec.shared_examples "an example actor" do |runs_in_background|
|
|
6
|
-
# standard:disable Lint/ConstantDefinitionInBlock
|
|
7
|
-
class Employee
|
|
8
|
-
include Plumbing::Actor
|
|
9
|
-
async :name, :job_title, :greet_slowly, :promote
|
|
10
|
-
|
|
11
|
-
def initialize(name)
|
|
12
|
-
@name = name
|
|
13
|
-
@job_title = "Sales assistant"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
attr_reader :name, :job_title
|
|
17
|
-
|
|
18
|
-
def promote
|
|
19
|
-
sleep 0.5
|
|
20
|
-
@job_title = "Sales manager"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def greet_slowly
|
|
24
|
-
sleep 0.2
|
|
25
|
-
"H E L L O"
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
# standard:enable Lint/ConstantDefinitionInBlock
|
|
29
|
-
|
|
30
|
-
it "queries an object" do
|
|
31
|
-
@person = Employee.start "Alice"
|
|
32
|
-
|
|
33
|
-
expect(await { @person.name }).to eq "Alice"
|
|
34
|
-
expect(await { @person.job_title }).to eq "Sales assistant"
|
|
35
|
-
|
|
36
|
-
@time = Time.now
|
|
37
|
-
# `greet_slowly` is a query so will block until a response is received
|
|
38
|
-
expect(await { @person.greet_slowly }).to eq "H E L L O"
|
|
39
|
-
expect(Time.now - @time).to be > 0.1
|
|
40
|
-
|
|
41
|
-
@time = Time.now
|
|
42
|
-
# we're not awaiting the result, so this should run in the background (unless we're using inline mode)
|
|
43
|
-
@person.greet_slowly
|
|
44
|
-
|
|
45
|
-
expect(Time.now - @time).to be < 0.1 if runs_in_background
|
|
46
|
-
expect(Time.now - @time).to be > 0.1 if !runs_in_background
|
|
47
|
-
ensure
|
|
48
|
-
@person.stop
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
it "commands an object" do
|
|
52
|
-
@person = Employee.start "Alice"
|
|
53
|
-
@person.promote
|
|
54
|
-
expect(@person.job_title.value).to eq "Sales manager"
|
|
55
|
-
ensure
|
|
56
|
-
@person.stop
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
RSpec.describe "Actor example: " do
|
|
61
|
-
context "inline mode" do
|
|
62
|
-
around :example do |example|
|
|
63
|
-
Plumbing.configure mode: :inline, &example
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
it_behaves_like "an example actor", false
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
context "async mode" do
|
|
70
|
-
around :example do |example|
|
|
71
|
-
Plumbing.configure mode: :async do
|
|
72
|
-
Kernel::Async(&example)
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
it_behaves_like "an example actor", true
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
context "threaded mode" do
|
|
80
|
-
around :example do |example|
|
|
81
|
-
Plumbing.configure mode: :threaded, &example
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it_behaves_like "an example actor", true
|
|
85
|
-
end
|
|
86
|
-
end
|
data/spec/examples/await_spec.rb
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
require "plumbing/actor/async"
|
|
3
|
-
require "plumbing/actor/threaded"
|
|
4
|
-
|
|
5
|
-
RSpec.describe "await" do
|
|
6
|
-
# standard:disable Lint/ConstantDefinitionInBlock
|
|
7
|
-
class Person
|
|
8
|
-
include Plumbing::Actor
|
|
9
|
-
async :name
|
|
10
|
-
def initialize name
|
|
11
|
-
@name = name
|
|
12
|
-
end
|
|
13
|
-
attr_reader :name
|
|
14
|
-
end
|
|
15
|
-
# standard:enable Lint/ConstantDefinitionInBlock
|
|
16
|
-
|
|
17
|
-
[:inline, :async, :threaded].each do |mode|
|
|
18
|
-
context "#{mode} mode" do
|
|
19
|
-
around :example do |example|
|
|
20
|
-
Sync do
|
|
21
|
-
Plumbing.configure mode: mode, &example
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "awaits a result from the actor directly" do
|
|
26
|
-
@person = Person.start "Alice"
|
|
27
|
-
|
|
28
|
-
expect(@person.name.value).to eq "Alice"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it "uses a block to await the result from the actor" do
|
|
32
|
-
@person = Person.start "Alice"
|
|
33
|
-
|
|
34
|
-
expect(await { @person.name }).to eq "Alice"
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it "uses a block to immediately access non-actor objects" do
|
|
38
|
-
@person = "Bob"
|
|
39
|
-
expect(await { @person }).to eq "Bob"
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
data/spec/examples/pipe_spec.rb
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
require "async"
|
|
3
|
-
require "plumbing/actor/async"
|
|
4
|
-
require "plumbing/actor/threaded"
|
|
5
|
-
|
|
6
|
-
RSpec.describe "Pipe examples" do
|
|
7
|
-
it "observes events" do
|
|
8
|
-
@source = Plumbing::Pipe.start
|
|
9
|
-
|
|
10
|
-
@result = []
|
|
11
|
-
@source.add_observer do |event|
|
|
12
|
-
@result << event.type
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
@source.notify "something_happened", message: "But what was it?"
|
|
16
|
-
expect(@result).to eq ["something_happened"]
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it "filters events" do
|
|
20
|
-
@source = Plumbing::Pipe.start
|
|
21
|
-
|
|
22
|
-
@filter = Plumbing::Filter.start source: @source do |event|
|
|
23
|
-
%w[important urgent].include? event.type
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
@result = []
|
|
27
|
-
@filter.add_observer do |event|
|
|
28
|
-
@result << event.type
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
@source.notify "important", message: "ALERT! ALERT!"
|
|
32
|
-
expect(@result).to eq ["important"]
|
|
33
|
-
|
|
34
|
-
@source.notify "unimportant", message: "Nothing to see here"
|
|
35
|
-
expect(@result).to eq ["important"]
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it "allows for custom filters" do
|
|
39
|
-
# standard:disable Lint/ConstantDefinitionInBlock
|
|
40
|
-
class EveryThirdEvent < Plumbing::CustomFilter
|
|
41
|
-
def initialize source:
|
|
42
|
-
super
|
|
43
|
-
@events = []
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def received event
|
|
47
|
-
safely do
|
|
48
|
-
@events << event
|
|
49
|
-
if @events.count >= 3
|
|
50
|
-
@events.clear
|
|
51
|
-
self << event
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
# standard:enable Lint/ConstantDefinitionInBlock
|
|
57
|
-
|
|
58
|
-
@source = Plumbing::Pipe.start
|
|
59
|
-
@filter = EveryThirdEvent.start(source: @source)
|
|
60
|
-
|
|
61
|
-
@result = []
|
|
62
|
-
@filter.add_observer do |event|
|
|
63
|
-
@result << event.type
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
1.upto 10 do |i|
|
|
67
|
-
@source.notify i.to_s
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
expect(@result).to eq ["3", "6", "9"]
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "joins multiple source pipes" do
|
|
74
|
-
@first_source = Plumbing::Pipe.start
|
|
75
|
-
@second_source = Plumbing::Pipe.start
|
|
76
|
-
|
|
77
|
-
@junction = Plumbing::Junction.start @first_source, @second_source
|
|
78
|
-
|
|
79
|
-
@result = []
|
|
80
|
-
@junction.add_observer do |event|
|
|
81
|
-
@result << event.type
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
@first_source.notify "one"
|
|
85
|
-
expect(@result).to eq ["one"]
|
|
86
|
-
@second_source.notify "two"
|
|
87
|
-
expect(@result).to eq ["one", "two"]
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
it "dispatches events asynchronously using async" do
|
|
91
|
-
Plumbing.configure mode: :async do
|
|
92
|
-
Sync do
|
|
93
|
-
@first_source = Plumbing::Pipe.start
|
|
94
|
-
@second_source = Plumbing::Pipe.start
|
|
95
|
-
@junction = Plumbing::Junction.start @first_source, @second_source
|
|
96
|
-
@filter = Plumbing::Filter.start source: @junction do |event|
|
|
97
|
-
%w[one-one two-two].include? event.type
|
|
98
|
-
end
|
|
99
|
-
@result = []
|
|
100
|
-
@filter.add_observer do |event|
|
|
101
|
-
@result << event.type
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
@first_source.notify "one-one"
|
|
105
|
-
@first_source.notify "one-two"
|
|
106
|
-
@second_source.notify "two-one"
|
|
107
|
-
@second_source.notify "two-two"
|
|
108
|
-
|
|
109
|
-
expect(["one-one", "two-two"]).to become_equal_to { @result }
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
it "dispatches events asynchronously using threads" do
|
|
115
|
-
Plumbing.configure mode: :threaded do
|
|
116
|
-
@result = []
|
|
117
|
-
|
|
118
|
-
@first_source = Plumbing::Pipe.start
|
|
119
|
-
@second_source = Plumbing::Pipe.start
|
|
120
|
-
@junction = Plumbing::Junction.start @first_source, @second_source
|
|
121
|
-
|
|
122
|
-
@filter = Plumbing::Filter.start source: @junction do |event|
|
|
123
|
-
%w[one-one two-two].include? event.type
|
|
124
|
-
end
|
|
125
|
-
await do
|
|
126
|
-
@filter.add_observer do |event|
|
|
127
|
-
puts "observing #{event.type}"
|
|
128
|
-
@result << event.type
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
@first_source.notify "one-one"
|
|
133
|
-
@first_source.notify "one-two"
|
|
134
|
-
@second_source.notify "two-one"
|
|
135
|
-
@second_source.notify "two-two"
|
|
136
|
-
|
|
137
|
-
expect(["one-one", "two-two"]).to become_equal_to { @result.sort }
|
|
138
|
-
ensure
|
|
139
|
-
@first_source.shutdown
|
|
140
|
-
@second_source.shutdown
|
|
141
|
-
@junction.shutdown
|
|
142
|
-
@filter.shutdown
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
end
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
require "dry/validation"
|
|
3
|
-
|
|
4
|
-
RSpec.describe "Pipeline examples" do
|
|
5
|
-
it "builds a simple pipeline of operations adding to an array with pre-conditions and post-conditions" do
|
|
6
|
-
# standard:disable Lint/ConstantDefinitionInBlock
|
|
7
|
-
class BuildArray < Plumbing::Pipeline
|
|
8
|
-
perform :add_first
|
|
9
|
-
perform :add_second
|
|
10
|
-
perform :add_third
|
|
11
|
-
|
|
12
|
-
pre_condition :must_be_an_array do |input|
|
|
13
|
-
input.is_a? Array
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
post_condition :must_have_three_elements do |output|
|
|
17
|
-
output.length == 3
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def add_first(input) = input << "first"
|
|
23
|
-
|
|
24
|
-
def add_second(input) = input << "second"
|
|
25
|
-
|
|
26
|
-
def add_third(input) = input << "third"
|
|
27
|
-
end
|
|
28
|
-
# standard:enable Lint/ConstantDefinitionInBlock
|
|
29
|
-
|
|
30
|
-
expect(BuildArray.new.call([])).to eq ["first", "second", "third"]
|
|
31
|
-
expect { BuildArray.new.call(1) }.to raise_error(Plumbing::PreConditionError)
|
|
32
|
-
expect { BuildArray.new.call(["extra element"]) }.to raise_error(Plumbing::PostConditionError)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it "builds a simple pipeline of operations using an external class to implement one of the steps" do
|
|
36
|
-
# standard:disable Lint/ConstantDefinitionInBlock
|
|
37
|
-
class ExternalStep < Plumbing::Pipeline
|
|
38
|
-
perform :add_item_to_array
|
|
39
|
-
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
def add_item_to_array(input) = input << "external"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
class BuildSequenceWithExternalStep < Plumbing::Pipeline
|
|
46
|
-
perform :add_first
|
|
47
|
-
perform :add_second, using: "ExternalStep"
|
|
48
|
-
perform :add_third
|
|
49
|
-
|
|
50
|
-
private
|
|
51
|
-
|
|
52
|
-
def add_first(input) = input << "first"
|
|
53
|
-
|
|
54
|
-
def add_third(input) = input << "third"
|
|
55
|
-
end
|
|
56
|
-
# standard:enable Lint/ConstantDefinitionInBlock
|
|
57
|
-
|
|
58
|
-
expect(BuildSequenceWithExternalStep.new.call([])).to eq ["first", "external", "third"]
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
it "uses a dry-validation contract to test the input parameters" do
|
|
62
|
-
# standard:disable Lint/ConstantDefinitionInBlock
|
|
63
|
-
class SayHello < Plumbing::Pipeline
|
|
64
|
-
validate_with "SayHello::Input"
|
|
65
|
-
perform :say_hello
|
|
66
|
-
|
|
67
|
-
private
|
|
68
|
-
|
|
69
|
-
def say_hello input
|
|
70
|
-
"Hello #{input[:name]} - I will now send a load of annoying marketing messages to #{input[:email]}"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
class Input < Dry::Validation::Contract
|
|
74
|
-
params do
|
|
75
|
-
required(:name).filled(:string)
|
|
76
|
-
required(:email).filled(:string)
|
|
77
|
-
end
|
|
78
|
-
rule :email do
|
|
79
|
-
key.failure("must be a valid email") unless /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.match? value
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
# standard:enable Lint/ConstantDefinitionInBlock
|
|
84
|
-
|
|
85
|
-
SayHello.new.call(name: "Alice", email: "alice@example.com")
|
|
86
|
-
|
|
87
|
-
expect { SayHello.new.call(some: "other data") }.to raise_error(Plumbing::PreConditionError)
|
|
88
|
-
end
|
|
89
|
-
end
|