rosarium 0.1.0 → 0.1.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.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/lib/rosarium/promise.rb +23 -19
- data/lib/rosarium/simple_promise.rb +27 -18
- data/spec/deferred_spec.rb +2 -2
- data/spec/promise_test_helper.rb +3 -8
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0caf50a0435f2f9bd47f702eb22de12e5ad672d2
|
4
|
+
data.tar.gz: dd71f5aa5e34a2b6302dcf6d65d5aecd41825f2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3075ef2b1dcd8cdf1911e00fafb55c211d940420a18bafe356b703236e2ce888fe299898dfbc37d99f99374a56eb2fc91f60bdddc5a92d6df6e56fe0129ce25b
|
7
|
+
data.tar.gz: d6575b8a7f78e44848d26e98b536e9bc08aec5db580af6523b04e10e541842256fe98b9ace1cf152adb17c64feddfd15e3e361aea1c92b33570a71242fd4a9ff
|
data/README.md
CHANGED
@@ -77,6 +77,10 @@ then later, use the "deferred" to fulfill or reject the promise:
|
|
77
77
|
# or nil (if fulfilled).
|
78
78
|
promise.reason
|
79
79
|
|
80
|
+
# A hash describing the state of the promise. Always includes :state key;
|
81
|
+
# may include :value or :reason.
|
82
|
+
promise.inspect
|
83
|
+
|
80
84
|
# true iff state == :fulfilled
|
81
85
|
promise.fulfilled?
|
82
86
|
|
data/lib/rosarium/promise.rb
CHANGED
@@ -5,28 +5,24 @@ module Rosarium
|
|
5
5
|
DEFAULT_ON_FULFILL = Proc.new {|value| value}
|
6
6
|
DEFAULT_ON_REJECT = Proc.new {|reason| raise reason}
|
7
7
|
|
8
|
-
def self.defer
|
9
|
-
new_deferred
|
10
|
-
end
|
11
|
-
|
12
8
|
def self.resolve(value)
|
13
9
|
if value.kind_of? Promise
|
14
10
|
return value
|
15
11
|
end
|
16
12
|
|
17
|
-
deferred =
|
13
|
+
deferred = defer
|
18
14
|
deferred.resolve(value)
|
19
15
|
deferred.promise
|
20
16
|
end
|
21
17
|
|
22
18
|
def self.reject(reason)
|
23
|
-
deferred =
|
19
|
+
deferred = defer
|
24
20
|
deferred.reject(reason)
|
25
21
|
deferred.promise
|
26
22
|
end
|
27
23
|
|
28
24
|
def self.execute(&block)
|
29
|
-
deferred =
|
25
|
+
deferred = defer
|
30
26
|
EXECUTOR.submit do
|
31
27
|
begin
|
32
28
|
deferred.resolve block.call
|
@@ -40,11 +36,15 @@ module Rosarium
|
|
40
36
|
def self.all_settled(promises)
|
41
37
|
return resolve([]) if promises.empty?
|
42
38
|
|
43
|
-
deferred =
|
39
|
+
deferred = defer
|
44
40
|
promises = promises.dup
|
45
41
|
|
42
|
+
waiting_for = promises.count
|
43
|
+
mutex = Mutex.new
|
44
|
+
|
46
45
|
check = Proc.new do
|
47
|
-
|
46
|
+
# Includes both fulfilled and rejected, so always hits zero eventually
|
47
|
+
if mutex.synchronize { (waiting_for -= 1) == 0 }
|
48
48
|
deferred.resolve promises
|
49
49
|
end
|
50
50
|
end
|
@@ -59,12 +59,16 @@ module Rosarium
|
|
59
59
|
def self.all(promises)
|
60
60
|
return resolve([]) if promises.empty?
|
61
61
|
|
62
|
-
deferred =
|
62
|
+
deferred = defer
|
63
63
|
promises = promises.dup
|
64
64
|
|
65
|
+
waiting_for = promises.count
|
66
|
+
mutex = Mutex.new
|
67
|
+
|
65
68
|
do_reject = Proc.new {|reason| deferred.reject reason}
|
66
69
|
do_fulfill = Proc.new do
|
67
|
-
|
70
|
+
# Only fulfilled (not rejected), so hits zero iff all promises were fulfilled
|
71
|
+
if mutex.synchronize { (waiting_for -= 1) == 0 }
|
68
72
|
deferred.resolve(promises.map &:value)
|
69
73
|
end
|
70
74
|
end
|
@@ -77,20 +81,20 @@ module Rosarium
|
|
77
81
|
end
|
78
82
|
|
79
83
|
def then(on_rejected = nil, &on_fulfilled)
|
80
|
-
deferred = self.class.
|
84
|
+
deferred = self.class.defer
|
81
85
|
|
82
86
|
on_fulfilled ||= DEFAULT_ON_FULFILL
|
83
87
|
on_rejected ||= DEFAULT_ON_REJECT
|
84
88
|
|
85
89
|
on_resolution do
|
86
|
-
callback, arg = if fulfilled?
|
87
|
-
[ on_fulfilled, value ]
|
88
|
-
else
|
89
|
-
[ on_rejected, reason ]
|
90
|
-
end
|
91
|
-
|
92
90
|
begin
|
93
|
-
deferred.resolve(
|
91
|
+
deferred.resolve(
|
92
|
+
if fulfilled?
|
93
|
+
on_fulfilled.call value
|
94
|
+
else
|
95
|
+
on_rejected.call reason
|
96
|
+
end
|
97
|
+
)
|
94
98
|
rescue Exception => e
|
95
99
|
deferred.reject e
|
96
100
|
end
|
@@ -2,7 +2,7 @@ module Rosarium
|
|
2
2
|
|
3
3
|
class SimplePromise
|
4
4
|
|
5
|
-
def self.
|
5
|
+
def self.defer
|
6
6
|
promise = new
|
7
7
|
resolver = promise.method :resolve
|
8
8
|
rejecter = promise.method :reject
|
@@ -17,23 +17,33 @@ module Rosarium
|
|
17
17
|
|
18
18
|
def initialize
|
19
19
|
@state = :pending
|
20
|
+
@resolving = false
|
20
21
|
@mutex = Mutex.new
|
21
22
|
@condition = ConditionVariable.new
|
22
23
|
@on_resolution = []
|
23
24
|
end
|
24
25
|
|
25
26
|
def state
|
26
|
-
|
27
|
+
synchronize { @state }
|
27
28
|
end
|
28
29
|
|
29
30
|
def value
|
30
31
|
wait
|
31
|
-
|
32
|
+
synchronize { @value }
|
32
33
|
end
|
33
34
|
|
34
35
|
def reason
|
35
36
|
wait
|
36
|
-
|
37
|
+
synchronize { @reason }
|
38
|
+
end
|
39
|
+
|
40
|
+
def inspect
|
41
|
+
synchronize do
|
42
|
+
r = { state: @state }
|
43
|
+
r[:value] = @value if @state == :fulfilled
|
44
|
+
r[:reason] = @reason if @state == :rejected
|
45
|
+
r
|
46
|
+
end
|
37
47
|
end
|
38
48
|
|
39
49
|
def fulfilled?
|
@@ -46,7 +56,7 @@ module Rosarium
|
|
46
56
|
|
47
57
|
def value!
|
48
58
|
wait
|
49
|
-
|
59
|
+
synchronize do
|
50
60
|
if @state == :rejected
|
51
61
|
raise @reason
|
52
62
|
else
|
@@ -70,7 +80,7 @@ module Rosarium
|
|
70
80
|
|
71
81
|
private
|
72
82
|
|
73
|
-
def
|
83
|
+
def synchronize
|
74
84
|
@mutex.synchronize { yield }
|
75
85
|
end
|
76
86
|
|
@@ -91,10 +101,10 @@ module Rosarium
|
|
91
101
|
callbacks = []
|
92
102
|
add_on_resolution = false
|
93
103
|
|
94
|
-
|
95
|
-
if @state == :pending
|
104
|
+
synchronize do
|
105
|
+
if @state == :pending and not @resolving
|
96
106
|
if value.kind_of? SimplePromise
|
97
|
-
@
|
107
|
+
@resolving = true
|
98
108
|
add_on_resolution = true
|
99
109
|
elsif reason.nil?
|
100
110
|
@value = value
|
@@ -120,14 +130,13 @@ module Rosarium
|
|
120
130
|
def copy_resolution_from(other)
|
121
131
|
callbacks = []
|
122
132
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
end
|
133
|
+
synchronize do
|
134
|
+
@value = other.value
|
135
|
+
@reason = other.reason
|
136
|
+
@state = other.state
|
137
|
+
@resolving = false
|
138
|
+
callbacks.concat @on_resolution
|
139
|
+
@on_resolution.clear
|
131
140
|
end
|
132
141
|
|
133
142
|
callbacks.each {|c| EXECUTOR.submit { c.call } }
|
@@ -136,7 +145,7 @@ module Rosarium
|
|
136
145
|
protected
|
137
146
|
|
138
147
|
def on_resolution(&block)
|
139
|
-
immediate =
|
148
|
+
immediate = synchronize do
|
140
149
|
if @state == :fulfilled or @state == :rejected
|
141
150
|
true
|
142
151
|
else
|
data/spec/deferred_spec.rb
CHANGED
@@ -61,7 +61,7 @@ describe "deferred promises" do
|
|
61
61
|
d1 = Rosarium::Promise.defer
|
62
62
|
d2 = Rosarium::Promise.defer
|
63
63
|
d1.resolve(d2.promise)
|
64
|
-
|
64
|
+
check_pending d1.promise
|
65
65
|
d2.resolve 7
|
66
66
|
d1.promise.wait
|
67
67
|
check_fulfilled d1.promise, 7
|
@@ -71,7 +71,7 @@ describe "deferred promises" do
|
|
71
71
|
d1 = Rosarium::Promise.defer
|
72
72
|
d2 = Rosarium::Promise.defer
|
73
73
|
d1.resolve(d2.promise)
|
74
|
-
|
74
|
+
check_pending d1.promise
|
75
75
|
e = an_error
|
76
76
|
d2.reject e
|
77
77
|
d1.promise.wait
|
data/spec/promise_test_helper.rb
CHANGED
@@ -6,14 +6,7 @@ module PromiseTestHelper
|
|
6
6
|
expect(promise).not_to be_rejected
|
7
7
|
# expect(promise.value).to be_nil # should block
|
8
8
|
# expect(promise.reason).to be_nil # should block
|
9
|
-
|
10
|
-
|
11
|
-
def check_resolving(promise)
|
12
|
-
expect(promise.state).to eq(:resolving)
|
13
|
-
expect(promise).not_to be_fulfilled
|
14
|
-
expect(promise).not_to be_rejected
|
15
|
-
# expect(promise.value).to be_nil # should block
|
16
|
-
# expect(promise.reason).to be_nil # should block
|
9
|
+
expect(promise.inspect).to eq(state: :pending)
|
17
10
|
end
|
18
11
|
|
19
12
|
def check_fulfilled(promise, value)
|
@@ -22,6 +15,7 @@ module PromiseTestHelper
|
|
22
15
|
expect(promise).not_to be_rejected
|
23
16
|
expect(promise.value).to eq(value)
|
24
17
|
expect(promise.reason).to be_nil
|
18
|
+
expect(promise.inspect).to eq(state: :fulfilled, value: value)
|
25
19
|
end
|
26
20
|
|
27
21
|
def check_rejected(promise, e)
|
@@ -30,6 +24,7 @@ module PromiseTestHelper
|
|
30
24
|
expect(promise).to be_rejected
|
31
25
|
expect(promise.value).to eq(nil)
|
32
26
|
expect(promise.reason).to eq(e)
|
27
|
+
expect(promise.inspect).to eq(state: :rejected, reason: e)
|
33
28
|
end
|
34
29
|
|
35
30
|
def an_error(message = "bang")
|