standard-procedure-plumbing 0.3.1 → 0.3.2
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/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
|