concurrent-ruby 0.3.0 → 0.3.1.pre.1

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.
@@ -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