concurrent-ruby 0.1.1.pre.5 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -48
- data/lib/concurrent.rb +0 -6
- data/lib/concurrent/agent.rb +40 -19
- data/lib/concurrent/cached_thread_pool.rb +11 -10
- data/lib/concurrent/defer.rb +12 -8
- data/lib/concurrent/fixed_thread_pool.rb +6 -12
- data/lib/concurrent/future.rb +20 -8
- data/lib/concurrent/global_thread_pool.rb +0 -13
- data/lib/concurrent/goroutine.rb +1 -5
- data/lib/concurrent/obligation.rb +64 -10
- data/lib/concurrent/promise.rb +60 -38
- data/lib/concurrent/thread_pool.rb +5 -16
- data/lib/concurrent/utilities.rb +0 -8
- data/lib/concurrent/version.rb +1 -1
- data/md/defer.md +4 -4
- data/md/promise.md +0 -2
- data/md/thread_pool.md +0 -27
- data/spec/concurrent/agent_spec.rb +27 -8
- data/spec/concurrent/cached_thread_pool_spec.rb +1 -14
- data/spec/concurrent/defer_spec.rb +21 -17
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +149 -159
- data/spec/concurrent/fixed_thread_pool_spec.rb +3 -2
- data/spec/concurrent/future_spec.rb +10 -3
- data/spec/concurrent/goroutine_spec.rb +0 -15
- data/spec/concurrent/obligation_shared.rb +2 -16
- data/spec/concurrent/promise_spec.rb +13 -15
- data/spec/concurrent/thread_pool_shared.rb +5 -5
- data/spec/concurrent/utilities_spec.rb +1 -30
- data/spec/spec_helper.rb +0 -25
- metadata +7 -28
- data/lib/concurrent/executor.rb +0 -95
- data/lib/concurrent/functions.rb +0 -120
- data/lib/concurrent/null_thread_pool.rb +0 -22
- data/lib/concurrent/reactor.rb +0 -161
- data/lib/concurrent/reactor/drb_async_demux.rb +0 -74
- data/lib/concurrent/reactor/tcp_sync_demux.rb +0 -98
- data/md/executor.md +0 -176
- data/spec/concurrent/executor_spec.rb +0 -200
- data/spec/concurrent/functions_spec.rb +0 -217
- data/spec/concurrent/global_thread_pool_spec.rb +0 -38
- data/spec/concurrent/null_thread_pool_spec.rb +0 -54
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +0 -12
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +0 -12
- data/spec/concurrent/reactor_spec.rb +0 -351
data/md/executor.md
DELETED
@@ -1,176 +0,0 @@
|
|
1
|
-
# Being of Sound Mind
|
2
|
-
|
3
|
-
A very common currency pattern is to run a thread that performs a task at regular
|
4
|
-
intervals. The thread that peforms the task sleeps for the given interval then
|
5
|
-
waked up and performs the task. Later, rinse, repeat... This pattern causes two
|
6
|
-
problems. First, it is difficult to test the business logic of the task becuse the
|
7
|
-
task itself is tightly couple with the threading. Second, an exception in the task
|
8
|
-
can cause the entire thread to abend. In a long-running application where the task
|
9
|
-
thread is intended to run for days/weeks/years a crashed task thread can pose a real
|
10
|
-
problem. The `Executor` class alleviates both problems.
|
11
|
-
|
12
|
-
When an executor is launched it starts a thread for monitoring the execution interval.
|
13
|
-
The executor thread does not perform the task, however. Instead, the executor
|
14
|
-
launches the task on a separat thread. The advantage of this approach is that if
|
15
|
-
the task crashes it will only kill the task thread, not the executor thread. The
|
16
|
-
executor thread can then log the success or failure of the task. The executor
|
17
|
-
can even be configured with a timeout value allowing it to kill a task that runs
|
18
|
-
to long and then log the error.
|
19
|
-
|
20
|
-
One other advantage of the `Executor` class is that it forces the bsiness logic to
|
21
|
-
be completely decoupled from the threading logic. The business logic can be tested
|
22
|
-
separately then passed to the an executor for scheduling and running.
|
23
|
-
|
24
|
-
Unlike some of the others concurrency objects in the library, executors do not
|
25
|
-
run on the global. In my experience the types of tasks that will benefit from
|
26
|
-
the `Executor` class tend to also be long running. For this reason they get their
|
27
|
-
own thread every time the task is executed.
|
28
|
-
|
29
|
-
## ExecutionContext
|
30
|
-
|
31
|
-
When an executor is run the return value is an `ExecutionContext` object. An
|
32
|
-
`ExecutionContext` object has several attribute readers (`#name`, `#execution_interval`,
|
33
|
-
and `#timeout_interval`). It also provides several `Thread` operations which can
|
34
|
-
be performed against the internal thread. These include `#status`, `#join`, and
|
35
|
-
`kill`.
|
36
|
-
|
37
|
-
## Custom Logging
|
38
|
-
|
39
|
-
An executor will write a log message to standard out at the completion of every
|
40
|
-
task run. When the task is successful the log message is tagged at the `:info`
|
41
|
-
level. When the task times out the log message is tagged at the `warn` level.
|
42
|
-
When the task fails tocomplete (most likely because of exception) the log
|
43
|
-
message is tagged at the `error` level.
|
44
|
-
|
45
|
-
The default logging behavior can be overridden by passing a `proc` to the executor
|
46
|
-
on creation. The block will be passes three (3) arguments every time it is run:
|
47
|
-
executor `name`, log `level`, and the log `msg` (message). The `proc` can do
|
48
|
-
whatever it wanst with these arguments.
|
49
|
-
|
50
|
-
## Examples
|
51
|
-
|
52
|
-
A basic example:
|
53
|
-
|
54
|
-
```ruby
|
55
|
-
require 'concurrent'
|
56
|
-
|
57
|
-
ec = Concurrent::Executor.run('Foo'){ puts 'Boom!' }
|
58
|
-
|
59
|
-
ec.name #=> "Foo"
|
60
|
-
ec.execution_interval #=> 60 == Concurrent::Executor::EXECUTION_INTERVAL
|
61
|
-
ec.timeout_interval #=> 30 == Concurrent::Executor::TIMEOUT_INTERVAL
|
62
|
-
ec.status #=> "sleep"
|
63
|
-
|
64
|
-
# wait 60 seconds...
|
65
|
-
#=> 'Boom!'
|
66
|
-
#=> ' INFO (2013-08-02 23:20:15) Foo: execution completed successfully'
|
67
|
-
|
68
|
-
ec.kill #=> true
|
69
|
-
```
|
70
|
-
|
71
|
-
Both the execution_interval and the timeout_interval can be configured:
|
72
|
-
|
73
|
-
```ruby
|
74
|
-
ec = Concurrent::Executor.run('Foo', execution_interval: 5, timeout_interval: 5) do
|
75
|
-
puts 'Boom!'
|
76
|
-
end
|
77
|
-
|
78
|
-
ec.execution_interval #=> 5
|
79
|
-
ec.timeout_interval #=> 5
|
80
|
-
```
|
81
|
-
|
82
|
-
A simple example with timeout and task exception:
|
83
|
-
|
84
|
-
```ruby
|
85
|
-
ec = Concurrent::Executor.run('Foo', execution_interval: 1, timeout_interval: 1){ sleep(10) }
|
86
|
-
|
87
|
-
#=> WARN (2013-08-02 23:45:26) Foo: execution timed out after 1 seconds
|
88
|
-
#=> WARN (2013-08-02 23:45:28) Foo: execution timed out after 1 seconds
|
89
|
-
#=> WARN (2013-08-02 23:45:30) Foo: execution timed out after 1 seconds
|
90
|
-
|
91
|
-
ec = Concurrent::Executor.run('Foo', execution_interval: 1){ raise StandardError }
|
92
|
-
|
93
|
-
#=> ERROR (2013-08-02 23:47:31) Foo: execution failed with error 'StandardError'
|
94
|
-
#=> ERROR (2013-08-02 23:47:32) Foo: execution failed with error 'StandardError'
|
95
|
-
#=> ERROR (2013-08-02 23:47:33) Foo: execution failed with error 'StandardError'
|
96
|
-
```
|
97
|
-
|
98
|
-
For custom logging, simply provide a `proc` when creating an executor:
|
99
|
-
|
100
|
-
```ruby
|
101
|
-
file_logger = proc do |name, level, msg|
|
102
|
-
open('executor.log', 'a') do |f|
|
103
|
-
f << ("%5s (%s) %s: %s\n" % [level.upcase, Time.now.strftime("%F %T"), name, msg])
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
ec = Concurrent::Executor.run('Foo', execution_interval: 5, logger: file_logger) do
|
108
|
-
puts 'Boom!'
|
109
|
-
end
|
110
|
-
|
111
|
-
# the log file contains
|
112
|
-
# INFO (2013-08-02 23:30:19) Foo: execution completed successfully
|
113
|
-
# INFO (2013-08-02 23:30:24) Foo: execution completed successfully
|
114
|
-
# INFO (2013-08-02 23:30:29) Foo: execution completed successfully
|
115
|
-
# INFO (2013-08-02 23:30:34) Foo: execution completed successfully
|
116
|
-
# INFO (2013-08-02 23:30:39) Foo: execution completed successfully
|
117
|
-
# INFO (2013-08-02 23:30:44) Foo: execution completed successfully
|
118
|
-
```
|
119
|
-
|
120
|
-
It is also possible to access the default stdout logger from within a logger `proc`:
|
121
|
-
|
122
|
-
```ruby
|
123
|
-
file_logger = proc do |name, level, msg|
|
124
|
-
Concurrent::Executor::STDOUT_LOGGER.call(name, level, msg)
|
125
|
-
open('executor.log', 'a') do |f|
|
126
|
-
f << ("%5s (%s) %s: %s\n" % [level.upcase, Time.now.strftime("%F %T"), name, msg])
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
ec = Concurrent::Executor.run('Foo', execution_interval: 5, logger: file_logger) do
|
131
|
-
puts 'Boom!'
|
132
|
-
end
|
133
|
-
|
134
|
-
# wait...
|
135
|
-
|
136
|
-
#=> Boom!
|
137
|
-
#=> INFO (2013-08-02 23:40:49) Foo: execution completed successfully
|
138
|
-
#=> Boom!
|
139
|
-
#=> INFO (2013-08-02 23:40:54) Foo: execution completed successfully
|
140
|
-
#=> Boom!
|
141
|
-
#=> INFO (2013-08-02 23:40:59) Foo: execution completed successfully
|
142
|
-
|
143
|
-
# and the log file contains
|
144
|
-
# INFO (2013-08-02 23:39:52) Foo: execution completed successfully
|
145
|
-
# INFO (2013-08-02 23:39:57) Foo: execution completed successfully
|
146
|
-
# INFO (2013-08-02 23:40:49) Foo: execution completed successfully
|
147
|
-
```
|
148
|
-
|
149
|
-
## Copyright
|
150
|
-
|
151
|
-
*Concurrent Ruby* is Copyright © 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
|
152
|
-
It is free software and may be redistributed under the terms specified in the LICENSE file.
|
153
|
-
|
154
|
-
## License
|
155
|
-
|
156
|
-
Released under the MIT license.
|
157
|
-
|
158
|
-
http://www.opensource.org/licenses/mit-license.php
|
159
|
-
|
160
|
-
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
161
|
-
> of this software and associated documentation files (the "Software"), to deal
|
162
|
-
> in the Software without restriction, including without limitation the rights
|
163
|
-
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
164
|
-
> copies of the Software, and to permit persons to whom the Software is
|
165
|
-
> furnished to do so, subject to the following conditions:
|
166
|
-
>
|
167
|
-
> The above copyright notice and this permission notice shall be included in
|
168
|
-
> all copies or substantial portions of the Software.
|
169
|
-
>
|
170
|
-
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
171
|
-
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
172
|
-
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
173
|
-
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
174
|
-
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
175
|
-
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
176
|
-
> THE SOFTWARE.
|
@@ -1,200 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
describe Executor do
|
6
|
-
|
7
|
-
before(:each) do
|
8
|
-
@orig_stdout = $stdout
|
9
|
-
$stdout = StringIO.new
|
10
|
-
end
|
11
|
-
|
12
|
-
after(:each) do
|
13
|
-
$stdout = @orig_stdout
|
14
|
-
end
|
15
|
-
|
16
|
-
after(:each) do
|
17
|
-
@ec.kill unless @ec.nil?
|
18
|
-
end
|
19
|
-
|
20
|
-
context '#run' do
|
21
|
-
|
22
|
-
it 'raises an exception if no block given' do
|
23
|
-
lambda {
|
24
|
-
@ec = Concurrent::Executor.run('Foo')
|
25
|
-
}.should raise_error
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'uses the default execution interval when no interval is given' do
|
29
|
-
@ec = Executor.run('Foo'){ nil }
|
30
|
-
@ec.execution_interval.should eq Executor::EXECUTION_INTERVAL
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'uses the default timeout interval when no interval is given' do
|
34
|
-
@ec = Executor.run('Foo'){ nil }
|
35
|
-
@ec.timeout_interval.should eq Executor::TIMEOUT_INTERVAL
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'uses the given execution interval' do
|
39
|
-
@ec = Executor.run('Foo', execution_interval: 5){ nil }
|
40
|
-
@ec.execution_interval.should eq 5
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'uses the given timeout interval' do
|
44
|
-
@ec = Executor.run('Foo', timeout_interval: 5){ nil }
|
45
|
-
@ec.timeout_interval.should eq 5
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'creates a new thread' do
|
49
|
-
thread = Thread.new{ sleep(1) }
|
50
|
-
Thread.should_receive(:new).with(any_args()).and_return(thread)
|
51
|
-
@ec = Executor.run('Foo'){ nil }
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'returns an ExecutionContext' do
|
55
|
-
@ec = Executor.run('Foo'){ nil }
|
56
|
-
@ec.should be_a(Executor::ExecutionContext)
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'sets the #name context variable' do
|
60
|
-
@ec = Executor.run('Foo'){ nil }
|
61
|
-
@ec.name.should eq 'Foo'
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'execution' do
|
66
|
-
|
67
|
-
it 'runs the block immediately when the :run_now option is true' do
|
68
|
-
@expected = false
|
69
|
-
@ec = Executor.run('Foo', execution: 500, now: true){ @expected = true }
|
70
|
-
@expected.should be_false
|
71
|
-
sleep(1)
|
72
|
-
@expected.should be_true
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'waits for :execution_interval seconds when the :run_now option is false' do
|
76
|
-
@expected = false
|
77
|
-
@ec = Executor.run('Foo', execution: 0.5, now: false){ @expected = true }
|
78
|
-
@expected.should be_false
|
79
|
-
sleep(1)
|
80
|
-
@expected.should be_true
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'waits for :execution_interval seconds when the :run_now option is not given' do
|
84
|
-
@expected = false
|
85
|
-
@ec = Executor.run('Foo', execution: 0.5){ @expected = true }
|
86
|
-
@expected.should be_false
|
87
|
-
sleep(1)
|
88
|
-
@expected.should be_true
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'yields to the execution block' do
|
92
|
-
@expected = false
|
93
|
-
@ec = Executor.run('Foo', execution: 1){ @expected = true }
|
94
|
-
sleep(2)
|
95
|
-
@expected.should be_true
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'passes any given arguments to the execution block' do
|
99
|
-
args = [1,2,3,4]
|
100
|
-
@expected = nil
|
101
|
-
@ec = Executor.run('Foo', execution_interval: 0.5, args: args) do |*args|
|
102
|
-
@expected = args
|
103
|
-
end
|
104
|
-
sleep(1)
|
105
|
-
@expected.should eq args
|
106
|
-
end
|
107
|
-
|
108
|
-
it 'supresses exceptions thrown by the execution block' do
|
109
|
-
lambda {
|
110
|
-
@ec = Executor.run('Foo', execution_interval: 0.5) { raise StandardError }
|
111
|
-
sleep(1)
|
112
|
-
}.should_not raise_error
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'kills the worker thread if the timeout is reached' do
|
116
|
-
# the after(:each) block will trigger this expectation
|
117
|
-
Thread.should_receive(:kill).at_least(1).with(any_args())
|
118
|
-
@ec = Executor.run('Foo', execution_interval: 0.5, timeout_interval: 0.5){ Thread.stop }
|
119
|
-
sleep(1.5)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
context 'logging' do
|
124
|
-
|
125
|
-
before(:each) do
|
126
|
-
@name = nil
|
127
|
-
@level = nil
|
128
|
-
@msg = nil
|
129
|
-
|
130
|
-
@logger = proc do |name, level, msg|
|
131
|
-
@name = name
|
132
|
-
@level = level
|
133
|
-
@msg = msg
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'uses a custom logger when given' do
|
138
|
-
@ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
|
139
|
-
sleep(0.5)
|
140
|
-
@name.should eq 'Foo'
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'logs :info when execution is successful' do
|
144
|
-
@ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
|
145
|
-
sleep(0.5)
|
146
|
-
@level.should eq :info
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'logs :warn when execution times out' do
|
150
|
-
@ec = Executor.run('Foo', execution_interval: 0.1, timeout_interval: 0.1, logger: @logger){ Thread.stop }
|
151
|
-
sleep(0.5)
|
152
|
-
@level.should eq :warn
|
153
|
-
end
|
154
|
-
|
155
|
-
it 'logs :error when execution is fails' do
|
156
|
-
@ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ raise StandardError }
|
157
|
-
sleep(0.5)
|
158
|
-
@level.should eq :error
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
context '#status' do
|
163
|
-
|
164
|
-
it 'returns the status of the executor thread when running' do
|
165
|
-
@ec = Executor.run('Foo'){ nil }
|
166
|
-
sleep(0.1)
|
167
|
-
@ec.status.should eq 'sleep'
|
168
|
-
end
|
169
|
-
|
170
|
-
it 'returns nil when not running' do
|
171
|
-
@ec = Executor.run('Foo'){ nil }
|
172
|
-
@ec.kill
|
173
|
-
sleep(0.1)
|
174
|
-
@ec.status.should be_nil
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
context '#join' do
|
179
|
-
|
180
|
-
it 'joins the executor thread when running' do
|
181
|
-
@ec = Executor.run('Foo'){ nil }
|
182
|
-
Thread.new{ sleep(1); @ec.kill }
|
183
|
-
@ec.join.should be_a(Thread)
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'joins the executor thread with timeout when running' do
|
187
|
-
@ec = Executor.run('Foo'){ nil }
|
188
|
-
@ec.join(1).should be_nil
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'immediately returns nil when not running' do
|
192
|
-
@ec = Executor.run('Foo'){ nil }
|
193
|
-
@ec.kill
|
194
|
-
sleep(0.1)
|
195
|
-
@ec.join.should be_nil
|
196
|
-
@ec.join(1).should be_nil
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
@@ -1,217 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
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
|
-
|
140
|
-
describe Agent do
|
141
|
-
|
142
|
-
before(:each) do
|
143
|
-
Agent.thread_pool = FixedThreadPool.new(1)
|
144
|
-
end
|
145
|
-
|
146
|
-
it 'aliases #<< for Agent#post' do
|
147
|
-
subject = Agent.new(0)
|
148
|
-
subject << proc{ 100 }
|
149
|
-
sleep(0.1)
|
150
|
-
subject.value.should eq 100
|
151
|
-
end
|
152
|
-
|
153
|
-
it 'aliases Kernel#agent for Agent.new' do
|
154
|
-
agent(10).should be_a(Agent)
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'aliases Kernel#deref for #deref' do
|
158
|
-
deref(Agent.new(10)).should eq 10
|
159
|
-
deref(Agent.new(10), 10).should eq 10
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'aliases Kernel:post for Agent#post' do
|
163
|
-
subject = Agent.new(0)
|
164
|
-
post(subject){ 100 }
|
165
|
-
sleep(0.1)
|
166
|
-
subject.value.should eq 100
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
describe Defer do
|
171
|
-
|
172
|
-
before(:each) do
|
173
|
-
Defer.thread_pool = FixedThreadPool.new(1)
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'aliases Kernel#defer' do
|
177
|
-
defer{ nil }.should be_a(Defer)
|
178
|
-
end
|
179
|
-
end
|
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
|
-
|
190
|
-
describe Future do
|
191
|
-
|
192
|
-
before(:each) do
|
193
|
-
Future.thread_pool = FixedThreadPool.new(1)
|
194
|
-
end
|
195
|
-
|
196
|
-
it 'aliases Kernel#future for Future.new' do
|
197
|
-
future().should be_a(Future)
|
198
|
-
future(){ nil }.should be_a(Future)
|
199
|
-
future(1, 2, 3).should be_a(Future)
|
200
|
-
future(1, 2, 3){ nil }.should be_a(Future)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
describe Promise do
|
205
|
-
|
206
|
-
before(:each) do
|
207
|
-
Promise.thread_pool = FixedThreadPool.new(1)
|
208
|
-
end
|
209
|
-
|
210
|
-
it 'aliases Kernel#promise for Promise.new' do
|
211
|
-
promise().should be_a(Promise)
|
212
|
-
promise(){ nil }.should be_a(Promise)
|
213
|
-
promise(1, 2, 3).should be_a(Promise)
|
214
|
-
promise(1, 2, 3){ nil }.should be_a(Promise)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|