standard-procedure-plumbing 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/plumbing/version.rb +1 -1
- data/spec/become_equal_to_matcher.rb +25 -0
- data/spec/examples/pipe_spec.rb +109 -0
- data/spec/examples/pipeline_spec.rb +89 -0
- data/spec/examples/rubber_duck_spec.rb +26 -0
- data/spec/examples/valve_spec.rb +88 -0
- data/spec/plumbing/a_pipe.rb +106 -0
- data/spec/plumbing/custom_filter_spec.rb +29 -0
- data/spec/plumbing/filter_spec.rb +32 -0
- data/spec/plumbing/junction_spec.rb +67 -0
- data/spec/plumbing/pipe_spec.rb +23 -0
- data/spec/plumbing/pipeline_spec.rb +208 -0
- data/spec/plumbing/rubber_duck_spec.rb +76 -0
- data/spec/plumbing/valve_spec.rb +167 -0
- data/spec/plumbing_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- metadata +17 -18
- data/.rspec +0 -3
- data/.rubocop.yml +0 -24
- data/.solargraph.yml +0 -32
- data/.standard.yml +0 -9
- data/.vscode/tasks.json +0 -11
- data/CHANGELOG.md +0 -40
- data/CODE_OF_CONDUCT.md +0 -5
- data/LICENSE +0 -504
- data/checksums/standard-procedure-plumbing-0.1.1.gem.sha512 +0 -1
- data/checksums/standard-procedure-plumbing-0.1.2.gem.sha512 +0 -1
- data/checksums/standard-procedure-plumbing-0.2.0.gem.sha512 +0 -1
- data/checksums/standard-procedure-plumbing-0.2.1.gem.sha512 +0 -1
- data/checksums/standard-procedure-plumbing-0.2.2.gem.sha512 +0 -1
- data/checksums/standard-procedure-plumbing-0.3.0.gem.sha512 +0 -1
- data/checksums/standard-procedure-plumbing-0.3.1.gem.sha512 +0 -1
- data/sig/plumbing.rbs +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54681502a7df050136406e706c4fd6b9d9bffea81e44c151e969379e6803c532
|
4
|
+
data.tar.gz: ed03cbc9476d43822792fd6a4788b0c2e6c629545056063342f15c0861dc7dd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1387fdd83a547157541f444ccf2dcb9465c261616f424dc530ef4c9c13dda52214c21c4d50c99eb825e4827268f4892d62a29d212af9be21bc5bd65dd83422a4
|
7
|
+
data.tar.gz: c0dcbde3271e4d34cd41d16bda9c488ee40bd838ac0f006fd46bd23eb2c0c1cc4ea18d86236de1d8e87f6b5b97fc5dc728bedbd5a3e354fa09886094866404c9
|
data/lib/plumbing/version.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "rspec/expectations"
|
2
|
+
|
3
|
+
# Custom matcher that repeatedly evaluates the block until it matches the expected value or 5 seconds have elapsed
|
4
|
+
#
|
5
|
+
# This allows asynchronous operations to be tested in a synchronous manner with a timeout
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
# expect("Hello").to become_equal_to { subject.greeting }
|
9
|
+
#
|
10
|
+
RSpec::Matchers.define :become_equal_to do
|
11
|
+
match do |expected|
|
12
|
+
counter = 0
|
13
|
+
matched = false
|
14
|
+
while (counter < 50) && (matched == false)
|
15
|
+
matched = true if (@result = block_arg.call) == expected
|
16
|
+
sleep 0.1
|
17
|
+
counter += 1
|
18
|
+
end
|
19
|
+
matched
|
20
|
+
end
|
21
|
+
|
22
|
+
failure_message do |expected|
|
23
|
+
"expected block to return #{expected} but was #{@result} after timeout expired"
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "async"
|
3
|
+
|
4
|
+
RSpec.describe "Pipe examples" do
|
5
|
+
it "observes events" do
|
6
|
+
@source = Plumbing::Pipe.start
|
7
|
+
|
8
|
+
@result = []
|
9
|
+
@observer = @source.add_observer do |event|
|
10
|
+
@result << event.type
|
11
|
+
end
|
12
|
+
|
13
|
+
@source.notify "something_happened", message: "But what was it?"
|
14
|
+
expect(@result).to eq ["something_happened"]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "filters events" do
|
18
|
+
@source = Plumbing::Pipe.start
|
19
|
+
|
20
|
+
@filter = Plumbing::Filter.start source: @source do |event|
|
21
|
+
%w[important urgent].include? event.type
|
22
|
+
end
|
23
|
+
|
24
|
+
@result = []
|
25
|
+
@observer = @filter.add_observer do |event|
|
26
|
+
@result << event.type
|
27
|
+
end
|
28
|
+
|
29
|
+
@source.notify "important", message: "ALERT! ALERT!"
|
30
|
+
expect(@result).to eq ["important"]
|
31
|
+
|
32
|
+
@source.notify "unimportant", message: "Nothing to see here"
|
33
|
+
expect(@result).to eq ["important"]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "allows for custom filters" do
|
37
|
+
# standard:disable Lint/ConstantDefinitionInBlock
|
38
|
+
class EveryThirdEvent < Plumbing::CustomFilter
|
39
|
+
def initialize source:
|
40
|
+
super
|
41
|
+
@events = []
|
42
|
+
end
|
43
|
+
|
44
|
+
def received event
|
45
|
+
@events << event
|
46
|
+
if @events.count >= 3
|
47
|
+
@events.clear
|
48
|
+
self << event
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
# standard:enable Lint/ConstantDefinitionInBlock
|
53
|
+
|
54
|
+
@source = Plumbing::Pipe.start
|
55
|
+
@filter = EveryThirdEvent.new(source: @source)
|
56
|
+
|
57
|
+
@result = []
|
58
|
+
@observer = @filter.add_observer do |event|
|
59
|
+
@result << event.type
|
60
|
+
end
|
61
|
+
|
62
|
+
1.upto 10 do |i|
|
63
|
+
@source.notify i.to_s
|
64
|
+
end
|
65
|
+
|
66
|
+
expect(@result).to eq ["3", "6", "9"]
|
67
|
+
end
|
68
|
+
|
69
|
+
it "joins multiple source pipes" do
|
70
|
+
@first_source = Plumbing::Pipe.start
|
71
|
+
@second_source = Plumbing::Pipe.start
|
72
|
+
|
73
|
+
@junction = Plumbing::Junction.start @first_source, @second_source
|
74
|
+
|
75
|
+
@result = []
|
76
|
+
@observer = @junction.add_observer do |event|
|
77
|
+
@result << event.type
|
78
|
+
end
|
79
|
+
|
80
|
+
@first_source.notify "one"
|
81
|
+
expect(@result).to eq ["one"]
|
82
|
+
@second_source.notify "two"
|
83
|
+
expect(@result).to eq ["one", "two"]
|
84
|
+
end
|
85
|
+
|
86
|
+
it "dispatches events asynchronously using fibers" do
|
87
|
+
Plumbing.configure mode: :async do
|
88
|
+
Sync do
|
89
|
+
@first_source = Plumbing::Pipe.start
|
90
|
+
@second_source = Plumbing::Pipe.start
|
91
|
+
@junction = Plumbing::Junction.start @first_source, @second_source
|
92
|
+
@filter = Plumbing::Filter.start source: @junction do |event|
|
93
|
+
%w[one-one two-two].include? event.type
|
94
|
+
end
|
95
|
+
@result = []
|
96
|
+
@filter.add_observer do |event|
|
97
|
+
@result << event.type
|
98
|
+
end
|
99
|
+
|
100
|
+
@first_source.notify "one-one"
|
101
|
+
@first_source.notify "one-two"
|
102
|
+
@second_source.notify "two-one"
|
103
|
+
@second_source.notify "two-two"
|
104
|
+
|
105
|
+
expect(["one-one", "two-two"]).to become_equal_to { @result }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,89 @@
|
|
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
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe "Rubber Duck examples" do
|
4
|
+
it "casts objects as duck types" do
|
5
|
+
# standard:disable Lint/ConstantDefinitionInBlock
|
6
|
+
Person = Plumbing::RubberDuck.define :first_name, :last_name, :email
|
7
|
+
LikesFood = Plumbing::RubberDuck.define :favourite_food
|
8
|
+
|
9
|
+
PersonData = Struct.new(:first_name, :last_name, :email, :favourite_food)
|
10
|
+
CarData = Struct.new(:make, :model, :colour)
|
11
|
+
# standard:enable Lint/ConstantDefinitionInBlock
|
12
|
+
|
13
|
+
@porsche_911 = CarData.new "Porsche", "911", "black"
|
14
|
+
expect { @porsche_911.as Person }.to raise_error(TypeError)
|
15
|
+
|
16
|
+
@alice = PersonData.new "Alice", "Aardvark", "alice@example.com", "Ice cream"
|
17
|
+
|
18
|
+
@person = @alice.as Person
|
19
|
+
expect(@person.first_name).to eq "Alice"
|
20
|
+
expect(@person.email).to eq "alice@example.com"
|
21
|
+
expect { @person.favourite_food }.to raise_error(NoMethodError)
|
22
|
+
|
23
|
+
@hungry = @person.as LikesFood
|
24
|
+
expect(@hungry.favourite_food).to eq "Ice cream"
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe "Valve examples" do
|
4
|
+
# standard:disable Lint/ConstantDefinitionInBlock
|
5
|
+
class Employee
|
6
|
+
include Plumbing::Valve
|
7
|
+
query :name, :job_title, :greet_slowly
|
8
|
+
command :promote
|
9
|
+
|
10
|
+
def initialize(name)
|
11
|
+
@name = name
|
12
|
+
@job_title = "Sales assistant"
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :name, :job_title
|
16
|
+
|
17
|
+
def promote
|
18
|
+
sleep 0.5
|
19
|
+
@job_title = "Sales manager"
|
20
|
+
end
|
21
|
+
|
22
|
+
def greet_slowly
|
23
|
+
sleep 0.2
|
24
|
+
"H E L L O"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
# standard:enable Lint/ConstantDefinitionInBlock
|
28
|
+
|
29
|
+
context "inline" do
|
30
|
+
it "queries an object" do
|
31
|
+
Plumbing.configure mode: :inline do
|
32
|
+
@person = Employee.start "Alice"
|
33
|
+
|
34
|
+
expect(@person.name).to eq "Alice"
|
35
|
+
expect(@person.job_title).to eq "Sales assistant"
|
36
|
+
|
37
|
+
@time = Time.now
|
38
|
+
expect(@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
|
+
expect(@person.greet_slowly(ignore_result: true)).to be_nil
|
43
|
+
expect(Time.now - @time).to be > 0.1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "commands an object" do
|
48
|
+
Plumbing.configure mode: :inline do
|
49
|
+
@person = Employee.start "Alice"
|
50
|
+
|
51
|
+
@person.promote
|
52
|
+
|
53
|
+
expect(@person.job_title).to eq "Sales manager"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "async" do
|
59
|
+
around :example do |example|
|
60
|
+
Plumbing.configure mode: :async do
|
61
|
+
Kernel::Async(&example)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "queries an object" do
|
66
|
+
@person = Employee.start "Alice"
|
67
|
+
|
68
|
+
expect(@person.name).to eq "Alice"
|
69
|
+
expect(@person.job_title).to eq "Sales assistant"
|
70
|
+
|
71
|
+
@time = Time.now
|
72
|
+
expect(@person.greet_slowly).to eq "H E L L O"
|
73
|
+
expect(Time.now - @time).to be > 0.1
|
74
|
+
|
75
|
+
@time = Time.now
|
76
|
+
expect(@person.greet_slowly(ignore_result: true)).to be_nil
|
77
|
+
expect(Time.now - @time).to be < 0.1
|
78
|
+
end
|
79
|
+
|
80
|
+
it "commands an object" do
|
81
|
+
@person = Employee.start "Alice"
|
82
|
+
|
83
|
+
@person.promote
|
84
|
+
|
85
|
+
expect(@person.job_title).to eq "Sales manager"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
RSpec.shared_examples "a pipe" do
|
2
|
+
it "adds a block observer" do
|
3
|
+
@pipe = described_class.start
|
4
|
+
@observer = @pipe.add_observer do |event|
|
5
|
+
puts event.type
|
6
|
+
end
|
7
|
+
expect(@pipe.is_observer?(@observer)).to eq true
|
8
|
+
end
|
9
|
+
|
10
|
+
it "adds a callable observer" do
|
11
|
+
@pipe = described_class.start
|
12
|
+
@proc = ->(event) { puts event.type }
|
13
|
+
|
14
|
+
@pipe.add_observer @proc
|
15
|
+
|
16
|
+
expect(@pipe.is_observer?(@proc)).to eq true
|
17
|
+
end
|
18
|
+
|
19
|
+
it "does not allow an observer without a #call method" do
|
20
|
+
@pipe = described_class.start
|
21
|
+
|
22
|
+
expect { @pipe.add_observer(Object.new) }.to raise_error(TypeError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "removes an observer" do
|
26
|
+
@pipe = described_class.start
|
27
|
+
@proc = ->(event) { puts event.type }
|
28
|
+
|
29
|
+
@pipe.remove_observer @proc
|
30
|
+
|
31
|
+
expect(@pipe.is_observer?(@proc)).to eq false
|
32
|
+
end
|
33
|
+
|
34
|
+
it "does not send notifications for objects which are not events" do
|
35
|
+
@pipe = described_class.start
|
36
|
+
@results = []
|
37
|
+
@observer = @pipe.add_observer do |event|
|
38
|
+
@results << event
|
39
|
+
end
|
40
|
+
|
41
|
+
@pipe << Object.new
|
42
|
+
|
43
|
+
sleep 0.5
|
44
|
+
expect(@results).to eq []
|
45
|
+
end
|
46
|
+
|
47
|
+
it "notifies block observers" do
|
48
|
+
@pipe = described_class.start
|
49
|
+
@results = []
|
50
|
+
@observer = @pipe.add_observer do |event|
|
51
|
+
@results << event
|
52
|
+
end
|
53
|
+
|
54
|
+
@first_event = Plumbing::Event.new type: "first_event", data: {test: "event"}
|
55
|
+
@second_event = Plumbing::Event.new type: "second_event", data: {test: "event"}
|
56
|
+
|
57
|
+
@pipe << @first_event
|
58
|
+
expect([@first_event]).to become_equal_to { @results }
|
59
|
+
|
60
|
+
@pipe << @second_event
|
61
|
+
expect([@first_event, @second_event]).to become_equal_to { @results }
|
62
|
+
end
|
63
|
+
|
64
|
+
it "notifies callable observers" do
|
65
|
+
@pipe = described_class.start
|
66
|
+
@results = []
|
67
|
+
@observer = ->(event) { @results << event }
|
68
|
+
@pipe.add_observer @observer
|
69
|
+
|
70
|
+
@first_event = Plumbing::Event.new type: "first_event", data: {test: "event"}
|
71
|
+
@second_event = Plumbing::Event.new type: "second_event", data: {test: "event"}
|
72
|
+
|
73
|
+
@pipe << @first_event
|
74
|
+
expect([@first_event]).to become_equal_to { @results }
|
75
|
+
|
76
|
+
@pipe << @second_event
|
77
|
+
expect([@first_event, @second_event]).to become_equal_to { @results }
|
78
|
+
end
|
79
|
+
|
80
|
+
it "ensures all observers are notified even if an observer raises an exception" do
|
81
|
+
@pipe = described_class.start
|
82
|
+
@results = []
|
83
|
+
@failing_observer = @pipe.add_observer do |event|
|
84
|
+
raise "Failed processing #{event.type}"
|
85
|
+
end
|
86
|
+
@working_observer = @pipe.add_observer do |event|
|
87
|
+
@results << event
|
88
|
+
end
|
89
|
+
|
90
|
+
@event = Plumbing::Event.new type: "event", data: {test: "event"}
|
91
|
+
|
92
|
+
@pipe << @event
|
93
|
+
|
94
|
+
expect([@event]).to become_equal_to { @results }
|
95
|
+
end
|
96
|
+
|
97
|
+
it "shuts down the pipe" do
|
98
|
+
@pipe = described_class.start
|
99
|
+
@observer = ->(event) { @results << event }
|
100
|
+
@pipe.add_observer @observer
|
101
|
+
|
102
|
+
@pipe.shutdown
|
103
|
+
|
104
|
+
expect(@pipe.is_observer?(@observer)).to eq false
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe Plumbing::CustomFilter do
|
4
|
+
it "raises a TypeError if it is connected to a non-Pipe" do
|
5
|
+
@invalid_source = Object.new
|
6
|
+
|
7
|
+
expect { described_class.start source: @invalid_source }.to raise_error(TypeError)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "defines a custom filter" do
|
11
|
+
# standard:disable Lint/ConstantDefinitionInBlock
|
12
|
+
class ReversingFilter < Plumbing::CustomFilter
|
13
|
+
def received(event) = notify event.type.reverse, event.data
|
14
|
+
end
|
15
|
+
# standard:enable Lint/ConstantDefinitionInBlock
|
16
|
+
|
17
|
+
@pipe = Plumbing::Pipe.start
|
18
|
+
@filter = ReversingFilter.new(source: @pipe)
|
19
|
+
@result = []
|
20
|
+
@filter.add_observer do |event|
|
21
|
+
@result << event.type
|
22
|
+
end
|
23
|
+
|
24
|
+
@pipe.notify "hello"
|
25
|
+
@pipe.notify "world"
|
26
|
+
|
27
|
+
expect(@result).to eq ["olleh", "dlrow"]
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe Plumbing::Filter do
|
4
|
+
it "raises a TypeError if it is connected to a non-Pipe" do
|
5
|
+
@invalid_source = Object.new
|
6
|
+
|
7
|
+
expect { described_class.start source: @invalid_source }.to raise_error(TypeError)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "accepts event types" do
|
11
|
+
@pipe = Plumbing::Pipe.start
|
12
|
+
|
13
|
+
@filter = described_class.start source: @pipe do |event|
|
14
|
+
%w[first_type third_type].include? event.type.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
@results = []
|
18
|
+
@filter.add_observer do |event|
|
19
|
+
@results << event
|
20
|
+
end
|
21
|
+
|
22
|
+
@pipe << Plumbing::Event.new(type: "first_type", data: nil)
|
23
|
+
expect(@results.count).to eq 1
|
24
|
+
|
25
|
+
@pipe << Plumbing::Event.new(type: "second_type", data: nil)
|
26
|
+
expect(@results.count).to eq 1
|
27
|
+
|
28
|
+
# Use the alternative syntax
|
29
|
+
@pipe.notify "third_type"
|
30
|
+
expect(@results.count).to eq 2
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe Plumbing::Junction do
|
4
|
+
it "raises a TypeError if it is connected to a non-Pipe" do
|
5
|
+
@sources = [Plumbing::Pipe.start, Object.new, Plumbing::Pipe.start]
|
6
|
+
|
7
|
+
expect { described_class.start(*@sources) }.to raise_error(TypeError)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "publishes events from a single source" do
|
11
|
+
@source = Plumbing::Pipe.start
|
12
|
+
@junction = described_class.start @source
|
13
|
+
|
14
|
+
@results = []
|
15
|
+
@junction.add_observer do |event|
|
16
|
+
@results << event
|
17
|
+
end
|
18
|
+
|
19
|
+
@event = Plumbing::Event.new type: "test_event", data: {test: "event"}
|
20
|
+
@source << @event
|
21
|
+
|
22
|
+
expect([@event]).to become_equal_to { @results }
|
23
|
+
end
|
24
|
+
|
25
|
+
it "publishes events from two sources" do
|
26
|
+
@first_source = Plumbing::Pipe.start
|
27
|
+
@second_source = Plumbing::Pipe.start
|
28
|
+
@junction = described_class.start @first_source, @second_source
|
29
|
+
|
30
|
+
@results = []
|
31
|
+
@junction.add_observer do |event|
|
32
|
+
@results << event
|
33
|
+
end
|
34
|
+
|
35
|
+
@first_event = Plumbing::Event.new type: "test_event", data: {test: "one"}
|
36
|
+
@first_source << @first_event
|
37
|
+
expect([@first_event]).to become_equal_to { @results }
|
38
|
+
|
39
|
+
@second_event = Plumbing::Event.new type: "test_event", data: {test: "two"}
|
40
|
+
@second_source << @second_event
|
41
|
+
expect([@first_event, @second_event]).to become_equal_to { @results }
|
42
|
+
end
|
43
|
+
|
44
|
+
it "publishes events from multiple sources" do
|
45
|
+
@first_source = Plumbing::Pipe.start
|
46
|
+
@second_source = Plumbing::Pipe.start
|
47
|
+
@third_source = Plumbing::Pipe.start
|
48
|
+
@junction = described_class.start @first_source, @second_source, @third_source
|
49
|
+
|
50
|
+
@results = []
|
51
|
+
@junction.add_observer do |event|
|
52
|
+
@results << event
|
53
|
+
end
|
54
|
+
|
55
|
+
@first_event = Plumbing::Event.new type: "test_event", data: {test: "one"}
|
56
|
+
@first_source << @first_event
|
57
|
+
expect([@first_event]).to become_equal_to { @results }
|
58
|
+
|
59
|
+
@second_event = Plumbing::Event.new type: "test_event", data: {test: "two"}
|
60
|
+
@second_source << @second_event
|
61
|
+
expect([@first_event, @second_event]).to become_equal_to { @results }
|
62
|
+
|
63
|
+
@third_event = Plumbing::Event.new type: "test_event", data: {test: "three"}
|
64
|
+
@third_source << @third_event
|
65
|
+
expect([@first_event, @second_event, @third_event]).to become_equal_to { @results }
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require_relative "a_pipe"
|
3
|
+
require "async"
|
4
|
+
|
5
|
+
RSpec.describe Plumbing::Pipe do
|
6
|
+
context "inline" do
|
7
|
+
around :example do |example|
|
8
|
+
Plumbing.configure mode: :inline, &example
|
9
|
+
end
|
10
|
+
|
11
|
+
it_behaves_like "a pipe"
|
12
|
+
end
|
13
|
+
|
14
|
+
context "async" do
|
15
|
+
around :example do |example|
|
16
|
+
Sync do
|
17
|
+
Plumbing.configure mode: :async, &example
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it_behaves_like "a pipe"
|
22
|
+
end
|
23
|
+
end
|