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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +16 -0
  3. data/lib/concurrent.rb +9 -29
  4. data/lib/concurrent/{actor.rb → actor/actor.rb} +3 -3
  5. data/lib/concurrent/actor/actor_context.rb +77 -0
  6. data/lib/concurrent/actor/actor_ref.rb +67 -0
  7. data/lib/concurrent/{postable.rb → actor/postable.rb} +1 -1
  8. data/lib/concurrent/actor/simple_actor_ref.rb +94 -0
  9. data/lib/concurrent/actors.rb +5 -0
  10. data/lib/concurrent/agent.rb +81 -47
  11. data/lib/concurrent/async.rb +35 -35
  12. data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
  13. data/lib/concurrent/atomic/atomic_fixnum.rb +170 -0
  14. data/lib/concurrent/{condition.rb → atomic/condition.rb} +0 -0
  15. data/lib/concurrent/{copy_on_notify_observer_set.rb → atomic/copy_on_notify_observer_set.rb} +48 -13
  16. data/lib/concurrent/{copy_on_write_observer_set.rb → atomic/copy_on_write_observer_set.rb} +41 -20
  17. data/lib/concurrent/atomic/count_down_latch.rb +116 -0
  18. data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
  19. data/lib/concurrent/atomic/event.rb +103 -0
  20. data/lib/concurrent/{thread_local_var.rb → atomic/thread_local_var.rb} +0 -0
  21. data/lib/concurrent/atomics.rb +9 -0
  22. data/lib/concurrent/channel/buffered_channel.rb +6 -4
  23. data/lib/concurrent/channel/channel.rb +30 -2
  24. data/lib/concurrent/channel/unbuffered_channel.rb +2 -2
  25. data/lib/concurrent/channel/waitable_list.rb +3 -1
  26. data/lib/concurrent/channels.rb +5 -0
  27. data/lib/concurrent/{channel → collection}/blocking_ring_buffer.rb +16 -5
  28. data/lib/concurrent/collection/priority_queue.rb +305 -0
  29. data/lib/concurrent/{channel → collection}/ring_buffer.rb +6 -1
  30. data/lib/concurrent/collections.rb +3 -0
  31. data/lib/concurrent/configuration.rb +68 -19
  32. data/lib/concurrent/dataflow.rb +9 -9
  33. data/lib/concurrent/delay.rb +21 -13
  34. data/lib/concurrent/dereferenceable.rb +40 -33
  35. data/lib/concurrent/exchanger.rb +3 -0
  36. data/lib/concurrent/{cached_thread_pool.rb → executor/cached_thread_pool.rb} +8 -9
  37. data/lib/concurrent/executor/executor.rb +222 -0
  38. data/lib/concurrent/{fixed_thread_pool.rb → executor/fixed_thread_pool.rb} +6 -7
  39. data/lib/concurrent/{immediate_executor.rb → executor/immediate_executor.rb} +5 -5
  40. data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
  41. data/lib/concurrent/{java_fixed_thread_pool.rb → executor/java_fixed_thread_pool.rb} +7 -11
  42. data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
  43. data/lib/concurrent/{java_thread_pool_executor.rb → executor/java_thread_pool_executor.rb} +66 -77
  44. data/lib/concurrent/executor/one_by_one.rb +65 -0
  45. data/lib/concurrent/{per_thread_executor.rb → executor/per_thread_executor.rb} +4 -4
  46. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
  47. data/lib/concurrent/{ruby_fixed_thread_pool.rb → executor/ruby_fixed_thread_pool.rb} +5 -4
  48. data/lib/concurrent/executor/ruby_single_thread_executor.rb +72 -0
  49. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +282 -0
  50. data/lib/concurrent/{ruby_thread_pool_worker.rb → executor/ruby_thread_pool_worker.rb} +6 -6
  51. data/lib/concurrent/{safe_task_executor.rb → executor/safe_task_executor.rb} +20 -13
  52. data/lib/concurrent/executor/single_thread_executor.rb +35 -0
  53. data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
  54. data/lib/concurrent/executor/timer_set.rb +138 -0
  55. data/lib/concurrent/executors.rb +9 -0
  56. data/lib/concurrent/future.rb +39 -40
  57. data/lib/concurrent/ivar.rb +22 -15
  58. data/lib/concurrent/mvar.rb +2 -1
  59. data/lib/concurrent/obligation.rb +9 -3
  60. data/lib/concurrent/observable.rb +33 -0
  61. data/lib/concurrent/options_parser.rb +46 -0
  62. data/lib/concurrent/promise.rb +23 -24
  63. data/lib/concurrent/scheduled_task.rb +21 -45
  64. data/lib/concurrent/timer_task.rb +204 -126
  65. data/lib/concurrent/tvar.rb +1 -1
  66. data/lib/concurrent/utilities.rb +3 -36
  67. data/lib/concurrent/{processor_count.rb → utility/processor_count.rb} +1 -1
  68. data/lib/concurrent/utility/timeout.rb +36 -0
  69. data/lib/concurrent/utility/timer.rb +21 -0
  70. data/lib/concurrent/version.rb +1 -1
  71. data/lib/concurrent_ruby_ext.bundle +0 -0
  72. data/spec/concurrent/{actor_context_spec.rb → actor/actor_context_spec.rb} +0 -8
  73. data/spec/concurrent/{actor_ref_shared.rb → actor/actor_ref_shared.rb} +9 -59
  74. data/spec/concurrent/{actor_spec.rb → actor/actor_spec.rb} +43 -41
  75. data/spec/concurrent/{postable_shared.rb → actor/postable_shared.rb} +0 -0
  76. data/spec/concurrent/actor/simple_actor_ref_spec.rb +135 -0
  77. data/spec/concurrent/agent_spec.rb +160 -71
  78. data/spec/concurrent/atomic/atomic_boolean_spec.rb +172 -0
  79. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +186 -0
  80. data/spec/concurrent/{condition_spec.rb → atomic/condition_spec.rb} +2 -2
  81. data/spec/concurrent/{copy_on_notify_observer_set_spec.rb → atomic/copy_on_notify_observer_set_spec.rb} +0 -0
  82. data/spec/concurrent/{copy_on_write_observer_set_spec.rb → atomic/copy_on_write_observer_set_spec.rb} +0 -0
  83. data/spec/concurrent/atomic/count_down_latch_spec.rb +151 -0
  84. data/spec/concurrent/atomic/cyclic_barrier_spec.rb +248 -0
  85. data/spec/concurrent/{event_spec.rb → atomic/event_spec.rb} +18 -3
  86. data/spec/concurrent/{observer_set_shared.rb → atomic/observer_set_shared.rb} +15 -6
  87. data/spec/concurrent/{thread_local_var_spec.rb → atomic/thread_local_var_spec.rb} +0 -0
  88. data/spec/concurrent/channel/buffered_channel_spec.rb +1 -1
  89. data/spec/concurrent/channel/channel_spec.rb +6 -4
  90. data/spec/concurrent/channel/probe_spec.rb +37 -9
  91. data/spec/concurrent/channel/unbuffered_channel_spec.rb +2 -2
  92. data/spec/concurrent/{channel → collection}/blocking_ring_buffer_spec.rb +0 -0
  93. data/spec/concurrent/collection/priority_queue_spec.rb +317 -0
  94. data/spec/concurrent/{channel → collection}/ring_buffer_spec.rb +0 -0
  95. data/spec/concurrent/configuration_spec.rb +4 -70
  96. data/spec/concurrent/dereferenceable_shared.rb +5 -4
  97. data/spec/concurrent/exchanger_spec.rb +10 -5
  98. data/spec/concurrent/{cached_thread_pool_shared.rb → executor/cached_thread_pool_shared.rb} +15 -37
  99. data/spec/concurrent/{fixed_thread_pool_shared.rb → executor/fixed_thread_pool_shared.rb} +0 -0
  100. data/spec/concurrent/{global_thread_pool_shared.rb → executor/global_thread_pool_shared.rb} +10 -8
  101. data/spec/concurrent/{immediate_executor_spec.rb → executor/immediate_executor_spec.rb} +0 -0
  102. data/spec/concurrent/{java_cached_thread_pool_spec.rb → executor/java_cached_thread_pool_spec.rb} +1 -21
  103. data/spec/concurrent/{java_fixed_thread_pool_spec.rb → executor/java_fixed_thread_pool_spec.rb} +0 -0
  104. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +21 -0
  105. data/spec/concurrent/{java_thread_pool_executor_spec.rb → executor/java_thread_pool_executor_spec.rb} +0 -0
  106. data/spec/concurrent/{per_thread_executor_spec.rb → executor/per_thread_executor_spec.rb} +0 -4
  107. data/spec/concurrent/{ruby_cached_thread_pool_spec.rb → executor/ruby_cached_thread_pool_spec.rb} +1 -1
  108. data/spec/concurrent/{ruby_fixed_thread_pool_spec.rb → executor/ruby_fixed_thread_pool_spec.rb} +0 -0
  109. data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +18 -0
  110. data/spec/concurrent/{ruby_thread_pool_executor_spec.rb → executor/ruby_thread_pool_executor_spec.rb} +12 -24
  111. data/spec/concurrent/executor/safe_task_executor_spec.rb +103 -0
  112. data/spec/concurrent/{thread_pool_class_cast_spec.rb → executor/thread_pool_class_cast_spec.rb} +12 -0
  113. data/spec/concurrent/{thread_pool_executor_shared.rb → executor/thread_pool_executor_shared.rb} +0 -0
  114. data/spec/concurrent/{thread_pool_shared.rb → executor/thread_pool_shared.rb} +84 -119
  115. data/spec/concurrent/executor/timer_set_spec.rb +183 -0
  116. data/spec/concurrent/future_spec.rb +12 -0
  117. data/spec/concurrent/ivar_spec.rb +11 -1
  118. data/spec/concurrent/observable_shared.rb +173 -0
  119. data/spec/concurrent/observable_spec.rb +51 -0
  120. data/spec/concurrent/options_parser_spec.rb +71 -0
  121. data/spec/concurrent/runnable_shared.rb +6 -0
  122. data/spec/concurrent/scheduled_task_spec.rb +60 -40
  123. data/spec/concurrent/timer_task_spec.rb +130 -144
  124. data/spec/concurrent/{processor_count_spec.rb → utility/processor_count_spec.rb} +0 -0
  125. data/spec/concurrent/{utilities_spec.rb → utility/timeout_spec.rb} +0 -0
  126. data/spec/concurrent/utility/timer_spec.rb +52 -0
  127. metadata +147 -108
  128. data/lib/concurrent/actor_context.rb +0 -31
  129. data/lib/concurrent/actor_ref.rb +0 -39
  130. data/lib/concurrent/atomic.rb +0 -121
  131. data/lib/concurrent/channel/probe.rb +0 -19
  132. data/lib/concurrent/count_down_latch.rb +0 -60
  133. data/lib/concurrent/event.rb +0 -80
  134. data/lib/concurrent/java_cached_thread_pool.rb +0 -45
  135. data/lib/concurrent/ruby_cached_thread_pool.rb +0 -37
  136. data/lib/concurrent/ruby_thread_pool_executor.rb +0 -268
  137. data/lib/concurrent/simple_actor_ref.rb +0 -124
  138. data/lib/concurrent/thread_pool_executor.rb +0 -30
  139. data/spec/concurrent/atomic_spec.rb +0 -201
  140. data/spec/concurrent/count_down_latch_spec.rb +0 -125
  141. data/spec/concurrent/safe_task_executor_spec.rb +0 -58
  142. 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(3).times
139
- subject.post { sleep(100) }
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(2).times
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
- rescue(StandardError) { |ex| @expected = 1 }.
231
- rescue(StandardError) { |ex| @expected = 2 }.
232
- rescue(StandardError) { |ex| @expected = 3 }
233
- subject.post { raise StandardError }
234
- sleep(0.1)
235
- @expected.should eq 1
236
- end
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
- rescue(LoadError) { |ex| @expected = 1 }.
242
- rescue { |ex| @expected = 2 }.
243
- rescue(StandardError) { |ex| @expected = 3 }
244
- subject.post { raise NoMethodError }
245
- sleep(0.1)
246
- @expected.should eq 2
247
- end
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
- rescue(ArgumentError) { |ex| @expected = 1 }.
253
- rescue(LoadError) { |ex| @expected = 2 }.
254
- rescue(StandardError) { |ex| @expected = 3 }
255
- subject.post { raise ArgumentError }
256
- sleep(0.1)
257
- @expected.should eq 1
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
- @expected = nil
260
- subject.
261
- rescue(ArgumentError) { |ex| @expected = 1 }.
262
- rescue(LoadError) { |ex| @expected = 2 }.
263
- rescue(StandardError) { |ex| @expected = 3 }
264
- subject.post { raise LoadError }
265
- sleep(0.1)
266
- @expected.should eq 2
267
-
268
- @expected = nil
269
- subject.
270
- rescue(ArgumentError) { |ex| @expected = 1 }.
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
- subject.post { raise StandardError }
274
- sleep(0.1)
275
- @expected.should eq 3
276
- end
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
- rescue(ArgumentError) { |ex| @expected = ex }.
282
- rescue(LoadError) { |ex| @expected = ex }.
283
- rescue(StandardError) { |ex| @expected = ex }
284
- subject.post { raise StandardError }
285
- sleep(0.1)
286
- @expected.should be_a(StandardError)
287
- end
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
- rescue(StandardError).
293
- rescue(StandardError) { |ex| @expected = ex }
294
- subject.post { raise StandardError }
295
- sleep(0.1)
296
- @expected.should be_a(StandardError)
297
- end
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
- rescue(ArgumentError) { |ex| @expected = ex }.
303
- rescue(NotImplementedError) { |ex| @expected = ex }.
304
- rescue(NoMethodError) { |ex| @expected = ex }
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
- end
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