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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f0c296247c0162ee53783379115ff4a8aaa6a33e
4
- data.tar.gz: fcfdc65d25c8610894b0c00087b4a12762c53056
3
+ metadata.gz: 0caf50a0435f2f9bd47f702eb22de12e5ad672d2
4
+ data.tar.gz: dd71f5aa5e34a2b6302dcf6d65d5aecd41825f2f
5
5
  SHA512:
6
- metadata.gz: 36bc6091d46684b63bb142db5b4b638785ea69552f8e00f2377c7dfdbe88be38abcc9d60fe827bca648308c30071f272b58ff7aca87e86679f888527897e4ae9
7
- data.tar.gz: 6a6a19090556dfba2defc71ff3c2ac44e884682003df62439148c39b1c546e49f7b4a074276c83362552fc66b1e47984ccac758c7ab0e9116f447fd2fab88e2c
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
 
@@ -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 = new_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 = new_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 = new_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 = new_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
- if promises.all? {|promise| promise.fulfilled? or promise.rejected?}
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 = new_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
- if promises.all?(&:fulfilled?)
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.new_deferred
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(callback.call arg)
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.new_deferred
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
- synchronized { @state }
27
+ synchronize { @state }
27
28
  end
28
29
 
29
30
  def value
30
31
  wait
31
- synchronized { @value }
32
+ synchronize { @value }
32
33
  end
33
34
 
34
35
  def reason
35
36
  wait
36
- synchronized { @reason }
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
- synchronized do
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 synchronized
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
- synchronized do
95
- if @state == :pending
104
+ synchronize do
105
+ if @state == :pending and not @resolving
96
106
  if value.kind_of? SimplePromise
97
- @state = :resolving
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
- synchronized do
124
- if @state == :resolving
125
- @value = other.value
126
- @reason = other.reason
127
- @state = other.state
128
- callbacks.concat @on_resolution
129
- @on_resolution.clear
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 = synchronized do
148
+ immediate = synchronize do
140
149
  if @state == :fulfilled or @state == :rejected
141
150
  true
142
151
  else
@@ -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
- check_resolving d1.promise
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
- check_resolving d1.promise
74
+ check_pending d1.promise
75
75
  e = an_error
76
76
  d2.reject e
77
77
  d1.promise.wait
@@ -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
- end
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")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rosarium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rachel Evans