drama_queen 0.1.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.
@@ -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