em-promise 1.0.3 → 1.1.0
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.
- data/README.textile +8 -5
- data/lib/em-promise.rb +1 -1
- data/lib/em-promise/{defer.rb → q.rb} +111 -50
- data/lib/em-promise/version.rb +1 -1
- data/spec/defer_spec.rb +15 -15
- metadata +3 -3
data/README.textile
CHANGED
@@ -8,11 +8,10 @@ From the perspective of dealing with error handling, deferred and promise apis a
|
|
8
8
|
|
9
9
|
<pre><code class="ruby">
|
10
10
|
require 'rubygems'
|
11
|
-
require 'eventmachine'
|
12
11
|
require 'em-promise'
|
13
12
|
|
14
13
|
def asyncGreet(name)
|
15
|
-
deferred = EM::
|
14
|
+
deferred = EM::Q.defer
|
16
15
|
|
17
16
|
EM::Timer.new(5) do
|
18
17
|
EM.defer do
|
@@ -26,13 +25,16 @@ end
|
|
26
25
|
|
27
26
|
EventMachine.run do
|
28
27
|
|
29
|
-
|
30
|
-
promise.then(proc { |greeting|
|
28
|
+
asyncGreet('Robin Hood').then(proc { |greeting|
|
31
29
|
p "Success: #{greeting}"
|
32
30
|
}, proc { |reason|
|
33
31
|
p "Failed: #{reason}"
|
34
32
|
})
|
35
33
|
|
34
|
+
asyncGreet('The Dude').then do |greeting|
|
35
|
+
p "Jeff '#{greeting}' Lebowski"
|
36
|
+
end
|
37
|
+
|
36
38
|
end
|
37
39
|
|
38
40
|
</code></pre>
|
@@ -40,4 +42,5 @@ end
|
|
40
42
|
|
41
43
|
h2. Start using it now
|
42
44
|
|
43
|
-
|
45
|
+
# Read the "Documentation":http://rubydoc.info/gems/em-promise/EventMachine/Q
|
46
|
+
# Then @gem install em-promise@
|
data/lib/em-promise.rb
CHANGED
@@ -1,28 +1,46 @@
|
|
1
1
|
|
2
2
|
|
3
3
|
module EventMachine
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
|
5
|
+
|
6
|
+
class Q
|
7
|
+
private_class_method :new
|
8
|
+
|
8
9
|
|
10
|
+
# @abstract
|
9
11
|
class Promise
|
12
|
+
private_class_method :new
|
10
13
|
end
|
11
14
|
|
15
|
+
|
16
|
+
#
|
17
|
+
# A new promise instance is created when a deferred instance is created and can be
|
18
|
+
# retrieved by calling deferred.promise
|
19
|
+
#
|
12
20
|
class DeferredPromise < Promise
|
21
|
+
public_class_method :new
|
22
|
+
|
13
23
|
def initialize(defer)
|
24
|
+
raise ArgumentError unless defer.is_a?(Deferred)
|
25
|
+
super()
|
26
|
+
|
14
27
|
@defer = defer
|
15
28
|
end
|
16
29
|
|
17
|
-
|
30
|
+
#
|
31
|
+
# regardless of when the promise was or will be resolved / rejected, calls one of
|
32
|
+
# the success or error callbacks asynchronously as soon as the result is available.
|
33
|
+
# The callbacks are called with a single argument, the result or rejection reason.
|
34
|
+
#
|
35
|
+
# @param [Proc, Proc, &blk] callbacks success, error, success_block
|
18
36
|
def then(callback = nil, errback = nil, &blk)
|
19
|
-
result =
|
37
|
+
result = Q.defer
|
20
38
|
|
21
39
|
callback ||= blk
|
22
40
|
|
23
|
-
wrappedCallback = proc { |
|
41
|
+
wrappedCallback = proc { |val|
|
24
42
|
begin
|
25
|
-
result.resolve(callback.nil? ?
|
43
|
+
result.resolve(callback.nil? ? val : callback.call(val))
|
26
44
|
rescue => e
|
27
45
|
warn "\nUnhandled exception: #{e.message}\n#{e.backtrace.join("\n")}\n"
|
28
46
|
result.reject(e);
|
@@ -31,7 +49,7 @@ module EventMachine
|
|
31
49
|
|
32
50
|
wrappedErrback = proc { |reason|
|
33
51
|
begin
|
34
|
-
result.resolve(errback.nil? ?
|
52
|
+
result.resolve(errback.nil? ? Q.reject(reason) : errback.call(reason))
|
35
53
|
rescue => e
|
36
54
|
warn "Unhandled exception: #{e.message}\n#{e.backtrace.join("\n")}\n"
|
37
55
|
result.reject(e);
|
@@ -39,8 +57,8 @@ module EventMachine
|
|
39
57
|
}
|
40
58
|
|
41
59
|
#
|
42
|
-
# Schedule as we are touching
|
43
|
-
#
|
60
|
+
# Schedule as we are touching shared state
|
61
|
+
# Everything else is locally scoped
|
44
62
|
#
|
45
63
|
EM.schedule do
|
46
64
|
pending_array = pending
|
@@ -56,7 +74,7 @@ module EventMachine
|
|
56
74
|
end
|
57
75
|
|
58
76
|
|
59
|
-
|
77
|
+
private
|
60
78
|
|
61
79
|
|
62
80
|
def pending
|
@@ -69,21 +87,26 @@ module EventMachine
|
|
69
87
|
end
|
70
88
|
|
71
89
|
|
90
|
+
|
72
91
|
class ResolvedPromise < Promise
|
92
|
+
public_class_method :new
|
93
|
+
|
73
94
|
def initialize(response, error = false)
|
74
95
|
raise ArgumentError if error && response.is_a?(Promise)
|
96
|
+
super()
|
97
|
+
|
75
98
|
@error = error
|
76
99
|
@response = response
|
77
100
|
end
|
78
101
|
|
79
102
|
def then(callback = nil, errback = nil, &blk)
|
80
|
-
result =
|
103
|
+
result = Q.defer
|
81
104
|
|
82
105
|
callback ||= blk
|
83
106
|
|
84
107
|
EM.next_tick {
|
85
108
|
if @error
|
86
|
-
result.resolve(errback.nil? ?
|
109
|
+
result.resolve(errback.nil? ? Q.reject(@response) : errback.call(@response))
|
87
110
|
else
|
88
111
|
result.resolve(callback.nil? ? @response : callback.call(@response))
|
89
112
|
end
|
@@ -94,36 +117,13 @@ module EventMachine
|
|
94
117
|
end
|
95
118
|
|
96
119
|
|
97
|
-
def initialize
|
98
|
-
@pending = []
|
99
|
-
@value = nil
|
100
|
-
end
|
101
|
-
|
102
|
-
|
103
|
-
def resolve(val = nil)
|
104
|
-
EM.schedule do
|
105
|
-
if !!@pending
|
106
|
-
callbacks = @pending
|
107
|
-
@pending = nil
|
108
|
-
@value = ref(val)
|
109
|
-
|
110
|
-
if callbacks.length > 0
|
111
|
-
callbacks.each do |callback|
|
112
|
-
@value.then(callback[0], callback[1])
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
|
120
|
-
def reject(reason = nil)
|
121
|
-
resolve(Defer.reject(reason))
|
122
|
-
end
|
123
|
-
|
124
120
|
|
125
|
-
|
126
|
-
|
121
|
+
#
|
122
|
+
# Creates a Deferred object which represents a task which will finish in the future.
|
123
|
+
#
|
124
|
+
# @return [Deferred] Returns a new instance of Deferred
|
125
|
+
def self.defer
|
126
|
+
return Deferred.new
|
127
127
|
end
|
128
128
|
|
129
129
|
|
@@ -143,7 +143,7 @@ module EventMachine
|
|
143
143
|
# #!/usr/bin/env ruby
|
144
144
|
#
|
145
145
|
# require 'rubygems' # or use Bundler.setup
|
146
|
-
# require '
|
146
|
+
# require 'em-promise'
|
147
147
|
#
|
148
148
|
# promiseB = promiseA.then(lambda {|result|
|
149
149
|
# # success: do something and resolve promiseB with the old or a new result
|
@@ -155,10 +155,11 @@ module EventMachine
|
|
155
155
|
# # handle the error and recover
|
156
156
|
# return newPromiseOrValue
|
157
157
|
# end
|
158
|
-
# return
|
158
|
+
# return Q.reject(reason)
|
159
159
|
# })
|
160
160
|
#
|
161
161
|
# @param [Object] reason constant, message, exception or an object representing the rejection reason.
|
162
|
+
# @return [Promise] Returns a promise that was already resolved as rejected with the reason
|
162
163
|
def self.reject(reason = nil)
|
163
164
|
return ResolvedPromise.new( reason, true ) # A resolved failed promise
|
164
165
|
end
|
@@ -168,12 +169,12 @@ module EventMachine
|
|
168
169
|
# promises are resolved.
|
169
170
|
#
|
170
171
|
# @param [Promise] a number of promises that will be combined into a single promise
|
171
|
-
# @
|
172
|
+
# @return [Promise] Returns a single promise that will be resolved with an array of values,
|
172
173
|
# each value corresponding to the promise at the same index in the `promises` array. If any of
|
173
174
|
# the promises is resolved with a rejection, this resulting promise will be resolved with the
|
174
175
|
# same rejection.
|
175
176
|
def self.all(*promises)
|
176
|
-
deferred =
|
177
|
+
deferred = Q.defer
|
177
178
|
counter = promises.length
|
178
179
|
results = []
|
179
180
|
|
@@ -198,19 +199,79 @@ module EventMachine
|
|
198
199
|
end
|
199
200
|
|
200
201
|
return deferred.promise
|
201
|
-
end
|
202
|
+
end
|
202
203
|
|
203
204
|
|
204
|
-
|
205
|
+
private
|
205
206
|
|
206
207
|
|
207
208
|
def self.ref(value)
|
208
209
|
return value if value.is_a?(Promise)
|
209
210
|
return ResolvedPromise.new( value ) # A resolved success promise
|
210
211
|
end
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
#
|
216
|
+
# The purpose of the deferred object is to expose the associated Promise instance as well
|
217
|
+
# as APIs that can be used for signalling the successful or unsuccessful completion of a task.
|
218
|
+
#
|
219
|
+
class Q::Deferred < Q
|
220
|
+
public_class_method :new
|
221
|
+
private_class_method :defer
|
222
|
+
private_class_method :reject
|
223
|
+
private_class_method :all
|
224
|
+
|
225
|
+
def initialize
|
226
|
+
super()
|
227
|
+
|
228
|
+
@pending = []
|
229
|
+
@value = nil
|
230
|
+
end
|
231
|
+
|
232
|
+
#
|
233
|
+
# resolves the derived promise with the value. If the value is a rejection constructed via
|
234
|
+
# Q.reject, the promise will be rejected instead.
|
235
|
+
#
|
236
|
+
# @param [Object] val constant, message or an object representing the result.
|
237
|
+
def resolve(val = nil)
|
238
|
+
EM.schedule do
|
239
|
+
if not @pending.nil?
|
240
|
+
callbacks = @pending
|
241
|
+
@pending = nil
|
242
|
+
@value = ref(val)
|
243
|
+
|
244
|
+
if callbacks.length > 0
|
245
|
+
callbacks.each do |callback|
|
246
|
+
@value.then(callback[0], callback[1])
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
#
|
254
|
+
# rejects the derived promise with the reason. This is equivalent to resolving it with a rejection
|
255
|
+
# constructed via Q.reject.
|
256
|
+
#
|
257
|
+
# @param [Object] reason constant, message, exception or an object representing the rejection reason.
|
258
|
+
def reject(reason = nil)
|
259
|
+
resolve(Q.reject(reason))
|
260
|
+
end
|
261
|
+
|
262
|
+
#
|
263
|
+
# Creates a promise object associated with this deferred
|
264
|
+
#
|
265
|
+
def promise
|
266
|
+
DeferredPromise.new( self )
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
private
|
271
|
+
|
211
272
|
|
212
273
|
def ref(value)
|
213
|
-
|
274
|
+
Deferred.ref(value) # Defined in Q (DRY)
|
214
275
|
end
|
215
276
|
end
|
216
277
|
|
data/lib/em-promise/version.rb
CHANGED
data/spec/defer_spec.rb
CHANGED
@@ -4,10 +4,10 @@ require 'bundler/setup'
|
|
4
4
|
require 'em-promise'
|
5
5
|
|
6
6
|
|
7
|
-
describe EventMachine::
|
7
|
+
describe EventMachine::Q do
|
8
8
|
|
9
9
|
before :each do
|
10
|
-
@deferred = EM::
|
10
|
+
@deferred = EM::Q.defer
|
11
11
|
@promise = @deferred.promise
|
12
12
|
@log = []
|
13
13
|
@default_fail = proc { |reason|
|
@@ -86,7 +86,7 @@ describe EventMachine::Defer do
|
|
86
86
|
|
87
87
|
|
88
88
|
it "should allow deferred resolution with a new promise" do
|
89
|
-
deferred2 = EM::
|
89
|
+
deferred2 = EM::Q.defer
|
90
90
|
EventMachine.run {
|
91
91
|
@promise.then(proc {|result|
|
92
92
|
result.should == :foo
|
@@ -190,7 +190,7 @@ describe EventMachine::Defer do
|
|
190
190
|
|
191
191
|
|
192
192
|
it "should not defer rejection with a new promise" do
|
193
|
-
deferred2 = EM::
|
193
|
+
deferred2 = EM::Q.defer
|
194
194
|
EventMachine.run {
|
195
195
|
@promise.then(@default_fail, @default_fail)
|
196
196
|
begin
|
@@ -205,7 +205,7 @@ describe EventMachine::Defer do
|
|
205
205
|
end
|
206
206
|
|
207
207
|
|
208
|
-
describe EventMachine::
|
208
|
+
describe EventMachine::Q::Promise do
|
209
209
|
|
210
210
|
describe 'then' do
|
211
211
|
|
@@ -314,7 +314,7 @@ describe EventMachine::Defer do
|
|
314
314
|
})
|
315
315
|
@promise.then(@default_fail, proc {|result|
|
316
316
|
@log << result
|
317
|
-
EM::
|
317
|
+
EM::Q.reject('some reason')
|
318
318
|
})
|
319
319
|
@promise.then(@default_fail, proc {|result|
|
320
320
|
@log << result
|
@@ -393,7 +393,7 @@ describe EventMachine::Defer do
|
|
393
393
|
|
394
394
|
it "should package a string into a rejected promise" do
|
395
395
|
EventMachine.run {
|
396
|
-
rejectedPromise = EM::
|
396
|
+
rejectedPromise = EM::Q.reject('not gonna happen')
|
397
397
|
|
398
398
|
@promise.then(nil, proc {|reason|
|
399
399
|
@log << reason
|
@@ -411,7 +411,7 @@ describe EventMachine::Defer do
|
|
411
411
|
|
412
412
|
it "should return a promise that forwards callbacks if the callbacks are missing" do
|
413
413
|
EventMachine.run {
|
414
|
-
rejectedPromise = EM::
|
414
|
+
rejectedPromise = EM::Q.reject('not gonna happen')
|
415
415
|
|
416
416
|
@promise.then(nil, proc {|reason|
|
417
417
|
@log << reason
|
@@ -436,7 +436,7 @@ describe EventMachine::Defer do
|
|
436
436
|
|
437
437
|
it "should resolve all of nothing" do
|
438
438
|
EventMachine.run {
|
439
|
-
EM::
|
439
|
+
EM::Q.all.then(proc {|result|
|
440
440
|
@log << result
|
441
441
|
}, @default_fail)
|
442
442
|
|
@@ -449,10 +449,10 @@ describe EventMachine::Defer do
|
|
449
449
|
|
450
450
|
it "should take an array of promises and return a promise for an array of results" do
|
451
451
|
EventMachine.run {
|
452
|
-
deferred1 = EM::
|
453
|
-
deferred2 = EM::
|
452
|
+
deferred1 = EM::Q.defer
|
453
|
+
deferred2 = EM::Q.defer
|
454
454
|
|
455
|
-
EM::
|
455
|
+
EM::Q.all(@promise, deferred1.promise, deferred2.promise).then(proc {|result|
|
456
456
|
result.should == [:foo, :bar, :baz]
|
457
457
|
EM.stop
|
458
458
|
}, @default_fail)
|
@@ -466,10 +466,10 @@ describe EventMachine::Defer do
|
|
466
466
|
|
467
467
|
it "should reject the derived promise if at least one of the promises in the array is rejected" do
|
468
468
|
EventMachine.run {
|
469
|
-
deferred1 = EM::
|
470
|
-
deferred2 = EM::
|
469
|
+
deferred1 = EM::Q.defer
|
470
|
+
deferred2 = EM::Q.defer
|
471
471
|
|
472
|
-
EM::
|
472
|
+
EM::Q.all(@promise, deferred1.promise, deferred2.promise).then(@default_fail, proc {|reason|
|
473
473
|
reason.should == :baz
|
474
474
|
EM.stop
|
475
475
|
})
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-promise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.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: 2012-11-
|
12
|
+
date: 2012-11-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
@@ -50,7 +50,7 @@ executables: []
|
|
50
50
|
extensions: []
|
51
51
|
extra_rdoc_files: []
|
52
52
|
files:
|
53
|
-
- lib/em-promise/
|
53
|
+
- lib/em-promise/q.rb
|
54
54
|
- lib/em-promise/version.rb
|
55
55
|
- lib/em-promise.rb
|
56
56
|
- MIT-LICENSE
|