concurrent-ruby 0.6.0 → 0.7.0.rc0

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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +55 -51
  3. data/lib/concurrent/actress/ad_hoc.rb +6 -0
  4. data/lib/concurrent/actress/context.rb +10 -8
  5. data/lib/concurrent/actress/core.rb +44 -20
  6. data/lib/concurrent/actress/core_delegations.rb +5 -0
  7. data/lib/concurrent/actress/envelope.rb +21 -5
  8. data/lib/concurrent/actress/reference.rb +5 -5
  9. data/lib/concurrent/actress.rb +152 -6
  10. data/lib/concurrent/agent.rb +9 -9
  11. data/lib/concurrent/atomic.rb +46 -0
  12. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
  13. data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
  14. data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
  15. data/lib/concurrent/atomic_reference/jruby.rb +8 -0
  16. data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
  17. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
  18. data/lib/concurrent/atomic_reference/rbx.rb +16 -0
  19. data/lib/concurrent/atomic_reference/ruby.rb +16 -0
  20. data/lib/concurrent/atomics.rb +1 -1
  21. data/lib/concurrent/configuration.rb +7 -2
  22. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +0 -1
  23. data/lib/concurrent/executor/{one_by_one.rb → serialized_execution.rb} +21 -8
  24. data/lib/concurrent/executor/timer_set.rb +6 -1
  25. data/lib/concurrent/executors.rb +1 -1
  26. data/lib/concurrent/logging.rb +1 -1
  27. data/lib/concurrent/observable.rb +1 -1
  28. data/lib/concurrent/supervisor.rb +1 -1
  29. data/lib/concurrent/timer_task.rb +0 -36
  30. data/lib/concurrent/version.rb +1 -1
  31. data/lib/concurrent.rb +3 -4
  32. data/lib/concurrent_ruby_ext.so +0 -0
  33. data/lib/extension_helper.rb +9 -0
  34. metadata +19 -152
  35. data/lib/concurrent/actor/actor.rb +0 -270
  36. data/lib/concurrent/actor/postable.rb +0 -102
  37. data/lib/concurrent/actors.rb +0 -2
  38. data/lib/concurrent/actress/doc.md +0 -53
  39. data/lib/concurrent/atomic/atomic.rb +0 -48
  40. data/lib/concurrent/runnable.rb +0 -90
  41. data/lib/concurrent/stoppable.rb +0 -20
  42. data/spec/concurrent/actor/actor_spec.rb +0 -376
  43. data/spec/concurrent/actor/postable_shared.rb +0 -218
  44. data/spec/concurrent/actress_spec.rb +0 -191
  45. data/spec/concurrent/agent_spec.rb +0 -500
  46. data/spec/concurrent/async_spec.rb +0 -352
  47. data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
  48. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
  49. data/spec/concurrent/atomic/atomic_spec.rb +0 -133
  50. data/spec/concurrent/atomic/condition_spec.rb +0 -171
  51. data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
  52. data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
  53. data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
  54. data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
  55. data/spec/concurrent/atomic/event_spec.rb +0 -200
  56. data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
  57. data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
  58. data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
  59. data/spec/concurrent/channel/channel_spec.rb +0 -39
  60. data/spec/concurrent/channel/probe_spec.rb +0 -77
  61. data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
  62. data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
  63. data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
  64. data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
  65. data/spec/concurrent/configuration_spec.rb +0 -71
  66. data/spec/concurrent/dataflow_spec.rb +0 -242
  67. data/spec/concurrent/delay_spec.rb +0 -91
  68. data/spec/concurrent/dereferenceable_shared.rb +0 -146
  69. data/spec/concurrent/exchanger_spec.rb +0 -66
  70. data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
  71. data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
  72. data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
  73. data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
  74. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
  75. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
  76. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
  77. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
  78. data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
  79. data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
  80. data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
  81. data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
  82. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
  83. data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
  84. data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
  85. data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
  86. data/spec/concurrent/executor/thread_pool_shared.rb +0 -239
  87. data/spec/concurrent/executor/timer_set_spec.rb +0 -183
  88. data/spec/concurrent/future_spec.rb +0 -329
  89. data/spec/concurrent/ivar_spec.rb +0 -215
  90. data/spec/concurrent/mvar_spec.rb +0 -380
  91. data/spec/concurrent/obligation_shared.rb +0 -102
  92. data/spec/concurrent/obligation_spec.rb +0 -282
  93. data/spec/concurrent/observable_shared.rb +0 -177
  94. data/spec/concurrent/observable_spec.rb +0 -56
  95. data/spec/concurrent/options_parser_spec.rb +0 -71
  96. data/spec/concurrent/promise_spec.rb +0 -367
  97. data/spec/concurrent/runnable_shared.rb +0 -68
  98. data/spec/concurrent/runnable_spec.rb +0 -235
  99. data/spec/concurrent/scheduled_task_spec.rb +0 -342
  100. data/spec/concurrent/stoppable_shared.rb +0 -37
  101. data/spec/concurrent/supervisor_spec.rb +0 -1148
  102. data/spec/concurrent/timer_task_spec.rb +0 -258
  103. data/spec/concurrent/tvar_spec.rb +0 -137
  104. data/spec/concurrent/utility/processor_count_spec.rb +0 -20
  105. data/spec/concurrent/utility/timeout_spec.rb +0 -50
  106. data/spec/concurrent/utility/timer_spec.rb +0 -52
  107. data/spec/spec_helper.rb +0 -31
  108. data/spec/support/example_group_extensions.rb +0 -48
  109. data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
  110. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -1,248 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe CyclicBarrier do
6
-
7
- let(:parties) { 3 }
8
- let!(:barrier) { described_class.new(3) }
9
-
10
- context '#initialize' do
11
-
12
- it 'raises an exception if the initial count is less than 1' do
13
- expect {
14
- described_class.new(0)
15
- }.to raise_error(ArgumentError)
16
- end
17
-
18
- it 'raises an exception if the initial count is not an integer' do
19
- expect {
20
- described_class.new('foo')
21
- }.to raise_error(ArgumentError)
22
- end
23
- end
24
-
25
- describe '#parties' do
26
-
27
- it 'should be the value passed to the constructor' do
28
- barrier.parties.should eq 3
29
- end
30
-
31
- end
32
-
33
- describe '#number_waiting' do
34
- context 'without any waiting thread' do
35
- it 'should be equal to zero' do
36
- barrier.number_waiting.should eq 0
37
- end
38
- end
39
-
40
- context 'with waiting threads' do
41
- it 'should be equal to the waiting threads count' do
42
- Thread.new { barrier.wait }
43
- Thread.new { barrier.wait }
44
-
45
- sleep(0.1)
46
-
47
- barrier.number_waiting.should eq 2
48
- end
49
- end
50
- end
51
-
52
- describe '#broken?' do
53
- it 'should not be broken when created' do
54
- barrier.broken?.should eq false
55
- end
56
-
57
- it 'should not be broken when reset is called without waiting thread' do
58
- barrier.reset
59
- barrier.broken?.should eq false
60
- end
61
- end
62
-
63
- describe 'reset' do
64
- it 'should release all waiting threads' do
65
- latch = CountDownLatch.new(1)
66
-
67
- Thread.new { barrier.wait; latch.count_down }
68
- sleep(0.1)
69
- barrier.reset
70
- latch.wait(0.1).should be_true
71
-
72
- barrier.should_not be_broken
73
- barrier.number_waiting.should eq 0
74
- end
75
- end
76
-
77
- describe '#wait' do
78
- context 'without timeout' do
79
- it 'should block the thread' do
80
- t = Thread.new { barrier.wait }
81
- sleep(0.1)
82
-
83
- t.status.should eq 'sleep'
84
- end
85
-
86
- it 'should release all threads when their number matches the desired one' do
87
- latch = CountDownLatch.new(parties)
88
-
89
- parties.times { Thread.new { barrier.wait; latch.count_down } }
90
- latch.wait(0.1).should be_true
91
- barrier.number_waiting.should eq 0
92
- barrier.should_not be_broken
93
- end
94
-
95
- it 'returns true when released' do
96
- latch = CountDownLatch.new(parties)
97
-
98
- parties.times { Thread.new { latch.count_down if barrier.wait == true } }
99
- latch.wait(0.1).should be_true
100
- end
101
-
102
- it 'executes the block once' do
103
- counter = AtomicFixnum.new
104
- barrier = described_class.new(parties) { counter.increment }
105
-
106
- latch = CountDownLatch.new(parties)
107
-
108
- parties.times { Thread.new { latch.count_down if barrier.wait == true } }
109
- latch.wait(0.1).should be_true
110
-
111
- counter.value.should eq 1
112
- end
113
-
114
- it 'can be reused' do
115
- first_latch = CountDownLatch.new(parties)
116
- parties.times { Thread.new { barrier.wait; first_latch.count_down } }
117
- first_latch.wait(0.1).should be_true
118
-
119
- latch = CountDownLatch.new(parties)
120
- parties.times { Thread.new { barrier.wait; latch.count_down } }
121
- latch.wait(0.1).should be_true
122
- end
123
-
124
- it 'return false if barrier has been reset' do
125
- latch = CountDownLatch.new(1)
126
-
127
- Thread.new { latch.count_down if barrier.wait == false }
128
- sleep(0.1)
129
- barrier.reset
130
- latch.wait(0.1).should be_true
131
- end
132
- end
133
-
134
- context 'with timeout' do
135
- context 'timeout not expiring' do
136
- it 'should block the thread' do
137
- t = Thread.new { barrier.wait(1) }
138
- sleep(0.1)
139
-
140
- t.status.should eq 'sleep'
141
- end
142
-
143
- it 'should release all threads when their number matches the desired one' do
144
- latch = CountDownLatch.new(parties)
145
-
146
- parties.times { Thread.new { barrier.wait(1); latch.count_down } }
147
- latch.wait(0.2).should be_true
148
- barrier.number_waiting.should eq 0
149
- end
150
-
151
- it 'returns true when released' do
152
- latch = CountDownLatch.new(parties)
153
-
154
- parties.times { Thread.new { latch.count_down if barrier.wait(1) == true } }
155
- latch.wait(0.1).should be_true
156
- end
157
- end
158
-
159
- context 'timeout expiring' do
160
-
161
- it 'returns false' do
162
- latch = CountDownLatch.new(1)
163
-
164
- Thread.new { latch.count_down if barrier.wait(0.1) == false }
165
- latch.wait(0.2).should be_true
166
- end
167
-
168
- it 'breaks the barrier and release all other threads' do
169
- latch = CountDownLatch.new(2)
170
-
171
- Thread.new { barrier.wait(0.1); latch.count_down }
172
- Thread.new { barrier.wait; latch.count_down }
173
-
174
- latch.wait(0.2).should be_true
175
- barrier.should be_broken
176
- end
177
-
178
- it 'does not execute the block on timeout' do
179
- counter = AtomicFixnum.new
180
- barrier = described_class.new(parties) { counter.increment }
181
-
182
- barrier.wait(0.1)
183
-
184
- counter.value.should eq 0
185
- end
186
- end
187
- end
188
-
189
- context '#broken barrier' do
190
- it 'should not accept new threads' do
191
- Thread.new { barrier.wait(0.1) }
192
- sleep(0.2)
193
-
194
- barrier.should be_broken
195
-
196
- barrier.wait.should be_false
197
- end
198
-
199
- it 'can be reset' do
200
- Thread.new { barrier.wait(0.1) }
201
- sleep(0.2)
202
-
203
- barrier.should be_broken
204
-
205
- barrier.reset
206
-
207
- barrier.should_not be_broken
208
- end
209
- end
210
- end
211
-
212
- context 'spurious wake ups' do
213
-
214
- before(:each) do
215
- def barrier.simulate_spurious_wake_up
216
- @mutex.synchronize do
217
- @condition.signal
218
- @condition.broadcast
219
- end
220
- end
221
- end
222
-
223
- it 'should resist to spurious wake ups without timeout' do
224
- @expected = false
225
- Thread.new { barrier.wait; @expected = true }
226
-
227
- sleep(0.1)
228
- barrier.simulate_spurious_wake_up
229
-
230
- sleep(0.1)
231
- @expected.should be_false
232
- end
233
-
234
- it 'should resist to spurious wake ups with timeout' do
235
- @expected = false
236
- Thread.new { barrier.wait(0.5); @expected = true }
237
-
238
- sleep(0.1)
239
- barrier.simulate_spurious_wake_up
240
-
241
- sleep(0.1)
242
- @expected.should be_false
243
-
244
- end
245
- end
246
- end
247
-
248
- end
@@ -1,200 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe Event do
6
-
7
- subject{ Event.new }
8
-
9
- context '#initialize' do
10
-
11
- it 'sets the state to unset' do
12
- subject.should_not be_set
13
- end
14
- end
15
-
16
- context '#set?' do
17
-
18
- it 'returns true when the event has been set' do
19
- subject.set
20
- subject.should be_set
21
- end
22
-
23
- it 'returns false if the event is unset' do
24
- subject.should_not be_set
25
- end
26
- end
27
-
28
- context '#set' do
29
-
30
- it 'triggers the event' do
31
- @expected = false
32
- Thread.new{ subject.wait; @expected = true }
33
- sleep(0.1)
34
- subject.set
35
- sleep(0.1)
36
- @expected.should be_true
37
- end
38
-
39
- it 'sets the state to set' do
40
- subject.set
41
- subject.should be_set
42
- end
43
- end
44
-
45
- context '#try?' do
46
-
47
- it 'triggers the event if not already set' do
48
- subject.try?
49
- subject.should be_set
50
- end
51
-
52
- it 'returns true if not previously set' do
53
- subject.try?.should be_true
54
- end
55
-
56
- it 'returns false if previously set' do
57
- subject.set
58
- subject.try?.should be_false
59
- end
60
- end
61
-
62
- context '#reset' do
63
-
64
- it 'does not change the state of an unset event' do
65
- subject.reset
66
- subject.should_not be_set
67
- end
68
-
69
- it 'does not trigger an unset event' do
70
- @expected = false
71
- Thread.new{ subject.wait; @expected = true }
72
- sleep(0.1)
73
- subject.reset
74
- sleep(0.1)
75
- @expected.should be_false
76
- end
77
-
78
- it 'does not interrupt waiting threads when event is unset' do
79
- @expected = false
80
- Thread.new{ subject.wait; @expected = true }
81
- sleep(0.1)
82
- subject.reset
83
- sleep(0.1)
84
- subject.set
85
- sleep(0.1)
86
- @expected.should be_true
87
- end
88
-
89
- it 'returns true when called on an unset event' do
90
- subject.reset.should be_true
91
- end
92
-
93
- it 'sets the state of a set event to unset' do
94
- subject.set
95
- subject.should be_set
96
- subject.reset
97
- subject.should_not be_set
98
- end
99
-
100
- it 'returns true when called on a set event' do
101
- subject.set
102
- subject.should be_set
103
- subject.reset.should be_true
104
- end
105
- end
106
-
107
- context '#wait' do
108
-
109
- it 'returns immediately when the event has been set' do
110
- subject.reset
111
- @expected = false
112
- subject.set
113
- Thread.new{ subject.wait(1000); @expected = true}
114
- sleep(1)
115
- @expected.should be_true
116
- end
117
-
118
- it 'returns true once the event is set' do
119
- subject.set
120
- subject.wait.should be_true
121
- end
122
-
123
- it 'blocks indefinitely when the timer is nil' do
124
- subject.reset
125
- @expected = false
126
- Thread.new{ subject.wait; @expected = true}
127
- subject.set
128
- sleep(1)
129
- @expected.should be_true
130
- end
131
-
132
- it 'stops waiting when the timer expires' do
133
- subject.reset
134
- @expected = false
135
- Thread.new{ subject.wait(0.5); @expected = true}
136
- sleep(1)
137
- @expected.should be_true
138
- end
139
-
140
- it 'returns false when the timer expires' do
141
- subject.reset
142
- subject.wait(1).should be_false
143
- end
144
-
145
- it 'triggers multiple waiting threads' do
146
- latch = CountDownLatch.new(5)
147
- subject.reset
148
- 5.times{ Thread.new{ subject.wait; latch.count_down } }
149
- subject.set
150
- latch.wait(0.2).should be_true
151
- end
152
-
153
- it 'behaves appropriately if wait begins while #set is processing' do
154
- subject.reset
155
- latch = CountDownLatch.new(5)
156
- 5.times{ Thread.new{ subject.wait(5) } }
157
- subject.set
158
- 5.times{ Thread.new{ subject.wait; latch.count_down } }
159
- latch.wait(0.2).should be_true
160
- end
161
- end
162
-
163
- context 'spurious wake ups' do
164
-
165
- before(:each) do
166
- def subject.simulate_spurious_wake_up
167
- @mutex.synchronize do
168
- @condition.signal
169
- @condition.broadcast
170
- end
171
- end
172
- end
173
-
174
- it 'should resist to spurious wake ups without timeout' do
175
- @expected = false
176
- Thread.new { subject.wait; @expected = true }
177
-
178
- sleep(0.1)
179
- subject.simulate_spurious_wake_up
180
-
181
- sleep(0.1)
182
- @expected.should be_false
183
- end
184
-
185
- it 'should resist to spurious wake ups with timeout' do
186
- @expected = false
187
- Thread.new { subject.wait(0.5); @expected = true }
188
-
189
- sleep(0.1)
190
- subject.simulate_spurious_wake_up
191
-
192
- sleep(0.1)
193
- @expected.should be_false
194
-
195
- sleep(0.4)
196
- @expected.should be_true
197
- end
198
- end
199
- end
200
- end
@@ -1,242 +0,0 @@
1
- require 'spec_helper'
2
-
3
- shared_examples "an observer set" do
4
-
5
- let (:observer_set) { described_class.new }
6
- let (:observer) { double('observer') }
7
- let (:another_observer) { double('another observer') }
8
-
9
- describe '#add_observer' do
10
-
11
- context 'with arguments' do
12
- it 'should return the observer' do
13
- observer_set.add_observer(observer, :a_method).should == observer
14
- end
15
- end
16
-
17
- context 'with a block' do
18
- it 'should return the observer based on a block' do
19
- observer = observer_set.add_observer { :block }
20
- observer.call.should == :block
21
- end
22
- end
23
- end
24
-
25
- describe '#notify_observers' do
26
- it 'should return the observer set' do
27
- observer_set.notify_observers.should be(observer_set)
28
- end
29
-
30
- context 'with a single observer' do
31
- it 'should update a registered observer without arguments' do
32
- expect(observer).to receive(:update).with(no_args)
33
-
34
- observer_set.add_observer(observer)
35
-
36
- observer_set.notify_observers
37
- end
38
-
39
- it 'should update a registered observer with arguments' do
40
- expect(observer).to receive(:update).with(1, 2, 3)
41
-
42
- observer_set.add_observer(observer)
43
-
44
- observer_set.notify_observers(1, 2, 3)
45
- end
46
-
47
- it 'should notify an observer using the chosen method' do
48
- expect(observer).to receive(:another_method).with('a string arg')
49
-
50
- observer_set.add_observer(observer, :another_method)
51
-
52
- observer_set.notify_observers('a string arg')
53
- end
54
-
55
- it 'should notify an observer once using the last added method' do
56
- expect(observer).to receive(:another_method).with(any_args).never
57
- expect(observer).to receive(:yet_another_method).with('a string arg')
58
-
59
- observer_set.add_observer(observer, :another_method)
60
- observer_set.add_observer(observer, :yet_another_method)
61
-
62
- observer_set.notify_observers('a string arg')
63
- end
64
-
65
- it 'should notify an observer from a block' do
66
- notification = double
67
- expect(notification).to receive(:catch)
68
-
69
- observer_set.add_observer {|arg| arg.catch }
70
- observer_set.notify_observers notification
71
- end
72
-
73
- it 'can be called many times' do
74
- expect(observer).to receive(:update).with(:an_arg).twice
75
- expect(observer).to receive(:update).with(no_args).once
76
-
77
- observer_set.add_observer(observer)
78
-
79
- observer_set.notify_observers(:an_arg)
80
- observer_set.notify_observers
81
- observer_set.notify_observers(:an_arg)
82
- end
83
- end
84
-
85
- context 'with many observers' do
86
- it 'should notify all observer using the chosen method' do
87
- expect(observer).to receive(:a_method).with(4, 'a')
88
- expect(another_observer).to receive(:update).with(4, 'a')
89
-
90
- observer_set.add_observer(observer, :a_method)
91
- observer_set.add_observer(another_observer)
92
-
93
- observer_set.notify_observers(4, 'a')
94
- end
95
- end
96
-
97
- context 'with a block' do
98
-
99
- before(:each) do
100
- observer.stub(:update).with(any_args)
101
- another_observer.stub(:update).with(any_args)
102
- end
103
-
104
- it 'calls the block once for every observer' do
105
-
106
- counter = double('block call counter')
107
- expect(counter).to receive(:called).with(no_args).exactly(2).times
108
-
109
- observer_set.add_observer(observer)
110
- observer_set.add_observer(another_observer)
111
-
112
- observer_set.notify_observers{ counter.called }
113
- end
114
-
115
- it 'passes the block return value to the update method' do
116
-
117
- expect(observer).to receive(:update).with(1, 2, 3, 4)
118
- observer_set.add_observer(observer)
119
- observer_set.notify_observers{ [1, 2, 3, 4] }
120
- end
121
-
122
- it 'accepts blocks returning a single value' do
123
-
124
- expect(observer).to receive(:update).with(:foo)
125
- observer_set.add_observer(observer)
126
- observer_set.notify_observers{ :foo }
127
- end
128
-
129
- it 'accepts block return values that include arrays' do
130
-
131
- expect(observer).to receive(:update).with(1, [2, 3], 4)
132
- observer_set.add_observer(observer)
133
- observer_set.notify_observers{ [1, [2, 3], 4] }
134
- end
135
-
136
- it 'raises an exception if given both arguments and a block' do
137
-
138
- observer_set.add_observer(observer)
139
-
140
- expect {
141
- observer_set.notify_observers(1, 2, 3, 4){ nil }
142
- }.to raise_error(ArgumentError)
143
- end
144
- end
145
- end
146
-
147
- context '#count_observers' do
148
- it 'should be zero after initialization' do
149
- observer_set.count_observers.should eq 0
150
- end
151
-
152
- it 'should be 1 after the first observer is added' do
153
- observer_set.add_observer(observer)
154
- observer_set.count_observers.should eq 1
155
- end
156
-
157
- it 'should be 1 if the same observer is added many times' do
158
- observer_set.add_observer(observer)
159
- observer_set.add_observer(observer, :another_method)
160
- observer_set.add_observer(observer, :yet_another_method)
161
-
162
- observer_set.count_observers.should eq 1
163
- end
164
-
165
- it 'should be equal to the number of unique observers' do
166
- observer_set.add_observer(observer)
167
- observer_set.add_observer(another_observer)
168
- observer_set.add_observer(double('observer 3'))
169
- observer_set.add_observer(double('observer 4'))
170
-
171
- observer_set.count_observers.should eq 4
172
- end
173
- end
174
-
175
- describe '#delete_observer' do
176
- it 'should not notify a deleted observer' do
177
- expect(observer).to receive(:update).never
178
-
179
- observer_set.add_observer(observer)
180
- observer_set.delete_observer(observer)
181
-
182
- observer_set.notify_observers
183
- end
184
-
185
- it 'can delete a non added observer' do
186
- observer_set.delete_observer(observer)
187
- end
188
-
189
- it 'should return the observer' do
190
- observer_set.delete_observer(observer).should be(observer)
191
- end
192
- end
193
-
194
- describe '#delete_observers' do
195
- it 'should remove all observers' do
196
- expect(observer).to receive(:update).never
197
- expect(another_observer).to receive(:update).never
198
-
199
- observer_set.add_observer(observer)
200
- observer_set.add_observer(another_observer)
201
-
202
- observer_set.delete_observers
203
-
204
- observer_set.notify_observers
205
- end
206
-
207
- it 'should return the observer set' do
208
- observer_set.delete_observers.should be(observer_set)
209
- end
210
- end
211
-
212
- describe '#notify_and_delete_observers' do
213
- before(:each) do
214
- observer_set.add_observer(observer, :a_method)
215
- observer_set.add_observer(another_observer)
216
-
217
- expect(observer).to receive(:a_method).with('args').once
218
- expect(another_observer).to receive(:update).with('args').once
219
- end
220
-
221
- it 'should notify all observers' do
222
- observer_set.notify_and_delete_observers('args')
223
- end
224
-
225
- it 'should clear observers' do
226
- observer_set.notify_and_delete_observers('args')
227
-
228
- observer_set.count_observers.should eq(0)
229
- end
230
-
231
- it 'can be called many times without any other notification' do
232
- observer_set.notify_and_delete_observers('args')
233
- observer_set.notify_and_delete_observers('args')
234
- observer_set.notify_and_delete_observers('args')
235
- end
236
-
237
- it 'should return the observer set' do
238
- observer_set.notify_and_delete_observers('args').should be(observer_set)
239
- end
240
- end
241
-
242
- end