concurrent-ruby 0.3.0 → 0.3.1.pre.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,6 +23,11 @@ module Concurrent
23
23
  Agent.thread_pool = FixedThreadPool.new(1)
24
24
  end
25
25
 
26
+ it 'includes Dereferenceable' do
27
+ agent = Agent.new(10)
28
+ agent.should be_a(Dereferenceable)
29
+ end
30
+
26
31
  context '#initialize' do
27
32
 
28
33
  it 'sets the value to the given initial state' do
@@ -268,7 +273,7 @@ module Concurrent
268
273
  end
269
274
  end
270
275
 
271
- context 'dereference' do
276
+ context 'Dereferenceable' do
272
277
 
273
278
  it 'defaults :dup_on_deref to false' do
274
279
  value = 'value'
@@ -362,6 +367,52 @@ module Concurrent
362
367
  agent = Agent.new(value, dup_on_deref: true, freeze_on_deref: true, copy_on_deref: copy)
363
368
  agent.value.should eq frozen
364
369
  end
370
+
371
+ it 'does not call #dup when #dup_on_deref is set and the value is nil' do
372
+ allow_message_expectations_on_nil
373
+ result = nil
374
+ result.should_not_receive(:dup).with(any_args())
375
+ agent = Agent.new(result, dup_on_deref: true)
376
+ agent.value
377
+ end
378
+
379
+ it 'does not call #freeze when #freeze_on_deref is set and the value is nil' do
380
+ allow_message_expectations_on_nil
381
+ result = nil
382
+ result.should_not_receive(:freeze).with(any_args())
383
+ agent = Agent.new(result, freeze_on_deref: true)
384
+ agent.value
385
+ end
386
+
387
+ it 'does not call the #copy_on_deref block when the value is nil' do
388
+ copier = proc { 42 }
389
+ agent = Agent.new(nil, copy_on_deref: copier)
390
+ agent.value.should be_nil
391
+ end
392
+
393
+ it 'does not lock when all options are false' do
394
+ agent = Agent.new(0)
395
+ mutex = double('mutex')
396
+ agent.stub(:mutex).and_return(mutex)
397
+ mutex.should_not_receive(:synchronize)
398
+ agent.value
399
+ end
400
+
401
+ it 'supports dereference flags with observers' do
402
+ result = 'result'
403
+ result.should_receive(:dup).and_return(result)
404
+ result.should_receive(:freeze).and_return(result)
405
+ copier = proc { result }
406
+
407
+ observer = double('observer')
408
+ observer.should_receive(:update).with(any_args())
409
+
410
+ agent = Agent.new(nil, dup_on_deref: true, freeze_on_deref: true, copy_on_deref: copier)
411
+ agent.add_observer(observer)
412
+
413
+ agent << proc { 'original result' }
414
+ sleep(0.1)
415
+ end
365
416
  end
366
417
 
367
418
  context 'observation' do
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ require_relative 'obligation_shared'
3
+
4
+ module Concurrent
5
+
6
+ describe Contract do
7
+
8
+ let!(:fulfilled_value) { 10 }
9
+ let(:rejected_reason) { StandardError.new('Boom!') }
10
+
11
+ let(:pending_subject) do
12
+ @contract = Contract.new
13
+ Thread.new do
14
+ sleep(3)
15
+ @contract.complete(fulfilled_value, nil)
16
+ end
17
+ @contract
18
+ end
19
+
20
+ let(:fulfilled_subject) do
21
+ contract = Contract.new
22
+ contract.complete(fulfilled_value, nil)
23
+ contract
24
+ end
25
+
26
+ let(:rejected_subject) do
27
+ contract = Contract.new
28
+ contract.complete(nil, rejected_reason)
29
+ contract
30
+ end
31
+
32
+ it_should_behave_like :obligation
33
+ end
34
+ end
@@ -28,7 +28,12 @@ module Concurrent
28
28
  Future.thread_pool = FixedThreadPool.new(1)
29
29
  end
30
30
 
31
- it_should_behave_like Concurrent::Obligation
31
+ it_should_behave_like :obligation
32
+
33
+ it 'includes Dereferenceable' do
34
+ future = Future.new{ nil }
35
+ future.should be_a(Dereferenceable)
36
+ end
32
37
 
33
38
  context '#initialize' do
34
39
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- share_examples_for Concurrent::Obligation do
3
+ share_examples_for :obligation do
4
4
 
5
5
  context '#state' do
6
6
 
@@ -29,7 +29,12 @@ module Concurrent
29
29
  Promise.thread_pool = FixedThreadPool.new(1)
30
30
  end
31
31
 
32
- it_should_behave_like Concurrent::Obligation
32
+ it_should_behave_like :obligation
33
+
34
+ it 'includes Dereferenceable' do
35
+ promise = Promise.new{ nil }
36
+ promise.should be_a(Dereferenceable)
37
+ end
33
38
 
34
39
  context '#then' do
35
40
 
@@ -12,7 +12,7 @@ share_examples_for :runnable do
12
12
 
13
13
  it 'starts the (blocking) runner on the current thread when stopped' do
14
14
  @thread = Thread.new { subject.run }
15
- @thread.join(1).should be_nil
15
+ @thread.join(0.1).should be_nil
16
16
  end
17
17
 
18
18
  it 'raises an exception when already running' do
@@ -0,0 +1,259 @@
1
+ require 'spec_helper'
2
+ require 'timecop'
3
+ require_relative 'obligation_shared'
4
+ require_relative 'runnable_shared'
5
+
6
+ module Concurrent
7
+
8
+ describe ScheduledTask do
9
+
10
+ context 'behavior' do
11
+
12
+ # runnable
13
+
14
+ subject { ScheduledTask.new(0.5){ nil } }
15
+ it_should_behave_like :runnable
16
+
17
+ # obligation
18
+
19
+ let!(:fulfilled_value) { 10 }
20
+ let!(:rejected_reason) { StandardError.new('mojo jojo') }
21
+
22
+ let(:pending_subject) do
23
+ task = ScheduledTask.new(1){ fulfilled_value }
24
+ task.run!
25
+ task
26
+ end
27
+
28
+ let(:fulfilled_subject) do
29
+ task = ScheduledTask.new(0.1){ fulfilled_value }
30
+ task.run
31
+ task
32
+ end
33
+
34
+ let(:rejected_subject) do
35
+ task = ScheduledTask.new(0.1){ raise rejected_reason }
36
+ task.run
37
+ task
38
+ end
39
+
40
+ it_should_behave_like :obligation
41
+ end
42
+
43
+ context '#initialize' do
44
+
45
+ it 'accepts a number of seconds (from now) as the shcedule time' do
46
+ Timecop.freeze do
47
+ now = Time.now
48
+ task = ScheduledTask.new(60){ nil }
49
+ task.schedule_time.to_i.should eq now.to_i + 60
50
+ end
51
+ end
52
+
53
+ it 'accepts a time object as the schedule time' do
54
+ schedule = Time.now + (60*10)
55
+ task = ScheduledTask.new(schedule){ nil }
56
+ task.schedule_time.should eq schedule
57
+ end
58
+
59
+ it 'raises an exception when seconds is less than zero' do
60
+ expect {
61
+ ScheduledTask.new(-1){ nil }
62
+ }.to raise_error(ArgumentError)
63
+ end
64
+
65
+ it 'raises an exception when schedule time is in the past' do
66
+ expect {
67
+ ScheduledTask.new(Time.now - 60){ nil }
68
+ }.to raise_error(ArgumentError)
69
+ end
70
+
71
+ it 'raises an exception when no block given' do
72
+ expect {
73
+ ScheduledTask.new(1)
74
+ }.to raise_error(ArgumentError)
75
+ end
76
+
77
+ it 'sets the initial state to :pending' do
78
+ task = ScheduledTask.new(1){ nil }
79
+ task.should be_pending
80
+ end
81
+ end
82
+
83
+ context '#cancel' do
84
+
85
+ it 'returns false if the task has already been performed' do
86
+ task = ScheduledTask.new(0.1){ 42 }
87
+ task.run!
88
+ sleep(0.2)
89
+ task.cancel.should be_false
90
+ end
91
+
92
+ it 'returns false if the task is already in progress' do
93
+ task = ScheduledTask.new(0.1){ sleep(1); 42 }
94
+ task.run!
95
+ sleep(0.2)
96
+ task.cancel.should be_false
97
+ end
98
+
99
+ it 'cancels the task if it has not yet started' do
100
+ @expected = true
101
+ task = ScheduledTask.new(0.3){ @expected = false }
102
+ task.run!
103
+ sleep(0.1)
104
+ task.cancel
105
+ sleep(0.5)
106
+ @expected.should be_true
107
+ end
108
+
109
+ it 'returns true on success' do
110
+ task = ScheduledTask.new(0.3){ @expected = false }
111
+ task.run!
112
+ sleep(0.1)
113
+ task.cancel.should be_true
114
+ end
115
+
116
+ it 'sets the state to :cancelled when cancelled' do
117
+ task = ScheduledTask.new(10){ 42 }
118
+ task.run!
119
+ sleep(0.1)
120
+ task.cancel
121
+ task.should be_cancelled
122
+ end
123
+
124
+ it 'stops the runnable' do
125
+ task = ScheduledTask.new(0.2){ 42 }
126
+ task.run!
127
+ sleep(0.1)
128
+ task.cancel
129
+ sleep(0.2)
130
+ task.should_not be_running
131
+ end
132
+ end
133
+
134
+ context 'execution' do
135
+
136
+ it 'sets the state to :in_progress when the task is running' do
137
+ task = ScheduledTask.new(0.1){ sleep(1); 42 }
138
+ task.run!
139
+ sleep(0.2)
140
+ task.should be_in_progress
141
+ end
142
+
143
+ it 'stops itself on task completion' do
144
+ task = ScheduledTask.new(0.1){ 42 }
145
+ task.run!
146
+ sleep(0.2)
147
+ task.should_not be_running
148
+ end
149
+ end
150
+
151
+ context 'observation' do
152
+
153
+ let(:clazz) do
154
+ Class.new do
155
+ attr_reader :value
156
+ attr_reader :reason
157
+ attr_reader :count
158
+ define_method(:update) do |time, value, reason|
159
+ @count = @count.to_i + 1
160
+ @value = value
161
+ @reason = reason
162
+ end
163
+ end
164
+ end
165
+
166
+ let(:observer) { clazz.new }
167
+
168
+ it 'returns true for an observer added while :pending' do
169
+ task = ScheduledTask.new(1){ 42 }
170
+ task.run!
171
+ task.add_observer(observer).should be_true
172
+ end
173
+
174
+ it 'returns true for an observer added while :in_progress' do
175
+ task = ScheduledTask.new(0.1){ sleep(1); 42 }
176
+ task.run!
177
+ sleep(0.2)
178
+ task.add_observer(observer).should be_true
179
+ end
180
+
181
+ it 'returns true for an observer added while not running' do
182
+ task = ScheduledTask.new(1){ 42 }
183
+ task.add_observer(observer).should be_true
184
+ end
185
+
186
+ it 'returns false for an observer added once :cancelled' do
187
+ task = ScheduledTask.new(1){ 42 }
188
+ task.run!
189
+ sleep(0.1)
190
+ task.cancel
191
+ sleep(0.1)
192
+ task.add_observer(observer).should be_false
193
+ end
194
+
195
+ it 'returns false for an observer added once :fulfilled' do
196
+ task = ScheduledTask.new(0.1){ 42 }
197
+ task.run!
198
+ sleep(0.2)
199
+ task.add_observer(observer).should be_false
200
+ end
201
+
202
+ it 'returns false for an observer added once :rejected' do
203
+ task = ScheduledTask.new(0.1){ raise StandardError }
204
+ task.run!
205
+ sleep(0.2)
206
+ task.add_observer(observer).should be_false
207
+ end
208
+
209
+ it 'notifies all observers on fulfillment' do
210
+ task = ScheduledTask.new(0.1){ 42 }
211
+ task.add_observer(observer)
212
+ task.run!
213
+ sleep(0.2)
214
+ task.value.should == 42
215
+ task.reason.should be_nil
216
+ observer.value.should == 42
217
+ observer.reason.should be_nil
218
+ end
219
+
220
+ it 'notifies all observers on rejection' do
221
+ task = ScheduledTask.new(0.1){ raise StandardError }
222
+ task.add_observer(observer)
223
+ task.run!
224
+ sleep(0.2)
225
+ task.value.should be_nil
226
+ task.reason.should be_a(StandardError)
227
+ observer.value.should be_nil
228
+ observer.reason.should be_a(StandardError)
229
+ end
230
+
231
+ it 'does not notify an observer added after fulfillment' do
232
+ observer.should_not_receive(:update).with(any_args())
233
+ task = ScheduledTask.new(0.1){ 42 }
234
+ sleep(0.2)
235
+ task.add_observer(observer)
236
+ sleep(0.1)
237
+ end
238
+
239
+ it 'does not notify an observer added after rejection' do
240
+ observer.should_not_receive(:update).with(any_args())
241
+ task = ScheduledTask.new(0.1){ raise StandardError }
242
+ sleep(0.2)
243
+ task.add_observer(observer)
244
+ sleep(0.1)
245
+ end
246
+
247
+ it 'does not notify an observer added after cancellation' do
248
+ observer.should_not_receive(:update).with(any_args())
249
+ task = ScheduledTask.new(0.5){ 42 }
250
+ task.run!
251
+ sleep(0.1)
252
+ task.cancel
253
+ sleep(0.1)
254
+ task.add_observer(observer)
255
+ sleep(0.5)
256
+ end
257
+ end
258
+ end
259
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerry D'Antonio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-17 00:00:00.000000000 Z
11
+ date: 2013-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -40,6 +40,8 @@ files:
40
40
  - lib/concurrent/agent.rb
41
41
  - lib/concurrent/cached_thread_pool/worker.rb
42
42
  - lib/concurrent/cached_thread_pool.rb
43
+ - lib/concurrent/contract.rb
44
+ - lib/concurrent/dereferenceable.rb
43
45
  - lib/concurrent/event.rb
44
46
  - lib/concurrent/event_machine_defer_proxy.rb
45
47
  - lib/concurrent/fixed_thread_pool/worker.rb
@@ -50,24 +52,28 @@ files:
50
52
  - lib/concurrent/obligation.rb
51
53
  - lib/concurrent/promise.rb
52
54
  - lib/concurrent/runnable.rb
55
+ - lib/concurrent/scheduled_task.rb
53
56
  - lib/concurrent/supervisor.rb
54
57
  - lib/concurrent/timer_task.rb
55
58
  - lib/concurrent/utilities.rb
56
59
  - lib/concurrent/version.rb
57
60
  - lib/concurrent.rb
58
61
  - lib/concurrent_ruby.rb
62
+ - md/actor.md
59
63
  - md/agent.md
60
64
  - md/event.md
61
65
  - md/future.md
62
66
  - md/goroutine.md
63
67
  - md/obligation.md
64
68
  - md/promise.md
69
+ - md/scheduled_task.md
65
70
  - md/supervisor.md
66
71
  - md/thread_pool.md
67
72
  - md/timer_task.md
68
73
  - spec/concurrent/actor_spec.rb
69
74
  - spec/concurrent/agent_spec.rb
70
75
  - spec/concurrent/cached_thread_pool_spec.rb
76
+ - spec/concurrent/contract_spec.rb
71
77
  - spec/concurrent/event_machine_defer_proxy_spec.rb
72
78
  - spec/concurrent/event_spec.rb
73
79
  - spec/concurrent/fixed_thread_pool_spec.rb
@@ -78,6 +84,7 @@ files:
78
84
  - spec/concurrent/promise_spec.rb
79
85
  - spec/concurrent/runnable_shared.rb
80
86
  - spec/concurrent/runnable_spec.rb
87
+ - spec/concurrent/scheduled_task_spec.rb
81
88
  - spec/concurrent/supervisor_spec.rb
82
89
  - spec/concurrent/thread_pool_shared.rb
83
90
  - spec/concurrent/timer_task_spec.rb
@@ -103,12 +110,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
110
  version: 1.9.2
104
111
  required_rubygems_version: !ruby/object:Gem::Requirement
105
112
  requirements:
106
- - - '>='
113
+ - - '>'
107
114
  - !ruby/object:Gem::Version
108
- version: '0'
115
+ version: 1.3.1
109
116
  requirements: []
110
117
  rubyforge_project:
111
- rubygems_version: 2.1.5
118
+ rubygems_version: 2.1.10
112
119
  signing_key:
113
120
  specification_version: 4
114
121
  summary: Modern concurrency tools including agents, futures, promises, thread pools,
@@ -117,6 +124,7 @@ test_files:
117
124
  - spec/concurrent/actor_spec.rb
118
125
  - spec/concurrent/agent_spec.rb
119
126
  - spec/concurrent/cached_thread_pool_spec.rb
127
+ - spec/concurrent/contract_spec.rb
120
128
  - spec/concurrent/event_machine_defer_proxy_spec.rb
121
129
  - spec/concurrent/event_spec.rb
122
130
  - spec/concurrent/fixed_thread_pool_spec.rb
@@ -127,6 +135,7 @@ test_files:
127
135
  - spec/concurrent/promise_spec.rb
128
136
  - spec/concurrent/runnable_shared.rb
129
137
  - spec/concurrent/runnable_spec.rb
138
+ - spec/concurrent/scheduled_task_spec.rb
130
139
  - spec/concurrent/supervisor_spec.rb
131
140
  - spec/concurrent/thread_pool_shared.rb
132
141
  - spec/concurrent/timer_task_spec.rb