drama_queen 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,32 @@
1
+ require_relative '../drama_queen'
2
+ require_relative 'exchange'
3
+
4
+
5
+ module DramaQueen
6
+
7
+ # A +producer+ is an object that has content to provide on a +topic+. When
8
+ # it decides it has content to +publish+ on that topic, it simply passes that
9
+ # info on to all of the +consumer+s that have +subscribe+d to the topic.
10
+ # Actually, it doesn't have to pass any info on--it can simply act like a ping
11
+ # to the subscribers; this is up to how you want to use them.
12
+ module Producer
13
+
14
+ # @param routing_key
15
+ # @param args
16
+ # @return [Boolean] +true+ if anything was published; +false+ if not.
17
+ def publish(routing_key, *args)
18
+ exchange = DramaQueen.exchange_for(routing_key)
19
+ exchange ||= DramaQueen::Exchange.new(routing_key)
20
+
21
+ all_exchanges = [exchange] + exchange.related_exchanges
22
+ subscription_count = 0
23
+
24
+ all_exchanges.each do |exchange|
25
+ subscription_count += exchange.subscribers.size
26
+ exchange.notify_with(*args)
27
+ end
28
+
29
+ !subscription_count.zero?
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module DramaQueen
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+ require 'drama_queen/consumer'
3
+ require 'drama_queen/producer'
4
+
5
+ class BigPublisher
6
+ include DramaQueen::Producer
7
+
8
+ def do_stuff
9
+ publish 'stuff1', 'the stuff1'
10
+ publish 'stuff2', 'the stuff2'
11
+ publish 'stuff5', 'the stuff3'
12
+ publish 'stuff3', 'the stuff4'
13
+ publish 'stuff5', 'the stuff5'
14
+ end
15
+ end
16
+
17
+ class BigConsumer
18
+ include DramaQueen::Consumer
19
+
20
+ def initialize(callback1, callback2)
21
+ 100000.times do
22
+ subscribe 'stuff1', callback1
23
+ subscribe 'stuff2', callback2
24
+ subscribe 'stuff3', callback1
25
+ subscribe 'stuff4', callback2
26
+ subscribe 'stuff5', ->(arg) {
27
+ #puts arg
28
+ }
29
+ end
30
+ end
31
+ end
32
+
33
+ class A
34
+ include DramaQueen::Consumer
35
+
36
+ def initialize(callback)
37
+ subscribe 'root.*.children', callback
38
+ end
39
+
40
+ def call_me(*args)
41
+ puts "A got called with args: #{args}"
42
+ end
43
+ end
44
+
45
+ class B
46
+ include DramaQueen::Producer
47
+
48
+ def do_stuff
49
+ publish 'root.parent', 1, 2, 3
50
+ end
51
+ end
52
+
53
+ class C
54
+ include DramaQueen::Producer
55
+
56
+ def do_stuff
57
+ publish 'root.parent.children', 'one', 'two', 'three'
58
+ end
59
+ end
60
+
61
+ describe 'Draaaamaaaa' do
62
+ before do
63
+ DramaQueen.unsubscribe_all
64
+ end
65
+
66
+ describe 'lots of action' do
67
+ it 'calls all of the things' do
68
+ callback1 = Proc.new {}
69
+ callback2 = Proc.new {}
70
+ expect(callback1).to receive(:call).at_least(10000).times.with('the stuff1')
71
+ expect(callback1).to receive(:call).at_least(10000).times.with('the stuff4')
72
+ expect(callback2).to receive(:call).at_least(10000).times.with('the stuff2')
73
+ expect(callback2).to receive(:call).at_most(10002)
74
+
75
+ a = BigPublisher.new
76
+ b = BigConsumer.new(callback1, callback2)
77
+
78
+ a.do_stuff
79
+ b.subscribe 'things', ->(arg) { puts arg }
80
+
81
+ a.do_stuff
82
+ a.publish 'things', 'hi'
83
+ end
84
+ end
85
+
86
+ describe 'topic matching' do
87
+ it 'calls only the topics that match' do
88
+ callback = Proc.new {}
89
+ #expect(callback).to receive(:call).with 'one', 'two', 'three'
90
+ expect(callback).to receive(:call)
91
+
92
+ a = A.new(callback)
93
+ b = B.new
94
+ c = C.new
95
+
96
+ b.do_stuff
97
+ c.do_stuff
98
+ end
99
+ end
100
+ end
@@ -0,0 +1 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+ require 'drama_queen/consumer'
3
+
4
+
5
+ describe DramaQueen::Consumer do
6
+ subject do
7
+ Object.new.extend(DramaQueen::Consumer)
8
+ end
9
+
10
+ let(:exchange) { double 'DramaQueen::Exchange', subscribers: [] }
11
+ let(:callback) { double 'Method', call: true }
12
+
13
+ describe '#subscribe' do
14
+ before do
15
+ allow(DramaQueen).to receive(:exchange_for).with('test') { exchange }
16
+ end
17
+
18
+ context 'routing key exists' do
19
+ before do
20
+ allow(DramaQueen).to receive(:routes_to?).with('test') { true }
21
+ end
22
+
23
+ it "creates a new exchange and adds itself to exchange's subscribers" do
24
+ expect(DramaQueen.exchanges).to_not receive(:<<)
25
+ expect(subject).to receive(:method).with(:call_me) { callback }
26
+
27
+ subject.subscribe('test', :call_me)
28
+
29
+ expect(exchange.subscribers).to eq [callback]
30
+ end
31
+ end
32
+
33
+ context 'routing key does not exist' do
34
+ before do
35
+ allow(DramaQueen).to receive(:routes_to?).with('test') { false }
36
+ end
37
+
38
+ it "find the exchange and adds itself to exchange's subscribers" do
39
+ expect(DramaQueen::Exchange).to receive(:new).with('test') { exchange }
40
+ expect(DramaQueen.exchanges).to receive(:<<).with(exchange)
41
+ expect(subject).to receive(:method).with(:call_me) { callback }
42
+
43
+ subject.subscribe('test', :call_me)
44
+
45
+ expect(exchange.subscribers).to eq [callback]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,252 @@
1
+ require 'spec_helper'
2
+ require 'drama_queen/exchange'
3
+
4
+
5
+ describe DramaQueen::Exchange do
6
+ let(:prim_object) { Object.new }
7
+ let(:prim_all) { '**' }
8
+ let(:prim_all_root) { '*' }
9
+ let(:prim_root) { 'root' }
10
+ let(:prim_notroot) { 'not-root' }
11
+ let(:prim_root_and_tree) { 'root.**' }
12
+ let(:prim_root_and_children) { 'root.*' }
13
+ let(:prim_root_child1) { 'root.child1' }
14
+ let(:prim_root_child2) { 'root.child2' }
15
+ let(:prim_root_child1_and_children) { 'root.child1.*' }
16
+ let(:prim_root_child2_and_children) { 'root.child2.*' }
17
+ let(:prim_root_child2_and_grandchild) { 'root.child2.grandchild' }
18
+ let(:prim_root_child2_and_greatgrandchild) { 'root.child2.grandchild.great_grandchild' }
19
+ let(:prim_root_child3_and_grandchild) { 'root.child3.grandchild' }
20
+ let(:prim_root_all_children_with_grandchild) { 'root.*.grandchild' }
21
+
22
+ let(:key_object) { described_class.new(prim_object) }
23
+ let(:key_all) { described_class.new '**' }
24
+ let(:key_all_root) { described_class.new '*' }
25
+ let(:key_root) { described_class.new 'root' }
26
+ let(:key_notroot) { described_class.new 'not-root' }
27
+ let(:key_root_and_tree) { described_class.new 'root.**' }
28
+ let(:key_root_and_children) { described_class.new 'root.*' }
29
+ let(:key_root_child1) { described_class.new 'root.child1' }
30
+ let(:key_root_child2) { described_class.new 'root.child2' }
31
+ let(:key_root_child1_and_children) { described_class.new 'root.child1.*' }
32
+ let(:key_root_child2_and_children) { described_class.new 'root.child2.*' }
33
+ let(:key_root_child2_and_grandchild) { described_class.new 'root.child2.grandchild' }
34
+ let(:key_root_child2_and_greatgrandchild) { described_class.new 'root.child2.grandchild.great_grandchild' }
35
+ let(:key_root_child3_and_grandchild) { described_class.new 'root.child3.grandchild' }
36
+ let(:key_root_all_children_with_grandchild) { described_class.new 'root.*.grandchild' }
37
+
38
+ let(:exchanges) do
39
+ [
40
+ key_object,
41
+ key_all,
42
+ key_all_root,
43
+ key_root,
44
+ key_notroot,
45
+ key_root_and_tree,
46
+ key_root_and_children,
47
+ key_root_child1,
48
+ key_root_child2,
49
+ key_root_child1_and_children,
50
+ key_root_child2_and_children,
51
+ key_root_child2_and_grandchild,
52
+ key_root_child2_and_greatgrandchild,
53
+ key_root_child3_and_grandchild,
54
+ key_root_all_children_with_grandchild
55
+ ]
56
+ end
57
+
58
+ before do
59
+ allow(DramaQueen).to receive(:exchanges) { exchanges }
60
+ end
61
+
62
+ describe '#related_keys' do
63
+ context '**' do
64
+ subject { described_class.new(prim_all) }
65
+
66
+ it 'returns all keys' do
67
+ expect(subject.related_exchanges).to eq exchanges
68
+ end
69
+ end
70
+
71
+ context '*' do
72
+ subject { described_class.new(prim_all_root) }
73
+
74
+ it 'returns all root level keys' do
75
+ expect(subject.related_exchanges).to eq [
76
+ key_root,
77
+ key_notroot
78
+ ]
79
+ end
80
+ end
81
+
82
+ context 'an object' do
83
+ subject { described_class.new(prim_object) }
84
+
85
+ specify do
86
+ expect(subject.related_exchanges).to eq []
87
+ end
88
+ end
89
+
90
+ context 'root' do
91
+ subject { described_class.new(prim_root) }
92
+
93
+ specify do
94
+ expect(subject.related_exchanges).to eq [
95
+ key_all_root
96
+ ]
97
+ end
98
+ end
99
+
100
+ context 'not-root' do
101
+ subject { described_class.new(prim_notroot) }
102
+
103
+ specify do
104
+ expect(subject.related_exchanges).to eq [
105
+ key_all_root,
106
+ ]
107
+ end
108
+ end
109
+
110
+ context 'root.**' do
111
+ subject { described_class.new(prim_root_and_tree) }
112
+
113
+ specify do
114
+ expect(subject.related_exchanges).to eq [
115
+ key_root_and_children,
116
+ key_root_child1,
117
+ key_root_child2,
118
+ key_root_child1_and_children,
119
+ key_root_child2_and_children,
120
+ key_root_child2_and_grandchild,
121
+ key_root_child2_and_greatgrandchild,
122
+ key_root_child3_and_grandchild,
123
+ key_root_all_children_with_grandchild
124
+ ]
125
+ end
126
+ end
127
+
128
+ context 'root.*' do
129
+ subject { described_class.new(prim_root_and_children) }
130
+
131
+ specify do
132
+ expect(subject.related_exchanges).to eq [
133
+ key_root_and_tree,
134
+ key_root_child1,
135
+ key_root_child2
136
+ ]
137
+ end
138
+ end
139
+
140
+ context 'root.child1' do
141
+ subject { described_class.new(prim_root_child1) }
142
+
143
+ specify do
144
+ expect(subject.related_exchanges).to eq [
145
+ key_root_and_tree,
146
+ key_root_and_children,
147
+ ]
148
+ end
149
+ end
150
+
151
+ context 'root.child2' do
152
+ subject { described_class.new(prim_root_child2) }
153
+
154
+ specify do
155
+ expect(subject.related_exchanges).to eq [
156
+ key_root_and_tree,
157
+ key_root_and_children,
158
+ ]
159
+ end
160
+ end
161
+
162
+ context 'root.child1.*' do
163
+ subject { described_class.new(prim_root_child1_and_children) }
164
+
165
+ specify do
166
+ expect(subject.related_exchanges).to eq [
167
+ key_root_and_tree,
168
+ ]
169
+ end
170
+ end
171
+
172
+ context 'root.child2.*' do
173
+ subject { described_class.new(prim_root_child2_and_children) }
174
+
175
+ specify do
176
+ expect(subject.related_exchanges).to eq [
177
+ key_root_and_tree,
178
+ key_root_child2_and_grandchild
179
+ ]
180
+ end
181
+ end
182
+
183
+ context 'root.child2.grandchild' do
184
+ subject { described_class.new(prim_root_child2_and_grandchild) }
185
+
186
+ specify do
187
+ expect(subject.related_exchanges).to eq [
188
+ key_root_and_tree,
189
+ key_root_child2_and_children,
190
+ key_root_all_children_with_grandchild
191
+ ]
192
+ end
193
+ end
194
+
195
+ context 'root.child2.grandchild.great_grandchild' do
196
+ subject { described_class.new(prim_root_child2_and_greatgrandchild) }
197
+
198
+ specify do
199
+ expect(subject.related_exchanges).to eq [
200
+ key_root_and_tree,
201
+ ]
202
+ end
203
+ end
204
+
205
+ context 'root.child3.grandchild' do
206
+ subject { described_class.new(prim_root_child3_and_grandchild) }
207
+
208
+ specify do
209
+ expect(subject.related_exchanges).to eq [
210
+ key_root_and_tree,
211
+ key_root_all_children_with_grandchild
212
+ ]
213
+ end
214
+ end
215
+
216
+ context 'root.*.grandchild' do
217
+ subject { described_class.new(prim_root_all_children_with_grandchild) }
218
+
219
+ specify do
220
+ expect(subject.related_exchanges).to eq [
221
+ key_root_and_tree,
222
+ key_root_child2_and_grandchild,
223
+ key_root_child3_and_grandchild,
224
+ ]
225
+ end
226
+ end
227
+ end
228
+
229
+ describe '#notify_with' do
230
+ let(:object) { Object.new }
231
+
232
+ subject do
233
+ described_class.new 'test_key'
234
+ end
235
+
236
+ context 'list is empty' do
237
+ it 'does not raise an error' do
238
+ expect { subject.notify_with('stuff') }.to_not raise_exception
239
+ end
240
+ end
241
+
242
+ context 'list is not empty' do
243
+ it 'it #calls each subscriber with the given args' do
244
+ subscriber = double 'Subscriber'
245
+ subject.instance_variable_set(:@subscribers, [subscriber])
246
+ expect(subscriber).to receive('call').with(1, 2, 3)
247
+
248
+ subject.notify_with 1, 2, 3
249
+ end
250
+ end
251
+ end
252
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+ require 'drama_queen/producer'
3
+
4
+
5
+ describe DramaQueen::Producer do
6
+ subject { Object.new.extend(described_class) }
7
+
8
+ let(:exchange) { double 'DramaQueen::Exchange', subscribers: [] }
9
+
10
+ before do
11
+ allow(DramaQueen).to receive(:exchange_for).with('test') { exchange }
12
+ end
13
+
14
+ describe '#publish' do
15
+ context 'with no related exchanges' do
16
+ context 'with no subscribers' do
17
+ before do
18
+ allow(exchange).to receive(:related_exchanges) { [] }
19
+ end
20
+
21
+ it 'returns false' do
22
+ allow(exchange).to receive(:notify_with)
23
+ expect(subject.publish('test', :an_arg)).to eq false
24
+ end
25
+
26
+ it 'calls #notify_with on the exchange' do
27
+ expect(exchange).to receive(:notify_with).with(:an_arg)
28
+ subject.publish('test', :an_arg)
29
+ end
30
+ end
31
+
32
+ context 'with subscribers' do
33
+ before do
34
+ allow(exchange).to receive(:related_exchanges) { [] }
35
+ exchange.subscribers << [1, 2]
36
+ end
37
+
38
+ it 'returns true' do
39
+ allow(exchange).to receive(:notify_with)
40
+ expect(subject.publish('test', :an_arg)).to eq true
41
+ end
42
+
43
+ it 'calls #notify_with on the exchange' do
44
+ expect(exchange).to receive(:notify_with).with(:an_arg)
45
+ subject.publish('test', :an_arg)
46
+ end
47
+ end
48
+ end
49
+
50
+ context 'with related exchanges' do
51
+ let(:another_exchange) do
52
+ double 'DramaQueen::Exchange'
53
+ end
54
+
55
+ before do
56
+ allow(exchange).to receive(:related_exchanges) { [another_exchange] }
57
+ end
58
+
59
+ context 'with no subscribers' do
60
+ before do
61
+ allow(another_exchange).to receive(:subscribers) { [] }
62
+ end
63
+
64
+ it 'calls #notify_with' do
65
+ expect(exchange).to receive(:notify_with).with(:an_arg)
66
+ expect(another_exchange).to receive(:notify_with).with(:an_arg)
67
+ subject.publish('test', :an_arg)
68
+ end
69
+
70
+ it 'returns false' do
71
+ allow(exchange).to receive(:notify_with)
72
+ allow(another_exchange).to receive(:notify_with)
73
+ expect(subject.publish('test', :an_arg)).to eq false
74
+ end
75
+ end
76
+
77
+ context 'with subscribers' do
78
+ before do
79
+ allow(another_exchange).to receive(:subscribers) { [1, 2] }
80
+ end
81
+
82
+ it 'calls #notify_with' do
83
+ expect(exchange).to receive(:notify_with).with(:an_arg)
84
+ expect(another_exchange).to receive(:notify_with).with(:an_arg)
85
+ subject.publish('test', :an_arg)
86
+ end
87
+
88
+ it 'returns true' do
89
+ allow(exchange).to receive(:notify_with)
90
+ allow(another_exchange).to receive(:notify_with)
91
+ expect(subject.publish('test', :an_arg)).to eq true
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end