wisper-compat 4.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 +7 -0
- data/.github/workflows/test.yml +19 -0
- data/.gitignore +20 -0
- data/.rspec +4 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +152 -0
- data/CONTRIBUTING.md +57 -0
- data/Gemfile +10 -0
- data/README.md +358 -0
- data/Rakefile +6 -0
- data/lib/wisper/broadcasters/logger_broadcaster.rb +41 -0
- data/lib/wisper/broadcasters/send_broadcaster.rb +9 -0
- data/lib/wisper/configuration.rb +44 -0
- data/lib/wisper/global_listeners.rb +72 -0
- data/lib/wisper/publisher.rb +89 -0
- data/lib/wisper/registration/block.rb +11 -0
- data/lib/wisper/registration/object.rb +43 -0
- data/lib/wisper/registration/registration.rb +18 -0
- data/lib/wisper/temporary_listeners.rb +41 -0
- data/lib/wisper/value_objects/events.rb +61 -0
- data/lib/wisper/value_objects/prefix.rb +29 -0
- data/lib/wisper/version.rb +3 -0
- data/lib/wisper.rb +65 -0
- data/spec/lib/global_listeners_spec.rb +82 -0
- data/spec/lib/integration_spec.rb +56 -0
- data/spec/lib/simple_example_spec.rb +21 -0
- data/spec/lib/temporary_global_listeners_spec.rb +103 -0
- data/spec/lib/wisper/broadcasters/logger_broadcaster_spec.rb +129 -0
- data/spec/lib/wisper/broadcasters/send_broadcaster_spec.rb +68 -0
- data/spec/lib/wisper/configuration/broadcasters_spec.rb +11 -0
- data/spec/lib/wisper/configuration_spec.rb +36 -0
- data/spec/lib/wisper/publisher_spec.rb +311 -0
- data/spec/lib/wisper/registrations/object_spec.rb +14 -0
- data/spec/lib/wisper/value_objects/events_spec.rb +107 -0
- data/spec/lib/wisper/value_objects/prefix_spec.rb +46 -0
- data/spec/lib/wisper_spec.rb +99 -0
- data/spec/spec_helper.rb +21 -0
- data/wisper-compat.gemspec +29 -0
- metadata +102 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
describe Wisper::TemporaryListeners do
|
2
|
+
let(:listener_1) { double('listener', :to_a => nil) } # [1]
|
3
|
+
let(:listener_2) { double('listener', :to_a => nil) }
|
4
|
+
|
5
|
+
let(:publisher) { publisher_class.new }
|
6
|
+
|
7
|
+
describe '.subscribe' do
|
8
|
+
it 'globally subscribes listener for duration of given block' do
|
9
|
+
|
10
|
+
expect(listener_1).to receive(:success)
|
11
|
+
expect(listener_1).to_not receive(:failure)
|
12
|
+
|
13
|
+
Wisper::TemporaryListeners.subscribe(listener_1) do
|
14
|
+
publisher.instance_eval { broadcast(:success) }
|
15
|
+
end
|
16
|
+
|
17
|
+
publisher.instance_eval { broadcast(:failure) }
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'globally subscribes listeners for duration of given block' do
|
21
|
+
|
22
|
+
expect(listener_1).to receive(:success)
|
23
|
+
expect(listener_1).to_not receive(:failure)
|
24
|
+
|
25
|
+
expect(listener_2).to receive(:success)
|
26
|
+
expect(listener_2).to_not receive(:failure)
|
27
|
+
|
28
|
+
Wisper::TemporaryListeners.subscribe(listener_1, listener_2) do
|
29
|
+
publisher.instance_eval { broadcast(:success) }
|
30
|
+
end
|
31
|
+
|
32
|
+
publisher.instance_eval { broadcast(:failure) }
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'globally subscribes listeners for duration of nested block' do
|
36
|
+
|
37
|
+
expect(listener_1).to receive(:success)
|
38
|
+
expect(listener_1).to receive(:failure)
|
39
|
+
|
40
|
+
expect(listener_2).to receive(:success)
|
41
|
+
expect(listener_2).to_not receive(:failure)
|
42
|
+
|
43
|
+
Wisper::TemporaryListeners.subscribe(listener_1) do
|
44
|
+
Wisper::TemporaryListeners.subscribe(listener_2) do
|
45
|
+
publisher.instance_eval { broadcast(:success) }
|
46
|
+
end
|
47
|
+
publisher.instance_eval { broadcast(:failure) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'clears registrations for the block which exits' do
|
52
|
+
|
53
|
+
# listener_1 is subscribed twice hence it's supposed to get the message twice
|
54
|
+
expect(listener_1).to receive(:success).twice
|
55
|
+
expect(listener_1).to receive(:failure)
|
56
|
+
expect(listener_1).to_not receive(:ignored)
|
57
|
+
|
58
|
+
expect(listener_2).to receive(:success)
|
59
|
+
expect(listener_2).to_not receive(:failure)
|
60
|
+
expect(listener_2).to_not receive(:ignored)
|
61
|
+
|
62
|
+
Wisper::TemporaryListeners.subscribe(listener_1) do
|
63
|
+
Wisper::TemporaryListeners.subscribe(listener_1, listener_2) do
|
64
|
+
publisher.instance_eval { broadcast(:success) }
|
65
|
+
end
|
66
|
+
publisher.instance_eval { broadcast(:failure) }
|
67
|
+
end
|
68
|
+
publisher.instance_eval { broadcast(:ignored) }
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'is thread safe' do
|
72
|
+
num_threads = 20
|
73
|
+
(1..num_threads).to_a.map do
|
74
|
+
Thread.new do
|
75
|
+
Wisper::TemporaryListeners.registrations << Object.new
|
76
|
+
expect(Wisper::TemporaryListeners.registrations.size).to eq 1
|
77
|
+
end
|
78
|
+
end.each(&:join)
|
79
|
+
|
80
|
+
expect(Wisper::TemporaryListeners.registrations).to be_empty
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'clears registrations when an exception occurs' do
|
84
|
+
MyError = Class.new(StandardError)
|
85
|
+
|
86
|
+
begin
|
87
|
+
Wisper::TemporaryListeners.subscribe(listener_1) do
|
88
|
+
raise MyError
|
89
|
+
end
|
90
|
+
rescue MyError
|
91
|
+
end
|
92
|
+
|
93
|
+
expect(Wisper::TemporaryListeners.registrations).to be_empty
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'returns self' do
|
97
|
+
expect(Wisper::TemporaryListeners.subscribe {}).to be_an_instance_of(Wisper::TemporaryListeners)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# [1] stubbing `to_a` prevents `Double "listener" received unexpected message
|
103
|
+
# :to_a with (no args)` on MRI 1.9.2 when a double is passed to `Array()`.
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module Wisper
|
2
|
+
module Broadcasters
|
3
|
+
|
4
|
+
describe LoggerBroadcaster do
|
5
|
+
|
6
|
+
describe 'integration tests:' do
|
7
|
+
let(:publisher) { publisher_class.new }
|
8
|
+
let(:listener) { double }
|
9
|
+
let(:logger) { double.as_null_object }
|
10
|
+
|
11
|
+
context 'with only positional arguments' do
|
12
|
+
it 'broadcasts the event to the listener' do
|
13
|
+
publisher.subscribe(listener, :broadcaster => LoggerBroadcaster.new(logger, Wisper::Broadcasters::SendBroadcaster.new))
|
14
|
+
if RUBY_VERSION < '3.0'
|
15
|
+
# Ruby 2.7 receives **{} as a positional argument
|
16
|
+
expect(listener).to receive(:it_happened).with(1, 2, {})
|
17
|
+
else
|
18
|
+
# Ruby 3.0 doesn't pass **empty_hash
|
19
|
+
expect(listener).to receive(:it_happened).with(1, 2)
|
20
|
+
end
|
21
|
+
publisher.send(:broadcast, :it_happened, 1, 2)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with only keyword arguments' do
|
26
|
+
it 'broadcasts the event to the listener' do
|
27
|
+
publisher.subscribe(listener, :broadcaster => LoggerBroadcaster.new(logger, Wisper::Broadcasters::SendBroadcaster.new))
|
28
|
+
expect(listener).to receive(:it_happened).with(key: 'value')
|
29
|
+
publisher.send(:broadcast, :it_happened, key: 'value')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with positional and keyword arguments' do
|
34
|
+
it 'broadcasts the event to the listener' do
|
35
|
+
publisher.subscribe(listener, :broadcaster => LoggerBroadcaster.new(logger, Wisper::Broadcasters::SendBroadcaster.new))
|
36
|
+
expect(listener).to receive(:it_happened).with(1, 2, key: 'value')
|
37
|
+
publisher.send(:broadcast, :it_happened, 1, 2, key: 'value')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'unit tests:' do
|
43
|
+
let(:publisher) { classy_double('Publisher', id: 1) }
|
44
|
+
let(:listener) { classy_double('Listener', id: 2) }
|
45
|
+
let(:logger) { double('Logger').as_null_object }
|
46
|
+
let(:broadcaster) { double('Broadcaster').as_null_object }
|
47
|
+
let(:event) { 'thing_created' }
|
48
|
+
|
49
|
+
subject { LoggerBroadcaster.new(logger, broadcaster) }
|
50
|
+
|
51
|
+
describe '#broadcast' do
|
52
|
+
context 'without arguments' do
|
53
|
+
let(:args) { [] }
|
54
|
+
let(:kwargs) { {} }
|
55
|
+
|
56
|
+
it 'logs published event' do
|
57
|
+
expect(logger).to receive(:info).with('[WISPER] Publisher#1 published thing_created to Listener#2 with no arguments and no keyword arguments')
|
58
|
+
subject.broadcast(listener, publisher, event, *args, **kwargs)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'delegates broadcast to a given broadcaster' do
|
62
|
+
expect(broadcaster).to receive(:broadcast).with(listener, publisher, event, *args, **kwargs)
|
63
|
+
subject.broadcast(listener, publisher, event, *args, **kwargs)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with arguments' do
|
68
|
+
let(:args) { [arg_double(id: 3), arg_double(id: 4)] }
|
69
|
+
let(:kwargs) { {x: :y} }
|
70
|
+
|
71
|
+
it 'logs published event and arguments' do
|
72
|
+
expect(logger).to receive(:info).with("[WISPER] Publisher#1 published thing_created to Listener#2 with Argument#3, Argument#4 and keyword arguments {:x=>:y}")
|
73
|
+
subject.broadcast(listener, publisher, event, *args, **kwargs)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'delegates broadcast to a given broadcaster' do
|
77
|
+
expect(broadcaster).to receive(:broadcast).with(listener, publisher, event, *args, **kwargs)
|
78
|
+
subject.broadcast(listener, publisher, event, *args, **kwargs)
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when argument is a hash' do
|
82
|
+
let(:args) { [hash] }
|
83
|
+
let(:hash) { {key: 'value'} }
|
84
|
+
let(:kwargs) { {x: :y} }
|
85
|
+
|
86
|
+
it 'logs published event and arguments' do
|
87
|
+
expect(logger).to receive(:info).with("[WISPER] Publisher#1 published thing_created to Listener#2 with Hash##{hash.object_id}: #{hash.inspect} and keyword arguments {:x=>:y}")
|
88
|
+
subject.broadcast(listener, publisher, event, *args, **kwargs)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when argument is an integer' do
|
93
|
+
let(:args) { [number] }
|
94
|
+
let(:number) { 10 }
|
95
|
+
|
96
|
+
it 'logs published event and arguments' do
|
97
|
+
expect(logger).to receive(:info).with("[WISPER] Publisher#1 published thing_created to Listener#2 with #{number.class.name}##{number.object_id}: 10 and keyword arguments {:x=>:y}")
|
98
|
+
subject.broadcast(listener, publisher, event, *args, **kwargs)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when only keyword arguments are present' do
|
103
|
+
let(:args) { [] }
|
104
|
+
|
105
|
+
it 'logs published event and arguments' do
|
106
|
+
expect(logger).to receive(:info).with("[WISPER] Publisher#1 published thing_created to Listener#2 with no arguments and keyword arguments {:x=>:y}")
|
107
|
+
subject.broadcast(listener, publisher, event, *args, **kwargs)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
# provides a way to specify `double.class.name` easily
|
115
|
+
def classy_double(klass, options)
|
116
|
+
double(klass, options.merge(class: double_class(klass)))
|
117
|
+
end
|
118
|
+
|
119
|
+
def arg_double(options)
|
120
|
+
classy_double('Argument', options)
|
121
|
+
end
|
122
|
+
|
123
|
+
def double_class(name)
|
124
|
+
double(name: name)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Wisper
|
2
|
+
module Broadcasters
|
3
|
+
describe SendBroadcaster do
|
4
|
+
let(:listener) { double('listener') }
|
5
|
+
let(:event) { 'thing_created' }
|
6
|
+
|
7
|
+
describe '#broadcast' do
|
8
|
+
context 'without arguments' do
|
9
|
+
it 'sends event to listener without any arguments' do
|
10
|
+
if RUBY_VERSION < '3.0'
|
11
|
+
expect(listener).to receive(event).with({})
|
12
|
+
else
|
13
|
+
expect(listener).to receive(event).with(no_args)
|
14
|
+
end
|
15
|
+
subject.broadcast(listener, anything, event)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with empty arguments' do
|
20
|
+
let(:args) { [] }
|
21
|
+
|
22
|
+
it 'sends event to listener without any arguments' do
|
23
|
+
if RUBY_VERSION < '3.0'
|
24
|
+
expect(listener).to receive(event).with({})
|
25
|
+
else
|
26
|
+
expect(listener).to receive(event).with(no_args)
|
27
|
+
end
|
28
|
+
subject.broadcast(listener, anything, event, *args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with arguments' do
|
33
|
+
context 'with only positional arguments' do
|
34
|
+
let(:args) { [1,2,3] }
|
35
|
+
|
36
|
+
it 'sends event to listener with arguments' do
|
37
|
+
if RUBY_VERSION < '3.0'
|
38
|
+
expect(listener).to receive(event).with(1, 2, 3, {})
|
39
|
+
else
|
40
|
+
expect(listener).to receive(event).with(1, 2, 3)
|
41
|
+
end
|
42
|
+
subject.broadcast(listener, anything, event, *args)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'with only keyword arguments' do
|
47
|
+
let(:kwargs) { { key: 'value' } }
|
48
|
+
|
49
|
+
it 'sends event to listener with arguments' do
|
50
|
+
expect(listener).to receive(event).with({key: 'value'})
|
51
|
+
subject.broadcast(listener, anything, event, **kwargs)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with positional and keyword arguments' do
|
56
|
+
let(:args) { [1,2,3] }
|
57
|
+
let(:kwargs) { { key: 'value' } }
|
58
|
+
|
59
|
+
it 'sends event to listener with arguments' do
|
60
|
+
expect(listener).to receive(event).with(1,2,3, {key: 'value'})
|
61
|
+
subject.broadcast(listener, anything, event, *args, **kwargs)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Wisper
|
2
|
+
describe Configuration do
|
3
|
+
describe 'broadcasters' do
|
4
|
+
let(:broadcaster) { double }
|
5
|
+
let(:key) { :default }
|
6
|
+
|
7
|
+
it '#broadcasters returns empty collection' do
|
8
|
+
expect(subject.broadcasters).to be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#broadcaster' do
|
12
|
+
it 'adds given broadcaster' do
|
13
|
+
subject.broadcaster(key, broadcaster)
|
14
|
+
expect(subject.broadcasters).to include key
|
15
|
+
expect(subject.broadcasters[key]).to eql broadcaster
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns the configuration' do
|
19
|
+
expect(subject.broadcaster(key, broadcaster)).to eq subject
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#default_prefix=' do
|
25
|
+
let(:prefix_class) { ValueObjects::Prefix }
|
26
|
+
let(:default_value) { double }
|
27
|
+
|
28
|
+
before { allow(prefix_class).to receive(:default=) }
|
29
|
+
|
30
|
+
it 'sets the default value for prefixes' do
|
31
|
+
expect(prefix_class).to receive(:default=).with(default_value)
|
32
|
+
subject.default_prefix = default_value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
describe Wisper::Publisher do
|
2
|
+
let(:listener) { double('listener') }
|
3
|
+
let(:publisher) { publisher_class.new }
|
4
|
+
|
5
|
+
describe '.subscribe' do
|
6
|
+
it 'subscribes given listener to all published events' do
|
7
|
+
expect(listener).to receive(:this_happened)
|
8
|
+
expect(listener).to receive(:so_did_this)
|
9
|
+
|
10
|
+
publisher.subscribe(listener)
|
11
|
+
|
12
|
+
publisher.send(:broadcast, 'this_happened')
|
13
|
+
publisher.send(:broadcast, 'so_did_this')
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ':on argument' do
|
17
|
+
before do
|
18
|
+
allow(listener).to receive(:something_a_happened)
|
19
|
+
allow(listener).to receive(:and_this)
|
20
|
+
allow(listener).to receive(:so_did_this)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'given a string' do
|
24
|
+
it 'subscribes listener to an event' do
|
25
|
+
expect(listener).to receive(:this_happened)
|
26
|
+
expect(listener).not_to receive(:so_did_this)
|
27
|
+
|
28
|
+
publisher.subscribe(listener, on: 'this_happened')
|
29
|
+
|
30
|
+
publisher.send(:broadcast, 'this_happened')
|
31
|
+
publisher.send(:broadcast, 'so_did_this')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'given a symbol' do
|
36
|
+
it 'subscribes listener to an event' do
|
37
|
+
expect(listener).to receive(:this_happened)
|
38
|
+
expect(listener).not_to receive(:so_did_this)
|
39
|
+
|
40
|
+
publisher.subscribe(listener, on: :this_happened)
|
41
|
+
|
42
|
+
publisher.send(:broadcast, 'this_happened')
|
43
|
+
publisher.send(:broadcast, 'so_did_this')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'given an array' do
|
48
|
+
it 'subscribes listener to events' do
|
49
|
+
expect(listener).to receive(:this_happened)
|
50
|
+
expect(listener).to receive(:and_this)
|
51
|
+
expect(listener).not_to receive(:so_did_this)
|
52
|
+
|
53
|
+
publisher.subscribe(listener, on: ['this_happened', 'and_this'])
|
54
|
+
|
55
|
+
publisher.send(:broadcast, 'this_happened')
|
56
|
+
publisher.send(:broadcast, 'so_did_this')
|
57
|
+
publisher.send(:broadcast, 'and_this')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'given a regex' do
|
62
|
+
it 'subscribes listener to matching events' do
|
63
|
+
expect(listener).to receive(:something_a_happened)
|
64
|
+
expect(listener).not_to receive(:so_did_this)
|
65
|
+
|
66
|
+
publisher.subscribe(listener, on: /something_._happened/)
|
67
|
+
|
68
|
+
publisher.send(:broadcast, 'something_a_happened')
|
69
|
+
publisher.send(:broadcast, 'so_did_this')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'given an unsupported argument' do
|
74
|
+
it 'raises an error' do
|
75
|
+
publisher.subscribe(listener, on: Object.new)
|
76
|
+
expect { publisher.send(:broadcast, 'something_a_happened') }.to raise_error(ArgumentError)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe ':with argument' do
|
82
|
+
it 'sets method to call listener with on event' do
|
83
|
+
expect(listener).to receive(:different_method).twice
|
84
|
+
|
85
|
+
publisher.subscribe(listener, :with => :different_method)
|
86
|
+
|
87
|
+
publisher.send(:broadcast, 'this_happened')
|
88
|
+
publisher.send(:broadcast, 'so_did_this')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe ':prefix argument' do
|
93
|
+
it 'prefixes broadcast events with given symbol' do
|
94
|
+
expect(listener).to receive(:after_it_happened)
|
95
|
+
expect(listener).not_to receive(:it_happened)
|
96
|
+
|
97
|
+
publisher.subscribe(listener, :prefix => :after)
|
98
|
+
|
99
|
+
publisher.send(:broadcast, 'it_happened')
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'prefixes broadcast events with "on" when given true' do
|
103
|
+
expect(listener).to receive(:on_it_happened)
|
104
|
+
expect(listener).not_to receive(:it_happened)
|
105
|
+
|
106
|
+
publisher.subscribe(listener, :prefix => true)
|
107
|
+
|
108
|
+
publisher.send(:broadcast, 'it_happened')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe ':scope argument' do
|
113
|
+
let(:listener_1) { double('Listener') }
|
114
|
+
let(:listener_2) { double('Listener') }
|
115
|
+
|
116
|
+
it 'scopes listener to given class' do
|
117
|
+
expect(listener_1).to receive(:it_happended)
|
118
|
+
expect(listener_2).not_to receive(:it_happended)
|
119
|
+
publisher.subscribe(listener_1, :scope => publisher.class)
|
120
|
+
publisher.subscribe(listener_2, :scope => Class.new)
|
121
|
+
publisher.send(:broadcast, 'it_happended')
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'scopes listener to given class string' do
|
125
|
+
expect(listener_1).to receive(:it_happended)
|
126
|
+
expect(listener_2).not_to receive(:it_happended)
|
127
|
+
publisher.subscribe(listener_1, :scope => publisher.class.to_s)
|
128
|
+
publisher.subscribe(listener_2, :scope => Class.new.to_s)
|
129
|
+
publisher.send(:broadcast, 'it_happended')
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'includes all subclasses of given class' do
|
133
|
+
publisher_super_klass = publisher_class
|
134
|
+
publisher_sub_klass = Class.new(publisher_super_klass)
|
135
|
+
|
136
|
+
listener = double('Listener')
|
137
|
+
expect(listener).to receive(:it_happended).once
|
138
|
+
|
139
|
+
publisher = publisher_sub_klass.new
|
140
|
+
|
141
|
+
publisher.subscribe(listener, :scope => publisher_super_klass)
|
142
|
+
publisher.send(:broadcast, 'it_happended')
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe ':broadcaster argument'do
|
147
|
+
let(:broadcaster) { double('broadcaster') }
|
148
|
+
let(:listener) { double('listener') }
|
149
|
+
let(:event_name) { 'it_happened' }
|
150
|
+
|
151
|
+
before do
|
152
|
+
Wisper.configuration.broadcasters.clear
|
153
|
+
allow(listener).to receive(event_name)
|
154
|
+
allow(broadcaster).to receive(:broadcast)
|
155
|
+
end
|
156
|
+
|
157
|
+
after { Wisper.setup } # restore default configuration
|
158
|
+
|
159
|
+
it 'given an object which responds_to broadcast it uses object' do
|
160
|
+
publisher.subscribe(listener, broadcaster: broadcaster)
|
161
|
+
expect(broadcaster).to receive('broadcast')
|
162
|
+
publisher.send(:broadcast, event_name)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'given a key it uses a configured broadcaster' do
|
166
|
+
Wisper.configure { |c| c.broadcaster(:foobar, broadcaster) }
|
167
|
+
publisher.subscribe(listener, broadcaster: :foobar)
|
168
|
+
expect(broadcaster).to receive('broadcast')
|
169
|
+
publisher.send(:broadcast, event_name)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'given an unknown key it raises error' do
|
173
|
+
expect { publisher.subscribe(listener, broadcaster: :foobar) }.to raise_error(KeyError, /broadcaster not found/)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'given nothing it uses the default broadcaster' do
|
177
|
+
Wisper.configure { |c| c.broadcaster(:default, broadcaster) }
|
178
|
+
publisher.subscribe(listener)
|
179
|
+
expect(broadcaster).to receive('broadcast')
|
180
|
+
publisher.send(:broadcast, event_name)
|
181
|
+
end
|
182
|
+
|
183
|
+
describe 'async alias' do
|
184
|
+
it 'given an object which responds_to broadcast it uses object' do
|
185
|
+
publisher.subscribe(listener, async: broadcaster)
|
186
|
+
expect(broadcaster).to receive('broadcast')
|
187
|
+
publisher.send(:broadcast, event_name)
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'given true it uses configured async broadcaster' do
|
191
|
+
Wisper.configure { |c| c.broadcaster(:async, broadcaster) }
|
192
|
+
publisher.subscribe(listener, async: true)
|
193
|
+
expect(broadcaster).to receive('broadcast')
|
194
|
+
publisher.send(:broadcast, event_name)
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'given false it uses configured default broadcaster' do
|
198
|
+
Wisper.configure { |c| c.broadcaster(:default, broadcaster) }
|
199
|
+
publisher.subscribe(listener, async: false)
|
200
|
+
expect(broadcaster).to receive('broadcast')
|
201
|
+
publisher.send(:broadcast, event_name)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'returns publisher so methods can be chained' do
|
207
|
+
expect(publisher.subscribe(listener, :on => 'so_did_this')).to \
|
208
|
+
eq publisher
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'is aliased to .subscribe' do
|
212
|
+
expect(publisher).to respond_to(:subscribe)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'raises a helpful error if trying to pass a block' do
|
216
|
+
invalid = ->{
|
217
|
+
publisher.subscribe(:success) do
|
218
|
+
puts
|
219
|
+
end
|
220
|
+
}
|
221
|
+
expect{ invalid.call }.to raise_error(ArgumentError)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe '.on' do
|
226
|
+
it 'returns publisher so methods can be chained' do
|
227
|
+
expect(publisher.on('this_thing_happened') {}).to eq publisher
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'raise an error if no events given' do
|
231
|
+
expect { publisher.on() {} }.to raise_error(ArgumentError)
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'raises an error of no block given' do
|
235
|
+
expect { publisher.on(:something) }.to raise_error(ArgumentError)
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'returns publisher so methods can be chained' do
|
239
|
+
expect(publisher.on(:foo) {}).to eq publisher
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe '.broadcast' do
|
244
|
+
|
245
|
+
it 'does not publish events which cannot be responded to' do
|
246
|
+
expect(listener).not_to receive(:so_did_this)
|
247
|
+
allow(listener).to receive(:respond_to?).and_return(false)
|
248
|
+
|
249
|
+
publisher.subscribe(listener, :on => 'so_did_this')
|
250
|
+
|
251
|
+
publisher.send(:broadcast, 'so_did_this')
|
252
|
+
end
|
253
|
+
|
254
|
+
describe ':event argument' do
|
255
|
+
it 'is indifferent to string and symbol' do
|
256
|
+
expect(listener).to receive(:this_happened).twice
|
257
|
+
|
258
|
+
publisher.subscribe(listener)
|
259
|
+
|
260
|
+
publisher.send(:broadcast, 'this_happened')
|
261
|
+
publisher.send(:broadcast, :this_happened)
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'is indifferent to dasherized and underscored strings' do
|
265
|
+
expect(listener).to receive(:this_happened).twice
|
266
|
+
|
267
|
+
publisher.subscribe(listener)
|
268
|
+
|
269
|
+
publisher.send(:broadcast, 'this_happened')
|
270
|
+
publisher.send(:broadcast, 'this-happened')
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'returns publisher' do
|
275
|
+
expect(publisher.send(:broadcast, :foo)).to eq publisher
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'is not public' do
|
279
|
+
expect(publisher).not_to respond_to(:broadcast)
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'is alised as .publish' do
|
283
|
+
expect(publisher.method(:broadcast)).to eq publisher.method(:publish)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
describe '.listeners' do
|
288
|
+
it 'returns an immutable collection' do
|
289
|
+
expect(publisher.listeners).to be_frozen
|
290
|
+
expect { publisher.listeners << listener }.to raise_error(RuntimeError)
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'returns local listeners' do
|
294
|
+
publisher.subscribe(listener)
|
295
|
+
expect(publisher.listeners).to eq [listener]
|
296
|
+
expect(publisher.listeners.size).to eq 1
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe '#subscribe' do
|
301
|
+
let(:publisher_klass_1) { publisher_class }
|
302
|
+
let(:publisher_klass_2) { publisher_class }
|
303
|
+
|
304
|
+
it 'subscribes listener to all instances of publisher' do
|
305
|
+
publisher_klass_1.subscribe(listener)
|
306
|
+
expect(listener).to receive(:it_happened).once
|
307
|
+
publisher_klass_1.new.send(:broadcast, 'it_happened')
|
308
|
+
publisher_klass_2.new.send(:broadcast, 'it_happened')
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
describe Wisper::ObjectRegistration do
|
2
|
+
|
3
|
+
describe 'broadcaster' do
|
4
|
+
it 'defaults to SendBroadcaster' do
|
5
|
+
subject = Wisper::ObjectRegistration.new(double('listener'))
|
6
|
+
expect(subject.broadcaster).to be_instance_of(Wisper::Broadcasters::SendBroadcaster)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'default is lazily evaluated' do
|
10
|
+
expect(Wisper::Broadcasters::SendBroadcaster).to_not receive :new
|
11
|
+
Wisper::ObjectRegistration.new(double('listener'), broadcaster: double('DifferentBroadcaster').as_null_object)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|