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.
- checksums.yaml +4 -4
- data/README.md +55 -51
- data/lib/concurrent/actress/ad_hoc.rb +6 -0
- data/lib/concurrent/actress/context.rb +10 -8
- data/lib/concurrent/actress/core.rb +44 -20
- data/lib/concurrent/actress/core_delegations.rb +5 -0
- data/lib/concurrent/actress/envelope.rb +21 -5
- data/lib/concurrent/actress/reference.rb +5 -5
- data/lib/concurrent/actress.rb +152 -6
- data/lib/concurrent/agent.rb +9 -9
- data/lib/concurrent/atomic.rb +46 -0
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
- data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
- data/lib/concurrent/atomic_reference/jruby.rb +8 -0
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
- data/lib/concurrent/atomic_reference/rbx.rb +16 -0
- data/lib/concurrent/atomic_reference/ruby.rb +16 -0
- data/lib/concurrent/atomics.rb +1 -1
- data/lib/concurrent/configuration.rb +7 -2
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +0 -1
- data/lib/concurrent/executor/{one_by_one.rb → serialized_execution.rb} +21 -8
- data/lib/concurrent/executor/timer_set.rb +6 -1
- data/lib/concurrent/executors.rb +1 -1
- data/lib/concurrent/logging.rb +1 -1
- data/lib/concurrent/observable.rb +1 -1
- data/lib/concurrent/supervisor.rb +1 -1
- data/lib/concurrent/timer_task.rb +0 -36
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent.rb +3 -4
- data/lib/concurrent_ruby_ext.so +0 -0
- data/lib/extension_helper.rb +9 -0
- metadata +19 -152
- data/lib/concurrent/actor/actor.rb +0 -270
- data/lib/concurrent/actor/postable.rb +0 -102
- data/lib/concurrent/actors.rb +0 -2
- data/lib/concurrent/actress/doc.md +0 -53
- data/lib/concurrent/atomic/atomic.rb +0 -48
- data/lib/concurrent/runnable.rb +0 -90
- data/lib/concurrent/stoppable.rb +0 -20
- data/spec/concurrent/actor/actor_spec.rb +0 -376
- data/spec/concurrent/actor/postable_shared.rb +0 -218
- data/spec/concurrent/actress_spec.rb +0 -191
- data/spec/concurrent/agent_spec.rb +0 -500
- data/spec/concurrent/async_spec.rb +0 -352
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
- data/spec/concurrent/atomic/atomic_spec.rb +0 -133
- data/spec/concurrent/atomic/condition_spec.rb +0 -171
- data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
- data/spec/concurrent/atomic/event_spec.rb +0 -200
- data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
- data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
- data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
- data/spec/concurrent/channel/channel_spec.rb +0 -39
- data/spec/concurrent/channel/probe_spec.rb +0 -77
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
- data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
- data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
- data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
- data/spec/concurrent/configuration_spec.rb +0 -71
- data/spec/concurrent/dataflow_spec.rb +0 -242
- data/spec/concurrent/delay_spec.rb +0 -91
- data/spec/concurrent/dereferenceable_shared.rb +0 -146
- data/spec/concurrent/exchanger_spec.rb +0 -66
- data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
- data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
- data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
- data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
- data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
- data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
- data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
- data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
- data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
- data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
- data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
- data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
- data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
- data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
- data/spec/concurrent/executor/thread_pool_shared.rb +0 -239
- data/spec/concurrent/executor/timer_set_spec.rb +0 -183
- data/spec/concurrent/future_spec.rb +0 -329
- data/spec/concurrent/ivar_spec.rb +0 -215
- data/spec/concurrent/mvar_spec.rb +0 -380
- data/spec/concurrent/obligation_shared.rb +0 -102
- data/spec/concurrent/obligation_spec.rb +0 -282
- data/spec/concurrent/observable_shared.rb +0 -177
- data/spec/concurrent/observable_spec.rb +0 -56
- data/spec/concurrent/options_parser_spec.rb +0 -71
- data/spec/concurrent/promise_spec.rb +0 -367
- data/spec/concurrent/runnable_shared.rb +0 -68
- data/spec/concurrent/runnable_spec.rb +0 -235
- data/spec/concurrent/scheduled_task_spec.rb +0 -342
- data/spec/concurrent/stoppable_shared.rb +0 -37
- data/spec/concurrent/supervisor_spec.rb +0 -1148
- data/spec/concurrent/timer_task_spec.rb +0 -258
- data/spec/concurrent/tvar_spec.rb +0 -137
- data/spec/concurrent/utility/processor_count_spec.rb +0 -20
- data/spec/concurrent/utility/timeout_spec.rb +0 -50
- data/spec/concurrent/utility/timer_spec.rb +0 -52
- data/spec/spec_helper.rb +0 -31
- data/spec/support/example_group_extensions.rb +0 -48
- data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
- /data/{LICENSE → LICENSE.txt} +0 -0
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
module Concurrent
|
|
2
|
-
|
|
3
|
-
class MutexAtomic
|
|
4
|
-
|
|
5
|
-
def initialize(init = nil)
|
|
6
|
-
@value = init
|
|
7
|
-
@mutex = Mutex.new
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def value
|
|
11
|
-
@mutex.lock
|
|
12
|
-
@value
|
|
13
|
-
ensure
|
|
14
|
-
@mutex.unlock
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def value=(value)
|
|
18
|
-
@mutex.lock
|
|
19
|
-
@value = value
|
|
20
|
-
ensure
|
|
21
|
-
@mutex.unlock
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def modify
|
|
25
|
-
@mutex.lock
|
|
26
|
-
result = yield @value
|
|
27
|
-
@value = result
|
|
28
|
-
ensure
|
|
29
|
-
@mutex.unlock
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def compare_and_set(expect, update)
|
|
33
|
-
@mutex.lock
|
|
34
|
-
if @value == expect
|
|
35
|
-
@value = update
|
|
36
|
-
true
|
|
37
|
-
else
|
|
38
|
-
false
|
|
39
|
-
end
|
|
40
|
-
ensure
|
|
41
|
-
@mutex.unlock
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
class Atomic < MutexAtomic
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
end
|
data/lib/concurrent/runnable.rb
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
require 'thread'
|
|
2
|
-
|
|
3
|
-
require 'concurrent/errors'
|
|
4
|
-
|
|
5
|
-
module Concurrent
|
|
6
|
-
|
|
7
|
-
module Runnable
|
|
8
|
-
|
|
9
|
-
class Context
|
|
10
|
-
attr_reader :runner, :thread
|
|
11
|
-
def initialize(runner)
|
|
12
|
-
@runner = runner
|
|
13
|
-
@thread = Thread.new(runner) do |runner|
|
|
14
|
-
Thread.abort_on_exception = false
|
|
15
|
-
runner.run
|
|
16
|
-
end
|
|
17
|
-
@thread.join(0.1) # let the thread start
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def self.included(base)
|
|
22
|
-
|
|
23
|
-
class << base
|
|
24
|
-
|
|
25
|
-
def run!(*args, &block)
|
|
26
|
-
runner = self.new(*args, &block)
|
|
27
|
-
return Context.new(runner)
|
|
28
|
-
rescue => ex
|
|
29
|
-
return nil
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def run!(abort_on_exception = false)
|
|
35
|
-
raise LifecycleError.new('already running') if @running
|
|
36
|
-
thread = Thread.new do
|
|
37
|
-
Thread.current.abort_on_exception = abort_on_exception
|
|
38
|
-
self.run
|
|
39
|
-
end
|
|
40
|
-
thread.join(0.1) # let the thread start
|
|
41
|
-
return thread
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def run
|
|
45
|
-
mutex.synchronize do
|
|
46
|
-
raise LifecycleError.new('already running') if @running
|
|
47
|
-
raise LifecycleError.new('#on_task not implemented') unless self.respond_to?(:on_task, true)
|
|
48
|
-
on_run if respond_to?(:on_run, true)
|
|
49
|
-
@running = true
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
loop do
|
|
53
|
-
break unless @running
|
|
54
|
-
on_task
|
|
55
|
-
break unless @running
|
|
56
|
-
Thread.pass
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
after_run if respond_to?(:after_run, true)
|
|
60
|
-
return true
|
|
61
|
-
rescue LifecycleError => ex
|
|
62
|
-
@running = false
|
|
63
|
-
raise ex
|
|
64
|
-
rescue => ex
|
|
65
|
-
@running = false
|
|
66
|
-
return false
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def stop
|
|
70
|
-
return true unless @running
|
|
71
|
-
mutex.synchronize do
|
|
72
|
-
@running = false
|
|
73
|
-
on_stop if respond_to?(:on_stop, true)
|
|
74
|
-
end
|
|
75
|
-
return true
|
|
76
|
-
rescue => ex
|
|
77
|
-
return false
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def running?
|
|
81
|
-
return @running == true
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
protected
|
|
85
|
-
|
|
86
|
-
def mutex
|
|
87
|
-
@mutex ||= Mutex.new
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
data/lib/concurrent/stoppable.rb
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require 'concurrent/runnable'
|
|
2
|
-
|
|
3
|
-
module Concurrent
|
|
4
|
-
|
|
5
|
-
module Stoppable
|
|
6
|
-
|
|
7
|
-
def before_stop(&block)
|
|
8
|
-
raise ArgumentError.new('no block given') unless block_given?
|
|
9
|
-
raise Runnable::LifecycleError.new('#before_stop already set') if @before_stop_proc
|
|
10
|
-
@before_stop_proc = block
|
|
11
|
-
self
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
protected
|
|
15
|
-
|
|
16
|
-
def before_stop_proc
|
|
17
|
-
@before_stop_proc
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,376 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require_relative 'postable_shared'
|
|
3
|
-
require_relative '../runnable_shared'
|
|
4
|
-
|
|
5
|
-
module Concurrent
|
|
6
|
-
|
|
7
|
-
describe Actor do
|
|
8
|
-
|
|
9
|
-
before do
|
|
10
|
-
# suppress deprecation warnings.
|
|
11
|
-
Concurrent::Actor.any_instance.stub(:warn)
|
|
12
|
-
Concurrent::Actor.stub(:warn)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
let(:actor_class) do
|
|
16
|
-
Class.new(Actor) do
|
|
17
|
-
attr_reader :last_message
|
|
18
|
-
def initialize(&block)
|
|
19
|
-
@task = block
|
|
20
|
-
super()
|
|
21
|
-
end
|
|
22
|
-
def act(*message)
|
|
23
|
-
@last_message = message
|
|
24
|
-
@task.call(*message) unless @task.nil?
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
## :runnable
|
|
30
|
-
subject { Class.new(actor_class).new }
|
|
31
|
-
it_should_behave_like :runnable
|
|
32
|
-
|
|
33
|
-
## :postable
|
|
34
|
-
|
|
35
|
-
let!(:postable_class){ actor_class }
|
|
36
|
-
|
|
37
|
-
let(:sender_class) do
|
|
38
|
-
Class.new(Actor) do
|
|
39
|
-
def act(*message)
|
|
40
|
-
if message.first.is_a?(Exception)
|
|
41
|
-
raise message.first
|
|
42
|
-
else
|
|
43
|
-
return message.first
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
let(:sender) { sender_class.new }
|
|
50
|
-
let(:receiver) { postable_class.new }
|
|
51
|
-
|
|
52
|
-
it_should_behave_like :postable
|
|
53
|
-
|
|
54
|
-
context '#run' do
|
|
55
|
-
|
|
56
|
-
it 'empties the queue' do
|
|
57
|
-
@thread = Thread.new{ subject.run }
|
|
58
|
-
@thread.join(0.1)
|
|
59
|
-
q = subject.instance_variable_get(:@queue)
|
|
60
|
-
q.size.should == 0
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
context '#stop' do
|
|
65
|
-
|
|
66
|
-
it 'empties the queue' do
|
|
67
|
-
actor = actor_class.new{|msg| sleep }
|
|
68
|
-
@thread = Thread.new{ actor.run }
|
|
69
|
-
10.times { actor.post(true) }
|
|
70
|
-
@thread.join(0.1)
|
|
71
|
-
actor.stop
|
|
72
|
-
@thread.join(0.1)
|
|
73
|
-
q = actor.instance_variable_get(:@queue)
|
|
74
|
-
if q.size >= 1
|
|
75
|
-
q.pop.should == :stop
|
|
76
|
-
else
|
|
77
|
-
q.size.should == 0
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it 'pushes a :stop message onto the queue' do
|
|
82
|
-
@thread = Thread.new{ subject.run }
|
|
83
|
-
@thread.join(0.1)
|
|
84
|
-
q = subject.instance_variable_get(:@queue)
|
|
85
|
-
q.should_receive(:push).once.with(:stop)
|
|
86
|
-
subject.stop
|
|
87
|
-
@thread.join(0.1)
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
context 'exception handling' do
|
|
92
|
-
|
|
93
|
-
#it 'supresses exceptions thrown when handling messages' do
|
|
94
|
-
#pending('intermittently failing; deprecated')
|
|
95
|
-
#actor = actor_class.new{|msg| raise StandardError }
|
|
96
|
-
#@thread = Thread.new{ actor.run }
|
|
97
|
-
#expect {
|
|
98
|
-
#@thread.join(0.1)
|
|
99
|
-
#10.times { actor.post(true) }
|
|
100
|
-
#}.not_to raise_error
|
|
101
|
-
#actor.stop
|
|
102
|
-
#end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
context 'observation' do
|
|
106
|
-
|
|
107
|
-
let(:actor_class) do
|
|
108
|
-
Class.new(Actor) do
|
|
109
|
-
def act(*message)
|
|
110
|
-
if message.first.is_a?(Exception)
|
|
111
|
-
raise message.first
|
|
112
|
-
else
|
|
113
|
-
return message.first
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
subject { Class.new(actor_class).new }
|
|
120
|
-
|
|
121
|
-
let(:observer) do
|
|
122
|
-
Class.new {
|
|
123
|
-
attr_reader :time
|
|
124
|
-
attr_reader :message
|
|
125
|
-
attr_reader :value
|
|
126
|
-
attr_reader :reason
|
|
127
|
-
def update(time, message, value, reason)
|
|
128
|
-
@time = time
|
|
129
|
-
@message = message
|
|
130
|
-
@value = value
|
|
131
|
-
@reason = reason
|
|
132
|
-
end
|
|
133
|
-
}.new
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
#it 'notifies observers when a message is successfully handled' do
|
|
137
|
-
#pending('intermittently failing; deprecated')
|
|
138
|
-
#observer.should_receive(:update).exactly(10).times.with(any_args())
|
|
139
|
-
#subject.add_observer(observer)
|
|
140
|
-
#@thread = Thread.new{ subject.run }
|
|
141
|
-
#@thread.join(0.1)
|
|
142
|
-
#10.times { subject.post(42) }
|
|
143
|
-
#@thread.join(0.1)
|
|
144
|
-
#end
|
|
145
|
-
|
|
146
|
-
#it 'notifies observers when a message raises an exception' do
|
|
147
|
-
#pending('intermittently failing; deprecated')
|
|
148
|
-
#error = StandardError.new
|
|
149
|
-
#observer.should_receive(:update).exactly(10).times.with(any_args())
|
|
150
|
-
#subject.add_observer(observer)
|
|
151
|
-
#@thread = Thread.new{ subject.run }
|
|
152
|
-
#@thread.join(0.1)
|
|
153
|
-
#10.times { subject.post(error) }
|
|
154
|
-
#@thread.join(0.1)
|
|
155
|
-
#end
|
|
156
|
-
|
|
157
|
-
it 'passes the time, message, value, and reason to the observer on success' do
|
|
158
|
-
subject.add_observer(observer)
|
|
159
|
-
@thread = Thread.new{ subject.run }
|
|
160
|
-
@thread.join(0.1)
|
|
161
|
-
subject.post(42)
|
|
162
|
-
@thread.join(0.1)
|
|
163
|
-
|
|
164
|
-
observer.time.should be_a(Time)
|
|
165
|
-
observer.message.should eq [42]
|
|
166
|
-
observer.value.should eq 42
|
|
167
|
-
observer.reason.should be_nil
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
it 'passes the time, message, value, and reason to the observer on exception' do
|
|
171
|
-
error = StandardError.new
|
|
172
|
-
subject.add_observer(observer)
|
|
173
|
-
@thread = Thread.new{ subject.run }
|
|
174
|
-
@thread.join(0.1)
|
|
175
|
-
subject.post(error)
|
|
176
|
-
@thread.join(0.1)
|
|
177
|
-
|
|
178
|
-
observer.time.should be_a(Time)
|
|
179
|
-
observer.message.should eq [error]
|
|
180
|
-
observer.value.should be_nil
|
|
181
|
-
observer.reason.should be_a(Exception)
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
context '#pool' do
|
|
186
|
-
|
|
187
|
-
let(:clazz){ Class.new(actor_class) }
|
|
188
|
-
|
|
189
|
-
it 'raises an exception if the count is zero or less' do
|
|
190
|
-
expect {
|
|
191
|
-
clazz.pool(0)
|
|
192
|
-
}.to raise_error(ArgumentError)
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
it 'creates the requested number of pool' do
|
|
196
|
-
mailbox, pool = clazz.pool(5)
|
|
197
|
-
pool.size.should == 5
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
it 'passes all optional arguments to the individual constructors' do
|
|
201
|
-
clazz.should_receive(:new).with(1, 2, 3).exactly(5).times
|
|
202
|
-
clazz.pool(5, 1, 2, 3)
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
it 'passes a duplicate of the given block to each actor in the pool' do
|
|
206
|
-
block = proc{ nil }
|
|
207
|
-
block.should_receive(:dup).exactly(5).times.and_return(proc{ nil })
|
|
208
|
-
mailbox, pool = clazz.pool(5, &block)
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
it 'gives all pool the same mailbox' do
|
|
212
|
-
mailbox, pool = clazz.pool(2)
|
|
213
|
-
mbox1 = pool.first.instance_variable_get(:@queue)
|
|
214
|
-
mbox2 = pool.last.instance_variable_get(:@queue)
|
|
215
|
-
mbox1.should eq mbox2
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
it 'returns a Poolbox as the first retval' do
|
|
219
|
-
mailbox, pool = clazz.pool(2)
|
|
220
|
-
mailbox.should be_a(Actor::Poolbox)
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
it 'gives the Poolbox the same mailbox as the pool' do
|
|
224
|
-
mailbox, pool = clazz.pool(1)
|
|
225
|
-
mbox1 = mailbox.instance_variable_get(:@queue)
|
|
226
|
-
mbox2 = pool.first.instance_variable_get(:@queue)
|
|
227
|
-
mbox1.should eq mbox2
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
it 'returns an array of pool as the second retval' do
|
|
231
|
-
mailbox, pool = clazz.pool(2)
|
|
232
|
-
pool.each do |actor|
|
|
233
|
-
actor.should be_a(clazz)
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
it 'posts to the mailbox with Poolbox#post' do
|
|
238
|
-
mailbox, pool = clazz.pool(1)
|
|
239
|
-
@thread = Thread.new{ pool.first.run }
|
|
240
|
-
sleep(0.1)
|
|
241
|
-
mailbox.post(42)
|
|
242
|
-
sleep(0.1)
|
|
243
|
-
pool.first.last_message.should eq [42]
|
|
244
|
-
pool.first.stop
|
|
245
|
-
@thread.kill
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
#it 'posts to the mailbox with Poolbox#<<' do
|
|
249
|
-
#pending('intermittently failing; deprecated')
|
|
250
|
-
#@expected = false
|
|
251
|
-
#mailbox, pool = clazz.pool(1)
|
|
252
|
-
#@thread = Thread.new{ pool.first.run }
|
|
253
|
-
#sleep(0.1)
|
|
254
|
-
#mailbox << 42
|
|
255
|
-
#sleep(0.1)
|
|
256
|
-
#pool.first.last_message.should eq [42]
|
|
257
|
-
#pool.first.stop
|
|
258
|
-
#@thread.kill
|
|
259
|
-
#end
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
context 'subclassing' do
|
|
263
|
-
|
|
264
|
-
after(:each) do
|
|
265
|
-
@thread.kill unless @thread.nil?
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
context '#pool' do
|
|
269
|
-
|
|
270
|
-
it 'creates pool of the appropriate subclass' do
|
|
271
|
-
actor = Class.new(actor_class)
|
|
272
|
-
mailbox, pool = actor.pool(1)
|
|
273
|
-
pool.first.should be_a(actor)
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
context '#act overloading' do
|
|
278
|
-
|
|
279
|
-
it 'raises an exception if #act is not implemented in the subclass' do
|
|
280
|
-
actor = Class.new(Actor).new
|
|
281
|
-
@thread = Thread.new{ actor.run }
|
|
282
|
-
@thread.join(0.1)
|
|
283
|
-
expect {
|
|
284
|
-
actor.post(:foo)
|
|
285
|
-
@thread.join(0.1)
|
|
286
|
-
}.to raise_error(NotImplementedError)
|
|
287
|
-
actor.stop
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
it 'uses the subclass #act implementation' do
|
|
291
|
-
actor = actor_class.new{|*args| @expected = true }
|
|
292
|
-
@thread = Thread.new{ actor.run }
|
|
293
|
-
@thread.join(0.1)
|
|
294
|
-
actor.post(:foo)
|
|
295
|
-
@thread.join(0.1)
|
|
296
|
-
actor.last_message.should eq [:foo]
|
|
297
|
-
actor.stop
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
context '#on_error overloading' do
|
|
302
|
-
|
|
303
|
-
let(:bad_actor) do
|
|
304
|
-
Class.new(actor_class) {
|
|
305
|
-
attr_reader :last_error
|
|
306
|
-
def act(*message)
|
|
307
|
-
raise StandardError
|
|
308
|
-
end
|
|
309
|
-
def on_error(*args)
|
|
310
|
-
@last_error = args
|
|
311
|
-
end
|
|
312
|
-
}
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
it 'uses the subclass #on_error implementation' do
|
|
316
|
-
actor = bad_actor.new
|
|
317
|
-
@thread = Thread.new{ actor.run }
|
|
318
|
-
@thread.join(0.1)
|
|
319
|
-
actor.post(42)
|
|
320
|
-
@thread.join(0.1)
|
|
321
|
-
actor.last_error[0].should be_a(Time)
|
|
322
|
-
actor.last_error[1].should eq [42]
|
|
323
|
-
actor.last_error[2].should be_a(StandardError)
|
|
324
|
-
actor.stop
|
|
325
|
-
end
|
|
326
|
-
end
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
context 'supervision' do
|
|
330
|
-
|
|
331
|
-
it 'can be started by a Supervisor' do
|
|
332
|
-
actor = actor_class.new
|
|
333
|
-
supervisor = Supervisor.new
|
|
334
|
-
supervisor.add_worker(actor)
|
|
335
|
-
|
|
336
|
-
actor.should_receive(:run).with(no_args())
|
|
337
|
-
supervisor.run!
|
|
338
|
-
sleep(0.1)
|
|
339
|
-
|
|
340
|
-
supervisor.stop
|
|
341
|
-
sleep(0.1)
|
|
342
|
-
actor.stop
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
it 'can receive messages while under supervision' do
|
|
346
|
-
@expected = false
|
|
347
|
-
actor = actor_class.new{|*args| @expected = true}
|
|
348
|
-
supervisor = Supervisor.new
|
|
349
|
-
supervisor.add_worker(actor)
|
|
350
|
-
supervisor.run!
|
|
351
|
-
sleep(0.1)
|
|
352
|
-
|
|
353
|
-
actor.post(42)
|
|
354
|
-
sleep(0.1)
|
|
355
|
-
@expected.should be_true
|
|
356
|
-
|
|
357
|
-
supervisor.stop
|
|
358
|
-
sleep(0.1)
|
|
359
|
-
actor.stop
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
it 'can be stopped by a supervisor' do
|
|
363
|
-
actor = actor_class.new
|
|
364
|
-
supervisor = Supervisor.new
|
|
365
|
-
supervisor.add_worker(actor)
|
|
366
|
-
|
|
367
|
-
supervisor.run!
|
|
368
|
-
sleep(0.1)
|
|
369
|
-
|
|
370
|
-
actor.should_receive(:stop).with(no_args())
|
|
371
|
-
supervisor.stop
|
|
372
|
-
sleep(0.1)
|
|
373
|
-
end
|
|
374
|
-
end
|
|
375
|
-
end
|
|
376
|
-
end
|