promise.rb 0.7.0.rc1 → 0.7.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/config/flog.yml +1 -1
- data/config/reek.yml +1 -1
- data/lib/promise.rb +42 -26
- data/lib/promise/callback.rb +19 -30
- data/lib/promise/group.rb +1 -1
- data/lib/promise/version.rb +1 -1
- data/spec/unit/promise_spec.rb +84 -23
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 487aaf8c555487ea2f7b3bbdb77a5a63b0be1f38
|
4
|
+
data.tar.gz: 1a1ede2482f03dd9c55c0050b913bc718b077bea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31b9d4895eca8ceab77fcce63730ad620b2d7f294b2bd53eb47c6da412557c714ce58bb99cc1a87995dac172e554e61ea4b0ae94ef6004d63746a3acc2ed8399
|
7
|
+
data.tar.gz: 6bf132f844d4f83b7369ffd79711aa9b772c2d285507908510993099a4c1a54a3aab66eb2de7d2d4271509c62bbea24c71229086deff567adf73f5867d3b4f54
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# promise.rb changelog
|
2
2
|
|
3
|
+
## 0.7.0.rc2 (February 17, 2016)
|
4
|
+
|
5
|
+
### Bug Fixes
|
6
|
+
|
7
|
+
* Avoid re-raising exception that occur in then callbacks (pull #13)
|
8
|
+
* Wait for an instance of a subclass of Promise in Promise.all (pull #15)
|
9
|
+
|
10
|
+
### Features
|
11
|
+
|
12
|
+
* Instantiate exception classes and set missing backtrace in reject (pull #12)
|
13
|
+
* Allow Promise#fulfill to be called with a promise (pull #14)
|
14
|
+
|
15
|
+
### Breaking Changes
|
16
|
+
|
17
|
+
* Make add_callback, dispatch, dispatch! and Promise::Callback private (pull #11)
|
18
|
+
* Remove Promise#backtrace, use #reason.backtrace instead (pull #12)
|
19
|
+
|
3
20
|
## 0.7.0.rc1 (February 9, 2016)
|
4
21
|
|
5
22
|
### Bug Fixes
|
data/config/flog.yml
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
---
|
2
|
-
threshold: 10.
|
2
|
+
threshold: 10.6
|
data/config/reek.yml
CHANGED
data/lib/promise.rb
CHANGED
@@ -11,10 +11,10 @@ class Promise
|
|
11
11
|
|
12
12
|
include Promise::Progress
|
13
13
|
|
14
|
-
attr_reader :state, :value, :reason
|
14
|
+
attr_reader :state, :value, :reason
|
15
15
|
|
16
16
|
def self.resolve(obj)
|
17
|
-
return obj if obj.
|
17
|
+
return obj if obj.is_a?(self)
|
18
18
|
new.tap { |promise| promise.fulfill(obj) }
|
19
19
|
end
|
20
20
|
|
@@ -43,52 +43,68 @@ class Promise
|
|
43
43
|
on_fulfill ||= block
|
44
44
|
next_promise = self.class.new
|
45
45
|
|
46
|
-
add_callback
|
46
|
+
add_callback(Callback.new(self, on_fulfill, on_reject, next_promise))
|
47
47
|
next_promise
|
48
48
|
end
|
49
49
|
|
50
|
-
def add_callback(&generator)
|
51
|
-
if pending?
|
52
|
-
@callbacks << generator
|
53
|
-
else
|
54
|
-
dispatch!(generator.call)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
50
|
def sync
|
59
51
|
wait if pending?
|
60
52
|
raise reason if rejected?
|
61
53
|
value
|
62
54
|
end
|
63
55
|
|
64
|
-
def fulfill(value = nil
|
65
|
-
|
66
|
-
|
67
|
-
|
56
|
+
def fulfill(value = nil)
|
57
|
+
if Promise === value
|
58
|
+
Callback.assume_state(value, self)
|
59
|
+
else
|
60
|
+
dispatch do
|
61
|
+
@state = :fulfilled
|
62
|
+
@value = value
|
63
|
+
end
|
68
64
|
end
|
65
|
+
nil
|
69
66
|
end
|
70
67
|
|
71
|
-
def reject(reason = nil
|
72
|
-
dispatch
|
68
|
+
def reject(reason = nil)
|
69
|
+
dispatch do
|
73
70
|
@state = :rejected
|
74
|
-
@reason = reason || Error
|
71
|
+
@reason = reason_coercion(reason || Error)
|
75
72
|
end
|
76
73
|
end
|
77
74
|
|
78
|
-
def
|
75
|
+
def defer
|
76
|
+
yield
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def reason_coercion(reason)
|
82
|
+
case reason
|
83
|
+
when Exception
|
84
|
+
reason.set_backtrace(caller) unless reason.backtrace
|
85
|
+
when Class
|
86
|
+
reason = reason_coercion(reason.new) if reason <= Exception
|
87
|
+
end
|
88
|
+
reason
|
89
|
+
end
|
90
|
+
|
91
|
+
def add_callback(callback)
|
92
|
+
if pending?
|
93
|
+
@callbacks << callback
|
94
|
+
else
|
95
|
+
dispatch!(callback)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def dispatch
|
79
100
|
if pending?
|
80
101
|
yield
|
81
|
-
@
|
82
|
-
@callbacks.each { |generator| dispatch!(generator.call) }
|
102
|
+
@callbacks.each { |callback| dispatch!(callback) }
|
83
103
|
nil
|
84
104
|
end
|
85
105
|
end
|
86
106
|
|
87
107
|
def dispatch!(callback)
|
88
|
-
defer { callback.
|
89
|
-
end
|
90
|
-
|
91
|
-
def defer
|
92
|
-
yield
|
108
|
+
defer { callback.call }
|
93
109
|
end
|
94
110
|
end
|
data/lib/promise/callback.rb
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
class Promise
|
4
4
|
class Callback
|
5
|
+
def self.assume_state(source, target)
|
6
|
+
on_fulfill = target.method(:fulfill)
|
7
|
+
on_reject = target.method(:reject)
|
8
|
+
source.then(on_fulfill, on_reject)
|
9
|
+
end
|
10
|
+
|
5
11
|
def initialize(promise, on_fulfill, on_reject, next_promise)
|
6
12
|
@promise = promise
|
7
13
|
@on_fulfill = on_fulfill
|
@@ -9,42 +15,25 @@ class Promise
|
|
9
15
|
@next_promise = next_promise
|
10
16
|
end
|
11
17
|
|
12
|
-
def
|
13
|
-
@promise.fulfilled?
|
14
|
-
|
15
|
-
|
16
|
-
def param
|
17
|
-
@promise.fulfilled? ? @promise.value : @promise.reason
|
18
|
-
end
|
19
|
-
|
20
|
-
def dispatch
|
21
|
-
if block
|
22
|
-
handle_result { execute }
|
18
|
+
def call
|
19
|
+
if @promise.fulfilled?
|
20
|
+
call_block(@on_fulfill, @promise.value)
|
23
21
|
else
|
24
|
-
|
22
|
+
call_block(@on_reject, @promise.reason)
|
25
23
|
end
|
26
24
|
end
|
27
25
|
|
28
|
-
def
|
29
|
-
block
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
def handle_result
|
36
|
-
if Promise === (result = yield)
|
37
|
-
assume_state(result, @next_promise)
|
26
|
+
def call_block(block, param)
|
27
|
+
if block
|
28
|
+
begin
|
29
|
+
@next_promise.fulfill(block.call(param))
|
30
|
+
rescue => ex
|
31
|
+
@next_promise.reject(ex)
|
32
|
+
end
|
38
33
|
else
|
39
|
-
|
34
|
+
self.class.assume_state(@promise, @next_promise)
|
40
35
|
end
|
41
36
|
end
|
42
|
-
|
43
|
-
def assume_state(source, target)
|
44
|
-
on_fulfill = proc { target.fulfill(source.value, source.backtrace) }
|
45
|
-
on_reject = proc { target.reject(source.reason, source.backtrace) }
|
46
|
-
|
47
|
-
source.then(on_fulfill, on_reject)
|
48
|
-
end
|
49
37
|
end
|
38
|
+
private_constant :Callback
|
50
39
|
end
|
data/lib/promise/group.rb
CHANGED
data/lib/promise/version.rb
CHANGED
data/spec/unit/promise_spec.rb
CHANGED
@@ -10,10 +10,10 @@ describe Promise do
|
|
10
10
|
|
11
11
|
let(:backtrace) { caller }
|
12
12
|
let(:reason) do
|
13
|
-
StandardError.new('reason').tap { |
|
13
|
+
StandardError.new('reason').tap { |err| err.set_backtrace(backtrace) }
|
14
14
|
end
|
15
15
|
let(:other_reason) do
|
16
|
-
StandardError.new('other_reason').tap { |
|
16
|
+
StandardError.new('other_reason').tap { |err| err.set_backtrace(caller) }
|
17
17
|
end
|
18
18
|
|
19
19
|
describe '3.1.1 pending' do
|
@@ -200,6 +200,25 @@ describe Promise do
|
|
200
200
|
expect(order).to eq([1, 2, 3])
|
201
201
|
end
|
202
202
|
|
203
|
+
it 'calls all on_fulfill callbacks even if one raises an exception' do
|
204
|
+
order = []
|
205
|
+
on_fulfill = proc do |i, val|
|
206
|
+
order << i
|
207
|
+
expect(val).to eq(value)
|
208
|
+
end
|
209
|
+
|
210
|
+
subject.then(on_fulfill.curry[1])
|
211
|
+
subject.then do |_|
|
212
|
+
order << 2
|
213
|
+
raise 'middle then error'
|
214
|
+
end
|
215
|
+
subject.then(on_fulfill.curry[3])
|
216
|
+
|
217
|
+
subject.fulfill(value)
|
218
|
+
|
219
|
+
expect(order).to eq([1, 2, 3])
|
220
|
+
end
|
221
|
+
|
203
222
|
it 'calls multiple on_reject callbacks in order of definition' do
|
204
223
|
order = []
|
205
224
|
on_reject = proc do |i, reas|
|
@@ -232,7 +251,6 @@ describe Promise do
|
|
232
251
|
|
233
252
|
expect(promise2).to be_fulfilled
|
234
253
|
expect(promise2.value).to eq(other_value)
|
235
|
-
expect(promise2.backtrace).to be(subject.backtrace)
|
236
254
|
end
|
237
255
|
|
238
256
|
it 'fulfills promise2 with value returned by on_reject' do
|
@@ -241,25 +259,22 @@ describe Promise do
|
|
241
259
|
|
242
260
|
expect(promise2).to be_fulfilled
|
243
261
|
expect(promise2.value).to eq(other_value)
|
244
|
-
expect(promise2.backtrace).to be(subject.backtrace)
|
245
262
|
end
|
246
263
|
|
247
264
|
it 'rejects promise2 with error raised by on_fulfill' do
|
248
265
|
promise2 = subject.then(proc { |_| raise error })
|
249
|
-
|
266
|
+
subject.fulfill(value)
|
250
267
|
|
251
268
|
expect(promise2).to be_rejected
|
252
269
|
expect(promise2.reason).to eq(error)
|
253
|
-
expect(promise2.backtrace).to be(subject.backtrace)
|
254
270
|
end
|
255
271
|
|
256
272
|
it 'rejects promise2 with error raised by on_reject' do
|
257
273
|
promise2 = subject.then(nil, proc { |_| raise error })
|
258
|
-
|
274
|
+
subject.reject(reason)
|
259
275
|
|
260
276
|
expect(promise2).to be_rejected
|
261
277
|
expect(promise2.reason).to eq(error)
|
262
|
-
expect(promise2.backtrace).to be(subject.backtrace)
|
263
278
|
end
|
264
279
|
|
265
280
|
describe 'on_fulfill returns promise' do
|
@@ -272,7 +287,6 @@ describe Promise do
|
|
272
287
|
returned_promise.fulfill(other_value)
|
273
288
|
expect(promise2).to be_fulfilled
|
274
289
|
expect(promise2.value).to eq(other_value)
|
275
|
-
expect(promise2.backtrace).to be(returned_promise.backtrace)
|
276
290
|
end
|
277
291
|
|
278
292
|
it 'makes promise2 assume rejected state of returned promise' do
|
@@ -284,7 +298,6 @@ describe Promise do
|
|
284
298
|
returned_promise.reject(other_reason)
|
285
299
|
expect(promise2).to be_rejected
|
286
300
|
expect(promise2.reason).to eq(other_reason)
|
287
|
-
expect(promise2.backtrace).to be(returned_promise.backtrace)
|
288
301
|
end
|
289
302
|
end
|
290
303
|
|
@@ -298,7 +311,6 @@ describe Promise do
|
|
298
311
|
returned_promise.fulfill(other_value)
|
299
312
|
expect(promise2).to be_fulfilled
|
300
313
|
expect(promise2.value).to eq(other_value)
|
301
|
-
expect(promise2.backtrace).to be(returned_promise.backtrace)
|
302
314
|
end
|
303
315
|
|
304
316
|
it 'makes promise2 assume rejected state of returned promise' do
|
@@ -310,7 +322,6 @@ describe Promise do
|
|
310
322
|
returned_promise.reject(other_reason)
|
311
323
|
expect(promise2).to be_rejected
|
312
324
|
expect(promise2.reason).to eq(other_reason)
|
313
|
-
expect(promise2.backtrace).to be(returned_promise.backtrace)
|
314
325
|
end
|
315
326
|
end
|
316
327
|
|
@@ -321,7 +332,6 @@ describe Promise do
|
|
321
332
|
|
322
333
|
expect(promise2).to be_fulfilled
|
323
334
|
expect(promise2.value).to eq(value)
|
324
|
-
expect(promise2.backtrace).to be(subject.backtrace)
|
325
335
|
end
|
326
336
|
end
|
327
337
|
|
@@ -332,7 +342,6 @@ describe Promise do
|
|
332
342
|
|
333
343
|
expect(promise2).to be_rejected
|
334
344
|
expect(promise2.reason).to eq(reason)
|
335
|
-
expect(promise2.backtrace).to be(subject.backtrace)
|
336
345
|
end
|
337
346
|
end
|
338
347
|
end
|
@@ -371,15 +380,24 @@ describe Promise do
|
|
371
380
|
expect(subject.fulfill(nil)).to eq(nil)
|
372
381
|
end
|
373
382
|
|
383
|
+
it 'does not return anything when given a promise' do
|
384
|
+
expect(subject.fulfill(Promise.new)).to eq(nil)
|
385
|
+
end
|
386
|
+
|
374
387
|
it 'does not require a value' do
|
375
388
|
subject.fulfill
|
376
389
|
expect(subject.value).to be(nil)
|
377
390
|
end
|
378
391
|
|
379
|
-
it '
|
380
|
-
|
381
|
-
|
382
|
-
|
392
|
+
it 'assumes the state of a given promise' do
|
393
|
+
promise = Promise.new
|
394
|
+
|
395
|
+
subject.fulfill(promise)
|
396
|
+
expect(subject).to be_pending
|
397
|
+
promise.fulfill(123)
|
398
|
+
|
399
|
+
expect(subject).to be_fulfilled
|
400
|
+
expect(subject.value).to eq(123)
|
383
401
|
end
|
384
402
|
end
|
385
403
|
|
@@ -390,14 +408,34 @@ describe Promise do
|
|
390
408
|
|
391
409
|
it 'does not require a reason' do
|
392
410
|
subject.reject
|
393
|
-
expect(subject.reason).to
|
411
|
+
expect(subject.reason).to be_a(Promise::Error)
|
394
412
|
end
|
395
413
|
|
396
414
|
it 'sets the backtrace' do
|
397
415
|
subject.reject
|
398
|
-
expect(subject.backtrace.join)
|
416
|
+
expect(subject.reason.backtrace.join)
|
399
417
|
.to include(__FILE__ + ':' + (__LINE__ - 2).to_s)
|
400
418
|
end
|
419
|
+
|
420
|
+
it 'leaves backtrace if already set' do
|
421
|
+
subject.reject(reason)
|
422
|
+
expect(subject.reason.backtrace).to eq(backtrace)
|
423
|
+
end
|
424
|
+
|
425
|
+
it 'instantiates exception class' do
|
426
|
+
subject.reject(Exception)
|
427
|
+
expect(subject.reason).to be_a(Exception)
|
428
|
+
end
|
429
|
+
|
430
|
+
it 'instantiates exception subclasses' do
|
431
|
+
subject.reject(RuntimeError)
|
432
|
+
expect(subject.reason).to be_a(RuntimeError)
|
433
|
+
end
|
434
|
+
|
435
|
+
it "doesn't instantiate non-error classes" do
|
436
|
+
subject.reject(Hash)
|
437
|
+
expect(subject.reason).to eq(Hash)
|
438
|
+
end
|
401
439
|
end
|
402
440
|
|
403
441
|
describe '#sync' do
|
@@ -425,12 +463,25 @@ describe Promise do
|
|
425
463
|
expect(promise.value).to eq(123)
|
426
464
|
end
|
427
465
|
|
428
|
-
it '
|
466
|
+
it 'returns a given promise' do
|
429
467
|
promise = Promise.new
|
430
468
|
new_promise = Promise.resolve(promise)
|
431
|
-
expect(new_promise.
|
469
|
+
expect(new_promise.object_id).to eq(promise.object_id)
|
470
|
+
end
|
471
|
+
|
472
|
+
it 'returns a given promise of a subclass of itself' do
|
473
|
+
promise = DelayedPromise.new
|
474
|
+
new_promise = Promise.resolve(promise)
|
475
|
+
expect(new_promise.object_id).to eq(promise.object_id)
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'assumes the state of a given promise of another class' do
|
479
|
+
promise = Promise.new
|
480
|
+
new_promise = DelayedPromise.resolve(promise)
|
481
|
+
expect(new_promise).to be_an_instance_of(DelayedPromise)
|
482
|
+
expect(new_promise).to be_pending
|
432
483
|
promise.fulfill(42)
|
433
|
-
expect(new_promise
|
484
|
+
expect(new_promise).to be_fulfilled
|
434
485
|
expect(new_promise.value).to eq(42)
|
435
486
|
end
|
436
487
|
end
|
@@ -492,6 +543,16 @@ describe Promise do
|
|
492
543
|
p1.fulfill(1.0)
|
493
544
|
expect(result.sync).to eq([1.0, 2])
|
494
545
|
end
|
546
|
+
|
547
|
+
it 'returns an instance of the class it is called on' do
|
548
|
+
p1 = DelayedPromise.new
|
549
|
+
|
550
|
+
result = DelayedPromise.all([p1, 2])
|
551
|
+
|
552
|
+
expect(result).to be_pending
|
553
|
+
p1.fulfill(1.0)
|
554
|
+
expect(result.sync).to eq([1.0, 2])
|
555
|
+
end
|
495
556
|
end
|
496
557
|
end
|
497
558
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: promise.rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.0.
|
4
|
+
version: 0.7.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lars Gierth
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|