concurrent-ruby 0.1.1.pre.2 → 0.1.1.pre.3
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.
- data/lib/concurrent.rb +4 -3
- data/lib/concurrent/agent.rb +3 -1
- data/lib/concurrent/defer.rb +4 -4
- data/lib/concurrent/executor.rb +4 -0
- data/lib/concurrent/functions.rb +30 -30
- data/lib/concurrent/future.rb +3 -8
- data/lib/concurrent/global_thread_pool.rb +13 -0
- data/lib/concurrent/null_thread_pool.rb +22 -0
- data/lib/concurrent/promise.rb +4 -10
- data/lib/concurrent/reactor/drb_async_demux.rb +74 -0
- data/lib/concurrent/reactor/tcp_sync_demux.rb +98 -0
- data/lib/concurrent/thread_pool.rb +7 -3
- data/lib/concurrent/version.rb +1 -1
- data/md/defer.md +4 -4
- data/md/promise.md +2 -0
- data/md/thread_pool.md +27 -0
- data/spec/concurrent/agent_spec.rb +5 -1
- data/spec/concurrent/cached_thread_pool_spec.rb +13 -0
- data/spec/concurrent/defer_spec.rb +9 -23
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +13 -10
- data/spec/concurrent/executor_spec.rb +38 -0
- data/spec/concurrent/functions_spec.rb +160 -0
- data/spec/concurrent/future_spec.rb +2 -19
- data/spec/concurrent/global_thread_pool_spec.rb +38 -0
- data/spec/concurrent/null_thread_pool_spec.rb +54 -0
- data/spec/concurrent/promise_spec.rb +6 -0
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +12 -0
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +12 -0
- data/spec/concurrent/reactor_spec.rb +10 -0
- data/spec/concurrent/thread_pool_shared.rb +3 -2
- data/spec/spec_helper.rb +9 -0
- metadata +15 -4
- data/lib/concurrent/drb_async_demux.rb +0 -72
- data/lib/concurrent/tcp_sync_demux.rb +0 -96
@@ -35,7 +35,7 @@ module Concurrent
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def shutdown?
|
38
|
-
return
|
38
|
+
return @status == :shutdown
|
39
39
|
end
|
40
40
|
|
41
41
|
def killed?
|
@@ -44,8 +44,12 @@ module Concurrent
|
|
44
44
|
|
45
45
|
def shutdown
|
46
46
|
atomic {
|
47
|
-
@pool.
|
48
|
-
|
47
|
+
if @pool.empty?
|
48
|
+
@status = :shutdown
|
49
|
+
else
|
50
|
+
@status = :shuttingdown
|
51
|
+
@pool.size.times{ @queue << :stop }
|
52
|
+
end
|
49
53
|
}
|
50
54
|
end
|
51
55
|
|
data/lib/concurrent/version.rb
CHANGED
data/md/defer.md
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
In the pantheon of concurrency objects a `Defer` sits somewhere between `Future` and `Promise`.
|
4
4
|
Inspired by [EventMachine's *defer* method](https://github.com/eventmachine/eventmachine/wiki/EM::Deferrable-and-EM.defer),
|
5
|
-
a `Defer` can be considered a non-blocking `Future` or a simplified, non-blocking `Promise`.
|
5
|
+
a `Defer` can be considered a non-blocking `Future` or a simplified, non-blocking `Promise`. Defers run on the global thread pool.
|
6
6
|
|
7
7
|
Unlike `Future` and `Promise` a defer is non-blocking. The deferred *operation* is performed on another
|
8
8
|
thread. If the *operation* is successful an optional *callback* is called on the same thread as the *operation*.
|
9
9
|
The result of the *operation* is passed to the *callbacl*. If the *operation* fails (by raising an exception)
|
10
|
-
then an optional *errorback* (error callback) is called on
|
11
|
-
|
12
|
-
|
10
|
+
then an optional *errorback* (error callback) is called on the same thread as the *operation*. The raised
|
11
|
+
exception is passed to the *errorback*. The calling thread is never aware of the result of the *operation*.
|
12
|
+
This approach fits much more cleanly within an
|
13
13
|
[event-driven](http://en.wikipedia.org/wiki/Event-driven_programming) application.
|
14
14
|
|
15
15
|
The operation of a `Defer` can easily be simulated using either `Future` or `Promise` and traditional branching
|
data/md/promise.md
CHANGED
@@ -28,6 +28,8 @@ A *timeout* value can be passed to `value` to limit how long the call will block
|
|
28
28
|
block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the
|
29
29
|
maximum number of seconds to block.
|
30
30
|
|
31
|
+
Promises run on the global thread pool.
|
32
|
+
|
31
33
|
## Examples
|
32
34
|
|
33
35
|
Start by requiring promises
|
data/md/thread_pool.md
CHANGED
@@ -151,6 +151,12 @@ $GLOBAL_THREAD_POOL = Concurrent::FixedThreadPool.new(10)
|
|
151
151
|
old_global_pool.shutdown
|
152
152
|
```
|
153
153
|
|
154
|
+
### NullThreadPool
|
155
|
+
|
156
|
+
If for some reason an appliction would be better served by *not* having a global thread pool, the
|
157
|
+
`NullThreadPool` is provided. The `NullThreadPool` is compatible with the global thread pool but
|
158
|
+
it is not an actual thread pool. Instead it spawns a new thread on every call to the `post` method.
|
159
|
+
|
154
160
|
### EventMachine
|
155
161
|
|
156
162
|
The [EventMachine](http://rubyeventmachine.com/) library (source [online](https://github.com/eventmachine/eventmachine))
|
@@ -167,6 +173,27 @@ require 'functional/concurrency'
|
|
167
173
|
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
168
174
|
```
|
169
175
|
|
176
|
+
## Per-class Thread Pools
|
177
|
+
|
178
|
+
Many of the classes in this library use the global thread pool rather than creating new threads.
|
179
|
+
Classes such as `Agent`, `Defer`, and others follow this pattern. There may be cases where a
|
180
|
+
program would be better suited for one or more of these classes used a different thread pool.
|
181
|
+
All classes that use the global thread pool support a class-level `thread_pool` attribute accessor.
|
182
|
+
This property defaults to the global thread pool but can be changed at any time. Once changed, all
|
183
|
+
new instances of that class will use the new thread pool.
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
Concurrent::Agent.thread_pool == $GLOBAL_THREAD_POOL #=> true
|
187
|
+
|
188
|
+
$GLOBAL_THREAD_POOL = Concurrent::FixedThreadPool.new(10) #=> #<Concurrent::FixedThreadPool:0x007fe31130f1f0 ...
|
189
|
+
|
190
|
+
Concurrent::Agent.thread_pool == $GLOBAL_THREAD_POOL #=> false
|
191
|
+
|
192
|
+
Concurrent::Defer.thread_pool = Concurrent::CachedThreadPool.new #=> #<Concurrent::CachedThreadPool:0x007fef1c6b6b48 ...
|
193
|
+
Concurrent::Defer.thread_pool == Concurrent::Agent.thread_pool #=> false
|
194
|
+
Concurrent::Defer.thread_pool == $GLOBAL_THREAD_POOL #=> false
|
195
|
+
```
|
196
|
+
|
170
197
|
## Copyright
|
171
198
|
|
172
199
|
*Concurrent Ruby* is Copyright © 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
|
@@ -15,6 +15,10 @@ module Concurrent
|
|
15
15
|
end.new
|
16
16
|
end
|
17
17
|
|
18
|
+
before(:each) do
|
19
|
+
Agent.thread_pool = FixedThreadPool.new(1)
|
20
|
+
end
|
21
|
+
|
18
22
|
context '#initialize' do
|
19
23
|
|
20
24
|
it 'sets the value to the given initial state' do
|
@@ -34,7 +38,7 @@ module Concurrent
|
|
34
38
|
end
|
35
39
|
|
36
40
|
it 'spawns the worker thread' do
|
37
|
-
|
41
|
+
Agent.thread_pool.should_receive(:post).once.with(any_args())
|
38
42
|
Agent.new(0)
|
39
43
|
end
|
40
44
|
end
|
@@ -10,6 +10,7 @@ module Concurrent
|
|
10
10
|
it_should_behave_like 'Thread Pool'
|
11
11
|
|
12
12
|
context '#initialize' do
|
13
|
+
|
13
14
|
it 'aliases Concurrent#new_cached_thread_pool' do
|
14
15
|
pool = Concurrent.new_cached_thread_pool
|
15
16
|
pool.should be_a(CachedThreadPool)
|
@@ -108,5 +109,17 @@ module Concurrent
|
|
108
109
|
subject.instance_variable_get(:@collector).status.should be_false
|
109
110
|
end
|
110
111
|
end
|
112
|
+
|
113
|
+
context '#status' do
|
114
|
+
|
115
|
+
it 'returns an empty collection when the pool is empty' do
|
116
|
+
subject.status.should be_empty
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'returns one status object for each thread in the pool' do
|
120
|
+
3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
|
121
|
+
subject.status.length.should eq 3
|
122
|
+
end
|
123
|
+
end
|
111
124
|
end
|
112
125
|
end
|
@@ -4,11 +4,11 @@ module Concurrent
|
|
4
4
|
|
5
5
|
describe Defer do
|
6
6
|
|
7
|
-
|
7
|
+
before(:each) do
|
8
|
+
Defer.thread_pool = FixedThreadPool.new(1)
|
9
|
+
end
|
8
10
|
|
9
|
-
|
10
|
-
$GLOBAL_THREAD_POOL = FixedThreadPool.new(1)
|
11
|
-
end
|
11
|
+
context '#initialize' do
|
12
12
|
|
13
13
|
it 'raises an exception if no block or operation given' do
|
14
14
|
lambda {
|
@@ -24,22 +24,15 @@ module Concurrent
|
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'starts the thread if an operation is given' do
|
27
|
-
|
27
|
+
Defer.thread_pool.should_receive(:post).once.with(any_args())
|
28
28
|
operation = proc{ nil }
|
29
29
|
Defer.new(op: operation)
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'does not start the thread if neither a callback or errorback is given' do
|
33
|
-
|
33
|
+
Defer.thread_pool.should_not_receive(:post)
|
34
34
|
Defer.new{ nil }
|
35
35
|
end
|
36
|
-
|
37
|
-
it 'runs on the alternate thread pool if given' do
|
38
|
-
operation = proc{ nil }
|
39
|
-
pool = Concurrent::FixedThreadPool.new(2)
|
40
|
-
pool.should_receive(:post).with(no_args())
|
41
|
-
Defer.new(op: operation, pool: pool)
|
42
|
-
end
|
43
36
|
end
|
44
37
|
|
45
38
|
context '#then' do
|
@@ -126,14 +119,14 @@ module Concurrent
|
|
126
119
|
|
127
120
|
it 'starts the thread if not started' do
|
128
121
|
deferred = Defer.new{ nil }
|
129
|
-
|
122
|
+
Defer.thread_pool.should_receive(:post).once.with(any_args())
|
130
123
|
deferred.go
|
131
124
|
end
|
132
125
|
|
133
126
|
it 'does nothing if called more than once' do
|
134
127
|
deferred = Defer.new{ nil }
|
135
128
|
deferred.go
|
136
|
-
|
129
|
+
Defer.thread_pool.should_not_receive(:post)
|
137
130
|
deferred.go
|
138
131
|
end
|
139
132
|
|
@@ -142,16 +135,9 @@ module Concurrent
|
|
142
135
|
callback = proc{|result| nil }
|
143
136
|
errorback = proc{|ex| nil }
|
144
137
|
deferred = Defer.new(op: operation, callback: callback, errorback: errorback)
|
145
|
-
|
138
|
+
Defer.thread_pool.should_not_receive(:post)
|
146
139
|
deferred.go
|
147
140
|
end
|
148
|
-
|
149
|
-
it 'runs on the alternate thread pool if given' do
|
150
|
-
pool = Concurrent::FixedThreadPool.new(2)
|
151
|
-
pool.should_receive(:post).with(no_args())
|
152
|
-
deferred = Defer.new{ nil }
|
153
|
-
deferred.go(pool)
|
154
|
-
end
|
155
141
|
end
|
156
142
|
|
157
143
|
context 'fulfillment' do
|
@@ -2,6 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
require 'concurrent/agent'
|
4
4
|
require 'concurrent/future'
|
5
|
+
require 'concurrent/goroutine'
|
5
6
|
require 'concurrent/promise'
|
6
7
|
|
7
8
|
module Concurrent
|
@@ -70,8 +71,11 @@ module Concurrent
|
|
70
71
|
|
71
72
|
subject { Agent.new(0) }
|
72
73
|
|
74
|
+
before(:each) do
|
75
|
+
Agent.thread_pool = EventMachineDeferProxy.new
|
76
|
+
end
|
77
|
+
|
73
78
|
it 'supports fulfillment' do
|
74
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
75
79
|
|
76
80
|
EventMachine.run do
|
77
81
|
|
@@ -87,7 +91,6 @@ module Concurrent
|
|
87
91
|
end
|
88
92
|
|
89
93
|
it 'supports validation' do
|
90
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
91
94
|
|
92
95
|
EventMachine.run do
|
93
96
|
|
@@ -102,7 +105,6 @@ module Concurrent
|
|
102
105
|
end
|
103
106
|
|
104
107
|
it 'supports rejection' do
|
105
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
106
108
|
|
107
109
|
EventMachine.run do
|
108
110
|
|
@@ -122,8 +124,11 @@ module Concurrent
|
|
122
124
|
|
123
125
|
context Future do
|
124
126
|
|
127
|
+
before(:each) do
|
128
|
+
Future.thread_pool = EventMachineDeferProxy.new
|
129
|
+
end
|
130
|
+
|
125
131
|
it 'supports fulfillment' do
|
126
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
127
132
|
|
128
133
|
EventMachine.run do
|
129
134
|
|
@@ -142,10 +147,13 @@ module Concurrent
|
|
142
147
|
|
143
148
|
context Promise do
|
144
149
|
|
150
|
+
before(:each) do
|
151
|
+
Promise.thread_pool = EventMachineDeferProxy.new
|
152
|
+
end
|
153
|
+
|
145
154
|
context 'fulfillment' do
|
146
155
|
|
147
156
|
it 'passes all arguments to the first promise in the chain' do
|
148
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
149
157
|
|
150
158
|
EventMachine.run do
|
151
159
|
|
@@ -162,7 +170,6 @@ module Concurrent
|
|
162
170
|
end
|
163
171
|
|
164
172
|
it 'passes the result of each block to all its children' do
|
165
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
166
173
|
|
167
174
|
EventMachine.run do
|
168
175
|
@expected = nil
|
@@ -176,7 +183,6 @@ module Concurrent
|
|
176
183
|
end
|
177
184
|
|
178
185
|
it 'sets the promise value to the result if its block' do
|
179
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
180
186
|
|
181
187
|
EventMachine.run do
|
182
188
|
|
@@ -193,7 +199,6 @@ module Concurrent
|
|
193
199
|
context 'rejection' do
|
194
200
|
|
195
201
|
it 'sets the promise reason and error on exception' do
|
196
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
197
202
|
|
198
203
|
EventMachine.run do
|
199
204
|
|
@@ -209,7 +214,6 @@ module Concurrent
|
|
209
214
|
end
|
210
215
|
|
211
216
|
it 'calls the first exception block with a matching class' do
|
212
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
213
217
|
|
214
218
|
EventMachine.run do
|
215
219
|
|
@@ -227,7 +231,6 @@ module Concurrent
|
|
227
231
|
end
|
228
232
|
|
229
233
|
it 'passes the exception object to the matched block' do
|
230
|
-
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
231
234
|
|
232
235
|
EventMachine.run do
|
233
236
|
|
@@ -142,5 +142,43 @@ module Concurrent
|
|
142
142
|
@level.should eq :error
|
143
143
|
end
|
144
144
|
end
|
145
|
+
|
146
|
+
context '#status' do
|
147
|
+
|
148
|
+
it 'returns the status of the executor thread when running' do
|
149
|
+
@ec = Executor.run('Foo'){ nil }
|
150
|
+
sleep(0.1)
|
151
|
+
@ec.status.should eq 'sleep'
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'returns nil when not running' do
|
155
|
+
@ec = Executor.run('Foo'){ nil }
|
156
|
+
@ec.kill
|
157
|
+
sleep(0.1)
|
158
|
+
@ec.status.should be_nil
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context '#join' do
|
163
|
+
|
164
|
+
it 'joins the executor thread when running' do
|
165
|
+
@ec = Executor.run('Foo'){ nil }
|
166
|
+
Thread.new{ sleep(1); @ec.kill }
|
167
|
+
@ec.join.should be_a(Thread)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'joins the executor thread with timeout when running' do
|
171
|
+
@ec = Executor.run('Foo'){ nil }
|
172
|
+
@ec.join(1).should be_nil
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'immediately returns nil when not running' do
|
176
|
+
@ec = Executor.run('Foo'){ nil }
|
177
|
+
@ec.kill
|
178
|
+
sleep(0.1)
|
179
|
+
@ec.join.should be_nil
|
180
|
+
@ec.join(1).should be_nil
|
181
|
+
end
|
182
|
+
end
|
145
183
|
end
|
146
184
|
end
|
@@ -2,8 +2,147 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Concurrent
|
4
4
|
|
5
|
+
describe 'functions' do
|
6
|
+
|
7
|
+
context '#post' do
|
8
|
+
|
9
|
+
it 'calls #post when supported by the object' do
|
10
|
+
object = Class.new{
|
11
|
+
def post() nil; end
|
12
|
+
}.new
|
13
|
+
object.should_receive(:post).with(no_args())
|
14
|
+
post(object){ nil }
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'raises an exception when not supported by the object' do
|
18
|
+
object = Class.new{ }.new
|
19
|
+
lambda {
|
20
|
+
post(object){ nil }
|
21
|
+
}.should raise_error(ArgumentError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context '#deref' do
|
26
|
+
|
27
|
+
it 'returns the value of the #deref function' do
|
28
|
+
object = Class.new{
|
29
|
+
def deref() nil; end
|
30
|
+
}.new
|
31
|
+
object.should_receive(:deref).with(nil)
|
32
|
+
deref(object, nil){ nil }
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns the value of the #value function' do
|
36
|
+
object = Class.new{
|
37
|
+
def value() nil; end
|
38
|
+
}.new
|
39
|
+
object.should_receive(:value).with(nil)
|
40
|
+
deref(object, nil){ nil }
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'raises an exception when not supported by the object' do
|
44
|
+
object = Class.new{ }.new
|
45
|
+
lambda {
|
46
|
+
deref(object, nil){ nil }
|
47
|
+
}.should raise_error(ArgumentError)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context '#pending?' do
|
52
|
+
|
53
|
+
it 'returns the value of the #pending? function' do
|
54
|
+
object = Class.new{
|
55
|
+
def pending?() nil; end
|
56
|
+
}.new
|
57
|
+
object.should_receive(:pending?).with(no_args())
|
58
|
+
pending?(object){ nil }
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'raises an exception when not supported by the object' do
|
62
|
+
object = Class.new{ }.new
|
63
|
+
lambda {
|
64
|
+
pending?(object){ nil }
|
65
|
+
}.should raise_error(ArgumentError)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context '#fulfilled?' do
|
70
|
+
|
71
|
+
it 'returns the value of the #fulfilled? function' do
|
72
|
+
object = Class.new{
|
73
|
+
def fulfilled?() nil; end
|
74
|
+
}.new
|
75
|
+
object.should_receive(:fulfilled?).with(no_args())
|
76
|
+
fulfilled?(object){ nil }
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'returns the value of the #realized? function' do
|
80
|
+
object = Class.new{
|
81
|
+
def realized?() nil; end
|
82
|
+
}.new
|
83
|
+
object.should_receive(:realized?).with(no_args())
|
84
|
+
fulfilled?(object){ nil }
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'raises an exception when not supported by the object' do
|
88
|
+
object = Class.new{ }.new
|
89
|
+
lambda {
|
90
|
+
fulfilled?(object){ nil }
|
91
|
+
}.should raise_error(ArgumentError)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context '#realized?' do
|
96
|
+
|
97
|
+
it 'returns the value of the #realized? function' do
|
98
|
+
object = Class.new{
|
99
|
+
def realized?() nil; end
|
100
|
+
}.new
|
101
|
+
object.should_receive(:realized?).with(no_args())
|
102
|
+
realized?(object){ nil }
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'returns the value of the #fulfilled? function' do
|
106
|
+
object = Class.new{
|
107
|
+
def fulfilled?() nil; end
|
108
|
+
}.new
|
109
|
+
object.should_receive(:fulfilled?).with(no_args())
|
110
|
+
realized?(object){ nil }
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'raises an exception when not supported by the object' do
|
114
|
+
object = Class.new{ }.new
|
115
|
+
lambda {
|
116
|
+
realized?(object){ nil }
|
117
|
+
}.should raise_error(ArgumentError)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context '#rejected?' do
|
122
|
+
|
123
|
+
it 'returns the value of the #rejected? function' do
|
124
|
+
object = Class.new{
|
125
|
+
def rejected?() nil; end
|
126
|
+
}.new
|
127
|
+
object.should_receive(:rejected?).with(no_args())
|
128
|
+
rejected?(object){ nil }
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'raises an exception when not supported by the object' do
|
132
|
+
object = Class.new{ }.new
|
133
|
+
lambda {
|
134
|
+
rejected?(object){ nil }
|
135
|
+
}.should raise_error(ArgumentError)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
5
140
|
describe Agent do
|
6
141
|
|
142
|
+
before(:each) do
|
143
|
+
Agent.thread_pool = FixedThreadPool.new(1)
|
144
|
+
end
|
145
|
+
|
7
146
|
it 'aliases #<< for Agent#post' do
|
8
147
|
subject = Agent.new(0)
|
9
148
|
subject << proc{ 100 }
|
@@ -30,13 +169,30 @@ module Concurrent
|
|
30
169
|
|
31
170
|
describe Defer do
|
32
171
|
|
172
|
+
before(:each) do
|
173
|
+
Defer.thread_pool = FixedThreadPool.new(1)
|
174
|
+
end
|
175
|
+
|
33
176
|
it 'aliases Kernel#defer' do
|
34
177
|
defer{ nil }.should be_a(Defer)
|
35
178
|
end
|
36
179
|
end
|
37
180
|
|
181
|
+
describe Executor do
|
182
|
+
|
183
|
+
it 'aliases Kernel#executor' do
|
184
|
+
ex = executor('executor'){ nil }
|
185
|
+
ex.should be_a(Executor::ExecutionContext)
|
186
|
+
ex.kill
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
38
190
|
describe Future do
|
39
191
|
|
192
|
+
before(:each) do
|
193
|
+
Future.thread_pool = FixedThreadPool.new(1)
|
194
|
+
end
|
195
|
+
|
40
196
|
it 'aliases Kernel#future for Future.new' do
|
41
197
|
future().should be_a(Future)
|
42
198
|
future(){ nil }.should be_a(Future)
|
@@ -47,6 +203,10 @@ module Concurrent
|
|
47
203
|
|
48
204
|
describe Promise do
|
49
205
|
|
206
|
+
before(:each) do
|
207
|
+
Promise.thread_pool = FixedThreadPool.new(1)
|
208
|
+
end
|
209
|
+
|
50
210
|
it 'aliases Kernel#promise for Promise.new' do
|
51
211
|
promise().should be_a(Promise)
|
52
212
|
promise(){ nil }.should be_a(Promise)
|