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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b98cd2e53ffcbfb4c387c41a85c9699b8c050f5e
4
- data.tar.gz: 22cf6c2bd54e4490470520aca42aa9f15abb24b4
3
+ metadata.gz: 487aaf8c555487ea2f7b3bbdb77a5a63b0be1f38
4
+ data.tar.gz: 1a1ede2482f03dd9c55c0050b913bc718b077bea
5
5
  SHA512:
6
- metadata.gz: 990eedfbc0cfb55355f2ca0bc963e0cec24d3668b7a22e8e97fb643bb6abd71da10dec39c9e4846f243bc3bad51b5e6a544a270d04a600f7fbca2b3d060e7f96
7
- data.tar.gz: dffd4ca2bd12d3ee92acb2dc4c719a7aacbe20a4563da016b21ad63d2909c1f22a5c68947b9369f3792b1440edf5e2b37f4b13d8b4e8aa4d14c0d4795ee83e25
6
+ metadata.gz: 31b9d4895eca8ceab77fcce63730ad620b2d7f294b2bd53eb47c6da412557c714ce58bb99cc1a87995dac172e554e61ea4b0ae94ef6004d63746a3acc2ed8399
7
+ data.tar.gz: 6bf132f844d4f83b7369ffd79711aa9b772c2d285507908510993099a4c1a54a3aab66eb2de7d2d4271509c62bbea24c71229086deff567adf73f5867d3b4f54
@@ -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
@@ -1,2 +1,2 @@
1
1
  ---
2
- threshold: 10.8
2
+ threshold: 10.6
@@ -60,7 +60,7 @@ TooManyInstanceVariables:
60
60
  TooManyMethods:
61
61
  enabled: true
62
62
  exclude: []
63
- max_methods: 12
63
+ max_methods: 13
64
64
  TooManyStatements:
65
65
  enabled: true
66
66
  exclude:
@@ -11,10 +11,10 @@ class Promise
11
11
 
12
12
  include Promise::Progress
13
13
 
14
- attr_reader :state, :value, :reason, :backtrace
14
+ attr_reader :state, :value, :reason
15
15
 
16
16
  def self.resolve(obj)
17
- return obj if obj.instance_of?(self)
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 { Callback.new(self, on_fulfill, on_reject, next_promise) }
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, backtrace = nil)
65
- dispatch(backtrace) do
66
- @state = :fulfilled
67
- @value = value
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, backtrace = nil)
72
- dispatch(backtrace) do
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 dispatch(backtrace)
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
- @backtrace = backtrace || caller
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.dispatch }
89
- end
90
-
91
- def defer
92
- yield
108
+ defer { callback.call }
93
109
  end
94
110
  end
@@ -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 block
13
- @promise.fulfilled? ? @on_fulfill : @on_reject
14
- end
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
- assume_state(@promise, @next_promise)
22
+ call_block(@on_reject, @promise.reason)
25
23
  end
26
24
  end
27
25
 
28
- def execute
29
- block.call(param)
30
- rescue => ex
31
- @next_promise.reject(ex, @promise.backtrace)
32
- raise
33
- end
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
- @next_promise.fulfill(result, @promise.backtrace)
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
@@ -32,7 +32,7 @@ class Promise
32
32
  end
33
33
 
34
34
  def promise?(obj)
35
- obj.instance_of?(Promise)
35
+ obj.is_a?(Promise)
36
36
  end
37
37
 
38
38
  def count_promises
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  class Promise
4
- VERSION = '0.7.0.rc1'
4
+ VERSION = '0.7.0.rc2'
5
5
  end
@@ -10,10 +10,10 @@ describe Promise do
10
10
 
11
11
  let(:backtrace) { caller }
12
12
  let(:reason) do
13
- StandardError.new('reason').tap { |ex| ex.set_backtrace(backtrace) }
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 { |ex| ex.set_backtrace(backtrace) }
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
- expect { subject.fulfill(value) }.to raise_error(error)
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
- expect { subject.reject(reason) }.to raise_error(error)
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 'sets the backtrace' do
380
- subject.fulfill
381
- expect(subject.backtrace.join)
382
- .to include(__FILE__ + ':' + (__LINE__ - 2).to_s)
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 be(Promise::Error)
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 'assumes the state of a given promise' do
466
+ it 'returns a given promise' do
429
467
  promise = Promise.new
430
468
  new_promise = Promise.resolve(promise)
431
- expect(new_promise.pending?).to eq(true)
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.fulfilled?).to eq(true)
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.rc1
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-09 00:00:00.000000000 Z
11
+ date: 2016-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec