promise.rb 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -1
- data/CHANGELOG.md +6 -0
- data/README.md +26 -3
- data/Rakefile +1 -1
- data/config/flay.yml +1 -1
- data/config/reek.yml +1 -1
- data/lib/promise.rb +8 -2
- data/lib/promise/version.rb +1 -1
- data/spec/promise_spec.rb +36 -8
- metadata +2 -2
data/.travis.yml
CHANGED
@@ -2,7 +2,7 @@ language: ruby
|
|
2
2
|
rvm:
|
3
3
|
- 1.9.3
|
4
4
|
- 2.0.0
|
5
|
-
- jruby
|
5
|
+
- jruby
|
6
6
|
- rbx
|
7
7
|
- ruby-head
|
8
8
|
- jruby-head
|
@@ -10,4 +10,5 @@ matrix:
|
|
10
10
|
allow_failures:
|
11
11
|
- rvm: ruby-head
|
12
12
|
- rvm: jruby-head
|
13
|
+
fast_finish: true
|
13
14
|
script: bundle exec rake -t metrics:coverage ci
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# promise.rb changelog
|
2
2
|
|
3
|
+
## 0.5.0 (December 16, 2013)
|
4
|
+
|
5
|
+
* Fulfillment value and rejection reason are no longer being frozen
|
6
|
+
* Rejection reason always gets a sensible backtrace now
|
7
|
+
* Have pending specs for deviations from the A+ spec
|
8
|
+
|
3
9
|
## 0.4.0 (December 13, 2013)
|
4
10
|
|
5
11
|
* Disclaiming my copyright, promise.rb is now in the Public Domain
|
data/README.md
CHANGED
@@ -6,15 +6,14 @@ Ruby implementation of the [Promises/A+ spec](http://promisesaplus.com/).
|
|
6
6
|
Similar projects:
|
7
7
|
|
8
8
|
- [concurrent-ruby](https://github.com/jdantonio/concurrent-ruby/blob/master/md/promise.md), Promises/A(+) implementation, thread based
|
9
|
+
- [ruby-thread](https://github.com/meh/ruby-thread), thread/mutex/condition variable based, thread safe
|
9
10
|
- [promise](https://github.com/bhuga/promising-future), a.k.a. promising-future, classic promises and futures, thread based
|
10
11
|
- [celluloid-promise](https://github.com/cotag/celluloid-promise), inspired by Q, backed by a Celluloid actor
|
11
12
|
- [em-promise](https://github.com/cotag/em-promise), inspired by Q, backed by an EventMachine reactor
|
12
13
|
- [futuristic](https://github.com/seanlilmateus/futuristic), MacRuby bindings for Grand Central Dispatch
|
13
14
|
- [methodmissing/promise](https://github.com/methodmissing/promise), thread based, abandoned
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
- test with https://gist.github.com/joeljackson/5722487
|
16
|
+
*Note that promise.rb is probably not thread safe.*
|
18
17
|
|
19
18
|
## Installation
|
20
19
|
|
@@ -81,6 +80,8 @@ end
|
|
81
80
|
failing_stuff.then(proc { |value| }, proc { |reason| p reason })
|
82
81
|
```
|
83
82
|
|
83
|
+
### Waiting for fulfillment/rejection
|
84
|
+
|
84
85
|
promise.rb also comes with the utility method `Promise#sync`, which waits for
|
85
86
|
the promise to be fulfilled and returns the value, or for it to be rejected and
|
86
87
|
re-raises the reason. Using `#sync` requires you to implement `#wait`. You could
|
@@ -127,6 +128,28 @@ end.resume
|
|
127
128
|
promise.reject(MyError.new)
|
128
129
|
```
|
129
130
|
|
131
|
+
### Chaining promises
|
132
|
+
|
133
|
+
As per the A+ spec, every call to `#then` returns a new promise, which assumes
|
134
|
+
the first promise's state. That means it passes its `#fulfill` and `#reject`
|
135
|
+
methods to first promise's `#then`, shortcircuiting the two promises. In case
|
136
|
+
a callback returns a promise, it'll instead assume that promise's state.
|
137
|
+
|
138
|
+
Imagine the `#fulfill` and `#reject` calls in the following example happening
|
139
|
+
somewhere in a background Fiber or so.
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
require 'promise'
|
143
|
+
|
144
|
+
Promise.new
|
145
|
+
.tap(&:fulfill)
|
146
|
+
.then { Promise.new.tap(&:fulfill) }
|
147
|
+
.then { Promise.new.tap(&:reject) }
|
148
|
+
.then(nil, proc { |reason| p reason })
|
149
|
+
```
|
150
|
+
|
151
|
+
### Progress callbacks
|
152
|
+
|
130
153
|
Very simple progress callbacks, as per Promises/A, are supported as well. They have been dropped in A+, but I found them to be a useful mechanism - if kept simple. Callback dispatch happens immediately in the call to `#progress`, in the order of definition via `#on_progress`. Also note that `#on_progress` does not return a new promise for chaining - the progress mechanism is meant to be very lightweight, and ignores many of the constraints and guarantees of `then`.
|
131
154
|
|
132
155
|
```ruby
|
data/Rakefile
CHANGED
data/config/flay.yml
CHANGED
data/config/reek.yml
CHANGED
data/lib/promise.rb
CHANGED
@@ -49,7 +49,8 @@ class Promise
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
def reject(reason =
|
52
|
+
def reject(reason = nil)
|
53
|
+
reason = build_reason(reason || RuntimeError, caller)
|
53
54
|
dispatch(@on_reject, reason) do
|
54
55
|
@state = :rejected
|
55
56
|
@reason = reason
|
@@ -68,7 +69,6 @@ class Promise
|
|
68
69
|
def dispatch(callbacks, arg)
|
69
70
|
if pending?
|
70
71
|
yield
|
71
|
-
arg.freeze
|
72
72
|
callbacks.each { |callback| dispatch!(callback, arg) }
|
73
73
|
end
|
74
74
|
|
@@ -97,4 +97,10 @@ class Promise
|
|
97
97
|
def defer
|
98
98
|
yield
|
99
99
|
end
|
100
|
+
|
101
|
+
def build_reason(reason, backtrace)
|
102
|
+
reason = reason.new if reason.respond_to?(:new)
|
103
|
+
reason.set_backtrace(backtrace) unless reason.backtrace
|
104
|
+
reason
|
105
|
+
end
|
100
106
|
end
|
data/lib/promise/version.rb
CHANGED
data/spec/promise_spec.rb
CHANGED
@@ -7,11 +7,13 @@ describe Promise do
|
|
7
7
|
|
8
8
|
let(:value) { double('value') }
|
9
9
|
let(:other_value) { double('other_value') }
|
10
|
+
|
11
|
+
let(:backtrace) { caller }
|
10
12
|
let(:reason) do
|
11
|
-
StandardError.new('reason').tap { |ex| ex.set_backtrace(
|
13
|
+
StandardError.new('reason').tap { |ex| ex.set_backtrace(backtrace) }
|
12
14
|
end
|
13
15
|
let(:other_reason) do
|
14
|
-
StandardError.new('other_reason').tap { |ex| ex.set_backtrace(
|
16
|
+
StandardError.new('other_reason').tap { |ex| ex.set_backtrace(backtrace) }
|
15
17
|
end
|
16
18
|
|
17
19
|
describe '3.1.1 pending' do
|
@@ -33,14 +35,16 @@ describe Promise do
|
|
33
35
|
expect(subject).to be_fulfilled
|
34
36
|
end
|
35
37
|
|
36
|
-
it 'has
|
38
|
+
it 'has a value' do
|
37
39
|
subject.fulfill(value)
|
38
40
|
expect(subject.value).to eq(value)
|
39
41
|
|
40
42
|
subject.fulfill(other_value)
|
41
43
|
expect(subject.value).to eq(value)
|
44
|
+
end
|
42
45
|
|
43
|
-
|
46
|
+
it 'freezes the value' do
|
47
|
+
pending 'Dropped in 74da6e9'
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
@@ -51,14 +55,16 @@ describe Promise do
|
|
51
55
|
expect(subject).to be_rejected
|
52
56
|
end
|
53
57
|
|
54
|
-
it 'has
|
58
|
+
it 'has a reason' do
|
55
59
|
subject.reject(reason)
|
56
60
|
expect(subject.reason).to eq(reason)
|
57
61
|
|
58
62
|
subject.reject(other_reason)
|
59
63
|
expect(subject.reason).to eq(reason)
|
64
|
+
end
|
60
65
|
|
61
|
-
|
66
|
+
it 'freezes the reason' do
|
67
|
+
pending 'Dropped in 74da6e9'
|
62
68
|
end
|
63
69
|
end
|
64
70
|
|
@@ -164,7 +170,7 @@ describe Promise do
|
|
164
170
|
|
165
171
|
describe '3.2.4' do
|
166
172
|
it 'returns before on_fulfill or on_reject is called' do
|
167
|
-
pending
|
173
|
+
pending 'To be implemented by application code'
|
168
174
|
end
|
169
175
|
end
|
170
176
|
|
@@ -358,7 +364,29 @@ describe Promise do
|
|
358
364
|
|
359
365
|
it 'does not require a reason' do
|
360
366
|
subject.reject
|
361
|
-
expect(subject.reason).to
|
367
|
+
expect(subject.reason).to be_a(RuntimeError)
|
368
|
+
end
|
369
|
+
|
370
|
+
it 'allows nil reason' do
|
371
|
+
subject.reject(nil)
|
372
|
+
expect(subject.reason).to be_a(RuntimeError)
|
373
|
+
end
|
374
|
+
|
375
|
+
it 'sets the backtrace' do
|
376
|
+
subject.reject
|
377
|
+
expect(subject.reason.backtrace[0])
|
378
|
+
.to include(__FILE__ + ':' + (__LINE__ - 2).to_s)
|
379
|
+
end
|
380
|
+
|
381
|
+
it 'does not override backtrace' do
|
382
|
+
subject.reject(reason)
|
383
|
+
expect(subject.reason.backtrace).to be(backtrace)
|
384
|
+
end
|
385
|
+
|
386
|
+
it 'builds exception object for custom error class' do
|
387
|
+
cls = Class.new(StandardError)
|
388
|
+
subject.reject(cls)
|
389
|
+
expect(subject.reason).to be_a(cls)
|
362
390
|
end
|
363
391
|
end
|
364
392
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: promise.rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-12-
|
12
|
+
date: 2013-12-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|