wisper-compat 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +19 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +4 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +152 -0
  7. data/CONTRIBUTING.md +57 -0
  8. data/Gemfile +10 -0
  9. data/README.md +358 -0
  10. data/Rakefile +6 -0
  11. data/lib/wisper/broadcasters/logger_broadcaster.rb +41 -0
  12. data/lib/wisper/broadcasters/send_broadcaster.rb +9 -0
  13. data/lib/wisper/configuration.rb +44 -0
  14. data/lib/wisper/global_listeners.rb +72 -0
  15. data/lib/wisper/publisher.rb +89 -0
  16. data/lib/wisper/registration/block.rb +11 -0
  17. data/lib/wisper/registration/object.rb +43 -0
  18. data/lib/wisper/registration/registration.rb +18 -0
  19. data/lib/wisper/temporary_listeners.rb +41 -0
  20. data/lib/wisper/value_objects/events.rb +61 -0
  21. data/lib/wisper/value_objects/prefix.rb +29 -0
  22. data/lib/wisper/version.rb +3 -0
  23. data/lib/wisper.rb +65 -0
  24. data/spec/lib/global_listeners_spec.rb +82 -0
  25. data/spec/lib/integration_spec.rb +56 -0
  26. data/spec/lib/simple_example_spec.rb +21 -0
  27. data/spec/lib/temporary_global_listeners_spec.rb +103 -0
  28. data/spec/lib/wisper/broadcasters/logger_broadcaster_spec.rb +129 -0
  29. data/spec/lib/wisper/broadcasters/send_broadcaster_spec.rb +68 -0
  30. data/spec/lib/wisper/configuration/broadcasters_spec.rb +11 -0
  31. data/spec/lib/wisper/configuration_spec.rb +36 -0
  32. data/spec/lib/wisper/publisher_spec.rb +311 -0
  33. data/spec/lib/wisper/registrations/object_spec.rb +14 -0
  34. data/spec/lib/wisper/value_objects/events_spec.rb +107 -0
  35. data/spec/lib/wisper/value_objects/prefix_spec.rb +46 -0
  36. data/spec/lib/wisper_spec.rb +99 -0
  37. data/spec/spec_helper.rb +21 -0
  38. data/wisper-compat.gemspec +29 -0
  39. 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,11 @@
1
+ module Wisper
2
+ describe Configuration::Broadcasters do
3
+ describe 'broadcasters' do
4
+ describe '#to_h' do
5
+ it 'returns a Hash' do
6
+ expect(subject.to_h).to be_instance_of(Hash)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ 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