concurrent-ruby 0.6.0.pre.1 → 0.6.0.pre.2
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 +4 -4
- data/README.md +16 -0
- data/lib/concurrent.rb +9 -29
- data/lib/concurrent/{actor.rb → actor/actor.rb} +3 -3
- data/lib/concurrent/actor/actor_context.rb +77 -0
- data/lib/concurrent/actor/actor_ref.rb +67 -0
- data/lib/concurrent/{postable.rb → actor/postable.rb} +1 -1
- data/lib/concurrent/actor/simple_actor_ref.rb +94 -0
- data/lib/concurrent/actors.rb +5 -0
- data/lib/concurrent/agent.rb +81 -47
- data/lib/concurrent/async.rb +35 -35
- data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +170 -0
- data/lib/concurrent/{condition.rb → atomic/condition.rb} +0 -0
- data/lib/concurrent/{copy_on_notify_observer_set.rb → atomic/copy_on_notify_observer_set.rb} +48 -13
- data/lib/concurrent/{copy_on_write_observer_set.rb → atomic/copy_on_write_observer_set.rb} +41 -20
- data/lib/concurrent/atomic/count_down_latch.rb +116 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
- data/lib/concurrent/atomic/event.rb +103 -0
- data/lib/concurrent/{thread_local_var.rb → atomic/thread_local_var.rb} +0 -0
- data/lib/concurrent/atomics.rb +9 -0
- data/lib/concurrent/channel/buffered_channel.rb +6 -4
- data/lib/concurrent/channel/channel.rb +30 -2
- data/lib/concurrent/channel/unbuffered_channel.rb +2 -2
- data/lib/concurrent/channel/waitable_list.rb +3 -1
- data/lib/concurrent/channels.rb +5 -0
- data/lib/concurrent/{channel → collection}/blocking_ring_buffer.rb +16 -5
- data/lib/concurrent/collection/priority_queue.rb +305 -0
- data/lib/concurrent/{channel → collection}/ring_buffer.rb +6 -1
- data/lib/concurrent/collections.rb +3 -0
- data/lib/concurrent/configuration.rb +68 -19
- data/lib/concurrent/dataflow.rb +9 -9
- data/lib/concurrent/delay.rb +21 -13
- data/lib/concurrent/dereferenceable.rb +40 -33
- data/lib/concurrent/exchanger.rb +3 -0
- data/lib/concurrent/{cached_thread_pool.rb → executor/cached_thread_pool.rb} +8 -9
- data/lib/concurrent/executor/executor.rb +222 -0
- data/lib/concurrent/{fixed_thread_pool.rb → executor/fixed_thread_pool.rb} +6 -7
- data/lib/concurrent/{immediate_executor.rb → executor/immediate_executor.rb} +5 -5
- data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
- data/lib/concurrent/{java_fixed_thread_pool.rb → executor/java_fixed_thread_pool.rb} +7 -11
- data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
- data/lib/concurrent/{java_thread_pool_executor.rb → executor/java_thread_pool_executor.rb} +66 -77
- data/lib/concurrent/executor/one_by_one.rb +65 -0
- data/lib/concurrent/{per_thread_executor.rb → executor/per_thread_executor.rb} +4 -4
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
- data/lib/concurrent/{ruby_fixed_thread_pool.rb → executor/ruby_fixed_thread_pool.rb} +5 -4
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +72 -0
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +282 -0
- data/lib/concurrent/{ruby_thread_pool_worker.rb → executor/ruby_thread_pool_worker.rb} +6 -6
- data/lib/concurrent/{safe_task_executor.rb → executor/safe_task_executor.rb} +20 -13
- data/lib/concurrent/executor/single_thread_executor.rb +35 -0
- data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
- data/lib/concurrent/executor/timer_set.rb +138 -0
- data/lib/concurrent/executors.rb +9 -0
- data/lib/concurrent/future.rb +39 -40
- data/lib/concurrent/ivar.rb +22 -15
- data/lib/concurrent/mvar.rb +2 -1
- data/lib/concurrent/obligation.rb +9 -3
- data/lib/concurrent/observable.rb +33 -0
- data/lib/concurrent/options_parser.rb +46 -0
- data/lib/concurrent/promise.rb +23 -24
- data/lib/concurrent/scheduled_task.rb +21 -45
- data/lib/concurrent/timer_task.rb +204 -126
- data/lib/concurrent/tvar.rb +1 -1
- data/lib/concurrent/utilities.rb +3 -36
- data/lib/concurrent/{processor_count.rb → utility/processor_count.rb} +1 -1
- data/lib/concurrent/utility/timeout.rb +36 -0
- data/lib/concurrent/utility/timer.rb +21 -0
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.bundle +0 -0
- data/spec/concurrent/{actor_context_spec.rb → actor/actor_context_spec.rb} +0 -8
- data/spec/concurrent/{actor_ref_shared.rb → actor/actor_ref_shared.rb} +9 -59
- data/spec/concurrent/{actor_spec.rb → actor/actor_spec.rb} +43 -41
- data/spec/concurrent/{postable_shared.rb → actor/postable_shared.rb} +0 -0
- data/spec/concurrent/actor/simple_actor_ref_spec.rb +135 -0
- data/spec/concurrent/agent_spec.rb +160 -71
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +172 -0
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +186 -0
- data/spec/concurrent/{condition_spec.rb → atomic/condition_spec.rb} +2 -2
- data/spec/concurrent/{copy_on_notify_observer_set_spec.rb → atomic/copy_on_notify_observer_set_spec.rb} +0 -0
- data/spec/concurrent/{copy_on_write_observer_set_spec.rb → atomic/copy_on_write_observer_set_spec.rb} +0 -0
- data/spec/concurrent/atomic/count_down_latch_spec.rb +151 -0
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +248 -0
- data/spec/concurrent/{event_spec.rb → atomic/event_spec.rb} +18 -3
- data/spec/concurrent/{observer_set_shared.rb → atomic/observer_set_shared.rb} +15 -6
- data/spec/concurrent/{thread_local_var_spec.rb → atomic/thread_local_var_spec.rb} +0 -0
- data/spec/concurrent/channel/buffered_channel_spec.rb +1 -1
- data/spec/concurrent/channel/channel_spec.rb +6 -4
- data/spec/concurrent/channel/probe_spec.rb +37 -9
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +2 -2
- data/spec/concurrent/{channel → collection}/blocking_ring_buffer_spec.rb +0 -0
- data/spec/concurrent/collection/priority_queue_spec.rb +317 -0
- data/spec/concurrent/{channel → collection}/ring_buffer_spec.rb +0 -0
- data/spec/concurrent/configuration_spec.rb +4 -70
- data/spec/concurrent/dereferenceable_shared.rb +5 -4
- data/spec/concurrent/exchanger_spec.rb +10 -5
- data/spec/concurrent/{cached_thread_pool_shared.rb → executor/cached_thread_pool_shared.rb} +15 -37
- data/spec/concurrent/{fixed_thread_pool_shared.rb → executor/fixed_thread_pool_shared.rb} +0 -0
- data/spec/concurrent/{global_thread_pool_shared.rb → executor/global_thread_pool_shared.rb} +10 -8
- data/spec/concurrent/{immediate_executor_spec.rb → executor/immediate_executor_spec.rb} +0 -0
- data/spec/concurrent/{java_cached_thread_pool_spec.rb → executor/java_cached_thread_pool_spec.rb} +1 -21
- data/spec/concurrent/{java_fixed_thread_pool_spec.rb → executor/java_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +21 -0
- data/spec/concurrent/{java_thread_pool_executor_spec.rb → executor/java_thread_pool_executor_spec.rb} +0 -0
- data/spec/concurrent/{per_thread_executor_spec.rb → executor/per_thread_executor_spec.rb} +0 -4
- data/spec/concurrent/{ruby_cached_thread_pool_spec.rb → executor/ruby_cached_thread_pool_spec.rb} +1 -1
- data/spec/concurrent/{ruby_fixed_thread_pool_spec.rb → executor/ruby_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +18 -0
- data/spec/concurrent/{ruby_thread_pool_executor_spec.rb → executor/ruby_thread_pool_executor_spec.rb} +12 -24
- data/spec/concurrent/executor/safe_task_executor_spec.rb +103 -0
- data/spec/concurrent/{thread_pool_class_cast_spec.rb → executor/thread_pool_class_cast_spec.rb} +12 -0
- data/spec/concurrent/{thread_pool_executor_shared.rb → executor/thread_pool_executor_shared.rb} +0 -0
- data/spec/concurrent/{thread_pool_shared.rb → executor/thread_pool_shared.rb} +84 -119
- data/spec/concurrent/executor/timer_set_spec.rb +183 -0
- data/spec/concurrent/future_spec.rb +12 -0
- data/spec/concurrent/ivar_spec.rb +11 -1
- data/spec/concurrent/observable_shared.rb +173 -0
- data/spec/concurrent/observable_spec.rb +51 -0
- data/spec/concurrent/options_parser_spec.rb +71 -0
- data/spec/concurrent/runnable_shared.rb +6 -0
- data/spec/concurrent/scheduled_task_spec.rb +60 -40
- data/spec/concurrent/timer_task_spec.rb +130 -144
- data/spec/concurrent/{processor_count_spec.rb → utility/processor_count_spec.rb} +0 -0
- data/spec/concurrent/{utilities_spec.rb → utility/timeout_spec.rb} +0 -0
- data/spec/concurrent/utility/timer_spec.rb +52 -0
- metadata +147 -108
- data/lib/concurrent/actor_context.rb +0 -31
- data/lib/concurrent/actor_ref.rb +0 -39
- data/lib/concurrent/atomic.rb +0 -121
- data/lib/concurrent/channel/probe.rb +0 -19
- data/lib/concurrent/count_down_latch.rb +0 -60
- data/lib/concurrent/event.rb +0 -80
- data/lib/concurrent/java_cached_thread_pool.rb +0 -45
- data/lib/concurrent/ruby_cached_thread_pool.rb +0 -37
- data/lib/concurrent/ruby_thread_pool_executor.rb +0 -268
- data/lib/concurrent/simple_actor_ref.rb +0 -124
- data/lib/concurrent/thread_pool_executor.rb +0 -30
- data/spec/concurrent/atomic_spec.rb +0 -201
- data/spec/concurrent/count_down_latch_spec.rb +0 -125
- data/spec/concurrent/safe_task_executor_spec.rb +0 -58
- data/spec/concurrent/simple_actor_ref_spec.rb +0 -219
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require_relative 'dereferenceable_shared'
|
3
|
+
require_relative 'observable_shared'
|
3
4
|
|
4
5
|
module Concurrent
|
5
6
|
|
@@ -18,6 +19,17 @@ module Concurrent
|
|
18
19
|
end.new
|
19
20
|
end
|
20
21
|
|
22
|
+
context '#send_off' do
|
23
|
+
subject { Agent.new 2 }
|
24
|
+
|
25
|
+
it 'executes post and post-off in order' do
|
26
|
+
subject.post { |v| v + 2 }
|
27
|
+
subject.post_off { |v| v * 3 }
|
28
|
+
subject.await
|
29
|
+
subject.value.should eq 12
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
21
33
|
context 'behavior' do
|
22
34
|
|
23
35
|
# dereferenceable
|
@@ -33,11 +45,22 @@ module Concurrent
|
|
33
45
|
end
|
34
46
|
|
35
47
|
def execute_dereferenceable(subject)
|
36
|
-
subject.post{|value| 10 }
|
48
|
+
subject.post { |value| 10 }
|
37
49
|
sleep(0.1)
|
38
50
|
end
|
39
51
|
|
40
52
|
it_should_behave_like :dereferenceable
|
53
|
+
|
54
|
+
# observable
|
55
|
+
|
56
|
+
subject { Agent.new(0) }
|
57
|
+
|
58
|
+
def trigger_observable(observable)
|
59
|
+
observable.post { nil }
|
60
|
+
sleep(0.1)
|
61
|
+
end
|
62
|
+
|
63
|
+
it_should_behave_like :observable
|
41
64
|
end
|
42
65
|
|
43
66
|
context '#initialize' do
|
@@ -59,25 +82,25 @@ module Concurrent
|
|
59
82
|
it 'uses the executor given with the :executor option' do
|
60
83
|
executor.should_receive(:post).with(any_args).and_return(0)
|
61
84
|
agent = Agent.new(0, executor: executor)
|
62
|
-
agent.post{|value| 0 }
|
85
|
+
agent.post { |value| 0 }
|
63
86
|
end
|
64
87
|
|
65
88
|
it 'uses the global operation pool when :operation is true' do
|
66
89
|
Concurrent.configuration.should_receive(:global_operation_pool).and_return(executor)
|
67
90
|
agent = Agent.new(0, operation: true)
|
68
|
-
agent.post{|value| 0 }
|
91
|
+
agent.post { |value| 0 }
|
69
92
|
end
|
70
93
|
|
71
94
|
it 'uses the global task pool when :task is true' do
|
72
95
|
Concurrent.configuration.should_receive(:global_task_pool).and_return(executor)
|
73
96
|
agent = Agent.new(0, task: true)
|
74
|
-
agent.post{|value| 0 }
|
97
|
+
agent.post { |value| 0 }
|
75
98
|
end
|
76
99
|
|
77
100
|
it 'uses the global task pool by default' do
|
78
101
|
Concurrent.configuration.should_receive(:global_task_pool).and_return(executor)
|
79
102
|
agent = Agent.new(0)
|
80
|
-
agent.post{|value| 0 }
|
103
|
+
agent.post { |value| 0 }
|
81
104
|
end
|
82
105
|
end
|
83
106
|
|
@@ -135,20 +158,54 @@ module Concurrent
|
|
135
158
|
context '#post' do
|
136
159
|
|
137
160
|
it 'adds the given block to the queue' do
|
138
|
-
executor.should_receive(:post).with(no_args).exactly(
|
139
|
-
subject.post { sleep(
|
161
|
+
executor.should_receive(:post).with(no_args).exactly(1).times
|
162
|
+
subject.post { sleep(1) }
|
140
163
|
subject.post { nil }
|
141
164
|
subject.post { nil }
|
142
165
|
sleep(0.1)
|
166
|
+
subject.
|
167
|
+
instance_variable_get(:@one_by_one).
|
168
|
+
instance_variable_get(:@stash).
|
169
|
+
size.should eq 2
|
143
170
|
end
|
144
171
|
|
145
172
|
it 'does not add to the queue when no block is given' do
|
146
|
-
executor.should_receive(:post).with(no_args).exactly(
|
147
|
-
subject.post { sleep(100) }
|
173
|
+
executor.should_receive(:post).with(no_args).exactly(0).times
|
148
174
|
subject.post
|
149
|
-
subject.post { nil }
|
150
175
|
sleep(0.1)
|
151
176
|
end
|
177
|
+
|
178
|
+
it 'works with ImmediateExecutor' do
|
179
|
+
agent = Agent.new(0, executor: ImmediateExecutor.new)
|
180
|
+
agent.post { |old| old + 1 }
|
181
|
+
agent.post { |old| old + 1 }
|
182
|
+
agent.value.should eq 2
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
context '#await' do
|
188
|
+
|
189
|
+
it 'waits until already sent updates are done' do
|
190
|
+
fn = false
|
191
|
+
subject.post { fn = true; sleep 0.1 }
|
192
|
+
subject.await
|
193
|
+
fn.should be_true
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'does not waits until updates sent after are done' do
|
197
|
+
fn = false
|
198
|
+
subject.await
|
199
|
+
subject.post { fn = true; sleep 0.1 }
|
200
|
+
fn.should be_false
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'does not alter the value' do
|
204
|
+
subject.post { |v| v + 1 }
|
205
|
+
subject.await
|
206
|
+
subject.value.should eq 1
|
207
|
+
end
|
208
|
+
|
152
209
|
end
|
153
210
|
|
154
211
|
context 'fulfillment' do
|
@@ -227,85 +284,85 @@ module Concurrent
|
|
227
284
|
it 'calls the first exception block with a matching class' do
|
228
285
|
@expected = nil
|
229
286
|
subject.
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
287
|
+
rescue(StandardError) { |ex| @expected = 1 }.
|
288
|
+
rescue(StandardError) { |ex| @expected = 2 }.
|
289
|
+
rescue(StandardError) { |ex| @expected = 3 }
|
290
|
+
subject.post { raise StandardError }
|
291
|
+
sleep(0.1)
|
292
|
+
@expected.should eq 1
|
293
|
+
end
|
237
294
|
|
238
295
|
it 'matches all with a rescue with no class given' do
|
239
296
|
@expected = nil
|
240
297
|
subject.
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
298
|
+
rescue(LoadError) { |ex| @expected = 1 }.
|
299
|
+
rescue { |ex| @expected = 2 }.
|
300
|
+
rescue(StandardError) { |ex| @expected = 3 }
|
301
|
+
subject.post { raise NoMethodError }
|
302
|
+
sleep(0.1)
|
303
|
+
@expected.should eq 2
|
304
|
+
end
|
248
305
|
|
249
306
|
it 'searches associated rescue handlers in order' do
|
250
307
|
@expected = nil
|
251
308
|
subject.
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
309
|
+
rescue(ArgumentError) { |ex| @expected = 1 }.
|
310
|
+
rescue(LoadError) { |ex| @expected = 2 }.
|
311
|
+
rescue(StandardError) { |ex| @expected = 3 }
|
312
|
+
subject.post { raise ArgumentError }
|
313
|
+
sleep(0.1)
|
314
|
+
@expected.should eq 1
|
258
315
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
316
|
+
@expected = nil
|
317
|
+
subject.
|
318
|
+
rescue(ArgumentError) { |ex| @expected = 1 }.
|
319
|
+
rescue(LoadError) { |ex| @expected = 2 }.
|
320
|
+
rescue(StandardError) { |ex| @expected = 3 }
|
321
|
+
subject.post { raise LoadError }
|
322
|
+
sleep(0.1)
|
323
|
+
@expected.should eq 2
|
324
|
+
|
325
|
+
@expected = nil
|
326
|
+
subject.
|
327
|
+
rescue(ArgumentError) { |ex| @expected = 1 }.
|
271
328
|
rescue(LoadError) { |ex| @expected = 2 }.
|
272
329
|
rescue(StandardError) { |ex| @expected = 3 }
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
330
|
+
subject.post { raise StandardError }
|
331
|
+
sleep(0.1)
|
332
|
+
@expected.should eq 3
|
333
|
+
end
|
277
334
|
|
278
335
|
it 'passes the exception object to the matched block' do
|
279
336
|
@expected = nil
|
280
337
|
subject.
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
338
|
+
rescue(ArgumentError) { |ex| @expected = ex }.
|
339
|
+
rescue(LoadError) { |ex| @expected = ex }.
|
340
|
+
rescue(StandardError) { |ex| @expected = ex }
|
341
|
+
subject.post { raise StandardError }
|
342
|
+
sleep(0.1)
|
343
|
+
@expected.should be_a(StandardError)
|
344
|
+
end
|
288
345
|
|
289
346
|
it 'ignores rescuers without a block' do
|
290
347
|
@expected = nil
|
291
348
|
subject.
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
349
|
+
rescue(StandardError).
|
350
|
+
rescue(StandardError) { |ex| @expected = ex }
|
351
|
+
subject.post { raise StandardError }
|
352
|
+
sleep(0.1)
|
353
|
+
@expected.should be_a(StandardError)
|
354
|
+
end
|
298
355
|
|
299
356
|
it 'supresses the exception if no rescue matches' do
|
300
357
|
lambda {
|
301
358
|
subject.
|
302
|
-
|
303
|
-
|
304
|
-
|
359
|
+
rescue(ArgumentError) { |ex| @expected = ex }.
|
360
|
+
rescue(NotImplementedError) { |ex| @expected = ex }.
|
361
|
+
rescue(NoMethodError) { |ex| @expected = ex }
|
305
362
|
subject.post { raise StandardError }
|
306
363
|
sleep(0.1)
|
307
364
|
}.should_not raise_error
|
308
|
-
|
365
|
+
end
|
309
366
|
|
310
367
|
it 'suppresses exceptions thrown from rescue handlers' do
|
311
368
|
lambda {
|
@@ -353,6 +410,46 @@ module Concurrent
|
|
353
410
|
end
|
354
411
|
end
|
355
412
|
|
413
|
+
context 'clojure-like behaviour' do
|
414
|
+
it 'does not block dereferencing when updating the value' do
|
415
|
+
continue = IVar.new
|
416
|
+
agent = Agent.new(0, executor: executor)
|
417
|
+
agent.post { |old| old + continue.value }
|
418
|
+
sleep 0.1
|
419
|
+
Concurrent.timeout(0.2) { agent.value.should eq 0 }
|
420
|
+
continue.set 1
|
421
|
+
sleep 0.1
|
422
|
+
end
|
423
|
+
|
424
|
+
it 'does not allow to execute two updates at the same time' do
|
425
|
+
agent = Agent.new(0, executor: executor)
|
426
|
+
continue1 = IVar.new
|
427
|
+
continue2 = IVar.new
|
428
|
+
f1 = f2 = false
|
429
|
+
agent.post { |old| f1 = true; old + continue1.value }
|
430
|
+
agent.post { |old| f2 = true; old + continue2.value }
|
431
|
+
|
432
|
+
sleep 0.1
|
433
|
+
f1.should eq true
|
434
|
+
f2.should eq false
|
435
|
+
agent.value.should eq 0
|
436
|
+
|
437
|
+
continue1.set 1
|
438
|
+
sleep 0.1
|
439
|
+
f1.should eq true
|
440
|
+
f2.should eq true
|
441
|
+
agent.value.should eq 1
|
442
|
+
|
443
|
+
continue2.set 1
|
444
|
+
sleep 0.1
|
445
|
+
f1.should eq true
|
446
|
+
f2.should eq true
|
447
|
+
agent.value.should eq 2
|
448
|
+
end
|
449
|
+
|
450
|
+
it 'waits with sending functions to other agents until update is done'
|
451
|
+
end
|
452
|
+
|
356
453
|
context 'aliases' do
|
357
454
|
|
358
455
|
it 'aliases #deref for #value' do
|
@@ -398,14 +495,6 @@ module Concurrent
|
|
398
495
|
sleep(0.1)
|
399
496
|
@expected.should be_true
|
400
497
|
end
|
401
|
-
|
402
|
-
it 'aliases #add_watch for #add_observer' do
|
403
|
-
agent = Agent.new(0, executor: executor)
|
404
|
-
agent.add_watch(observer)
|
405
|
-
agent.post { 10 }
|
406
|
-
sleep(0.1)
|
407
|
-
observer.value.should eq 10
|
408
|
-
end
|
409
498
|
end
|
410
499
|
end
|
411
500
|
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
share_examples_for :atomic_boolean do
|
4
|
+
|
5
|
+
describe 'construction' do
|
6
|
+
|
7
|
+
it 'sets the initial value' do
|
8
|
+
described_class.new(true).value.should be_true
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'defaults the initial value to false' do
|
12
|
+
described_class.new.value.should be_false
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'evaluates the truthiness of a true value' do
|
16
|
+
described_class.new(10).value.should be_true
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'evaluates the truthiness of a false value' do
|
20
|
+
described_class.new(nil).value.should be_false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#value' do
|
25
|
+
|
26
|
+
it 'returns the current value' do
|
27
|
+
counter = described_class.new(true)
|
28
|
+
counter.value.should be_true
|
29
|
+
counter.make_false
|
30
|
+
counter.value.should be_false
|
31
|
+
counter.make_true
|
32
|
+
counter.value.should be_true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#value=' do
|
37
|
+
|
38
|
+
it 'sets the #value to the given `Boolean`' do
|
39
|
+
atomic = described_class.new(true)
|
40
|
+
atomic.value = false
|
41
|
+
atomic.value.should be_false
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns the new value' do
|
45
|
+
atomic = described_class.new(false)
|
46
|
+
(atomic.value = true).should be_true
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'evaluates the truthiness of a true value' do
|
50
|
+
atomic = described_class.new(false)
|
51
|
+
atomic.value = 10
|
52
|
+
atomic.value.should be_true
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'evaluates the truthiness of a false value' do
|
56
|
+
atomic = described_class.new(true)
|
57
|
+
atomic.value = nil
|
58
|
+
atomic.value.should be_false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#true?' do
|
63
|
+
|
64
|
+
specify { described_class.new(true).true?.should be_true }
|
65
|
+
|
66
|
+
specify { described_class.new(false).true?.should be_false }
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#false?' do
|
70
|
+
|
71
|
+
specify { described_class.new(true).false?.should be_false }
|
72
|
+
|
73
|
+
specify { described_class.new(false).false?.should be_true }
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#make_true' do
|
77
|
+
|
78
|
+
it 'makes a false value true and returns true' do
|
79
|
+
subject = described_class.new(false)
|
80
|
+
subject.make_true.should be_true
|
81
|
+
subject.value.should be_true
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'keeps a true value true and returns false' do
|
85
|
+
subject = described_class.new(true)
|
86
|
+
subject.make_true.should be_false
|
87
|
+
subject.value.should be_true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#make_false' do
|
92
|
+
|
93
|
+
it 'makes a true value false and returns true' do
|
94
|
+
subject = described_class.new(true)
|
95
|
+
subject.make_false.should be_true
|
96
|
+
subject.value.should be_false
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'keeps a false value false and returns false' do
|
100
|
+
subject = described_class.new(false)
|
101
|
+
subject.make_false.should be_false
|
102
|
+
subject.value.should be_false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
module Concurrent
|
108
|
+
|
109
|
+
describe MutexAtomicBoolean do
|
110
|
+
|
111
|
+
it_should_behave_like :atomic_boolean
|
112
|
+
|
113
|
+
specify 'construction is synchronized' do
|
114
|
+
mutex = double('mutex')
|
115
|
+
Mutex.should_receive(:new).once.with(no_args).and_return(mutex)
|
116
|
+
described_class.new
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'instance methods' do
|
120
|
+
|
121
|
+
before(:each) do
|
122
|
+
mutex = double('mutex')
|
123
|
+
Mutex.stub(:new).with(no_args).and_return(mutex)
|
124
|
+
mutex.should_receive(:lock)
|
125
|
+
mutex.should_receive(:unlock)
|
126
|
+
end
|
127
|
+
|
128
|
+
specify 'value is synchronized' do
|
129
|
+
described_class.new.value
|
130
|
+
end
|
131
|
+
|
132
|
+
specify 'value= is synchronized' do
|
133
|
+
described_class.new.value = 10
|
134
|
+
end
|
135
|
+
|
136
|
+
specify 'true? is synchronized' do
|
137
|
+
described_class.new.true?
|
138
|
+
end
|
139
|
+
|
140
|
+
specify 'false? is synchronized' do
|
141
|
+
described_class.new.false?
|
142
|
+
end
|
143
|
+
|
144
|
+
specify 'make_true is synchronized' do
|
145
|
+
described_class.new.make_true
|
146
|
+
end
|
147
|
+
|
148
|
+
specify 'make_false is synchronized' do
|
149
|
+
described_class.new.make_false
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
if jruby?
|
155
|
+
|
156
|
+
describe JavaAtomicBoolean do
|
157
|
+
it_should_behave_like :atomic_boolean
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe AtomicBoolean do
|
162
|
+
if jruby?
|
163
|
+
it 'inherits from JavaAtomicBoolean' do
|
164
|
+
AtomicBoolean.ancestors.should include(JavaAtomicBoolean)
|
165
|
+
end
|
166
|
+
else
|
167
|
+
it 'inherits from MutexAtomicBoolean' do
|
168
|
+
AtomicBoolean.ancestors.should include(MutexAtomicBoolean)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|