em-promise 1.0.1 → 1.0.2

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.
@@ -1,20 +1,20 @@
1
- Copyright 2012 YOURNAME
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -24,9 +24,7 @@ module EventMachine
24
24
  begin
25
25
  result.resolve(callback.nil? ? value : callback.call(value))
26
26
  rescue => e
27
- #
28
- # TODO:: add debugging output here
29
- #
27
+ warn "\nUnhandled exception: #{e.message}\n#{e.backtrace.join("\n")}\n"
30
28
  result.reject(e);
31
29
  end
32
30
  }
@@ -35,9 +33,7 @@ module EventMachine
35
33
  begin
36
34
  result.resolve(errback.nil? ? Defer.reject(reason) : errback.call(reason))
37
35
  rescue => e
38
- #
39
- # TODO:: add debugging output here
40
- #
36
+ warn "Unhandled exception: #{e.message}\n#{e.backtrace.join("\n")}\n"
41
37
  result.reject(e);
42
38
  end
43
39
  }
@@ -75,6 +71,7 @@ module EventMachine
75
71
 
76
72
  class ResolvedPromise < Promise
77
73
  def initialize(response, error = false)
74
+ raise ArgumentError if error && response.is_a?(Promise)
78
75
  @error = error
79
76
  @response = response
80
77
  end
@@ -111,11 +108,9 @@ module EventMachine
111
108
  @value = ref(val)
112
109
 
113
110
  if callbacks.length > 0
114
- EM.next_tick {
115
- callbacks.each do |callback|
116
- @value.then(callback[0], callback[1])
117
- end
118
- }
111
+ callbacks.each do |callback|
112
+ @value.then(callback[0], callback[1])
113
+ end
119
114
  end
120
115
  end
121
116
  end
@@ -168,14 +163,55 @@ module EventMachine
168
163
  return ResolvedPromise.new( reason, true ) # A resolved failed promise
169
164
  end
170
165
 
166
+ #
167
+ # Combines multiple promises into a single promise that is resolved when all of the input
168
+ # promises are resolved.
169
+ #
170
+ # @param [Promise] a number of promises that will be combined into a single promise
171
+ # @returns [Promise] Returns a single promise that will be resolved with an array of values,
172
+ # each value corresponding to the promise at the same index in the `promises` array. If any of
173
+ # the promises is resolved with a rejection, this resulting promise will be resolved with the
174
+ # same rejection.
175
+ def self.all(*promises)
176
+ deferred = Defer.new
177
+ counter = promises.length
178
+ results = []
179
+
180
+ if counter > 0
181
+ promises.each_index do |index|
182
+ ref(promises[index]).then(proc {|result|
183
+ if results[index].nil?
184
+ results[index] = result
185
+ counter -= 1
186
+ deferred.resolve(results) if counter <= 0
187
+ end
188
+ result
189
+ }, proc {|reason|
190
+ if results[index].nil?
191
+ deferred.reject(reason)
192
+ end
193
+ reason
194
+ })
195
+ end
196
+ else
197
+ deferred.resolve(results)
198
+ end
199
+
200
+ return deferred.promise
201
+ end
202
+
171
203
 
172
204
  protected
173
205
 
174
206
 
175
- def ref(value)
207
+ def self.ref(value)
176
208
  return value if value.is_a?(Promise)
177
209
  return ResolvedPromise.new( value ) # A resolved success promise
178
210
  end
211
+
212
+ def ref(value)
213
+ Defer.ref(value)
214
+ end
179
215
  end
180
216
 
181
217
  end
@@ -1,5 +1,5 @@
1
1
  module EventMachine
2
2
  class Defer
3
- VERSION = "1.0.1"
3
+ VERSION = "1.0.2"
4
4
  end
5
5
  end
@@ -5,26 +5,482 @@ require 'em-promise'
5
5
 
6
6
 
7
7
  describe EventMachine::Defer do
8
+
9
+ before :each do
10
+ @deferred = EM::Defer.new
11
+ @promise = @deferred.promise
12
+ @log = []
13
+ @default_fail = proc { |reason|
14
+ fail(reason)
15
+ EM.stop
16
+ }
17
+ end
18
+
19
+
20
+ describe 'resolve' do
21
+
22
+
23
+ it "should call the callback in the next turn" do
24
+ deferred2 = EM::Defer.new
25
+ EventMachine.run {
26
+ @promise.then(proc {|result|
27
+ @log << result
28
+ }, @default_fail)
29
+
30
+ @deferred.resolve(:foo)
31
+
32
+ EM.next_tick do
33
+ @log.should == [:foo]
34
+ EM.stop
35
+ end
36
+ }
37
+ end
38
+
39
+
40
+ it "should fulfill success callbacks in the registration order" do
41
+ EventMachine.run {
42
+ @promise.then(proc {|result|
43
+ @log << :first
44
+ }, @default_fail)
45
+
46
+ @promise.then(proc {|result|
47
+ @log << :second
48
+ }, @default_fail)
49
+
50
+ @deferred.resolve(:foo)
51
+
52
+ EM.next_tick do
53
+ @log.should == [:first, :second]
54
+ EM.stop
55
+ end
56
+ }
57
+ end
58
+
59
+
60
+ it "should do nothing if a promise was previously resolved" do
61
+ EventMachine.run {
62
+ @promise.then(proc {|result|
63
+ @log << result
64
+ @log.should == [:foo]
65
+ @deferred.resolve(:bar)
66
+ }, @default_fail)
67
+
68
+ @deferred.resolve(:foo)
69
+ @deferred.reject(:baz)
70
+
71
+ #
72
+ # 4 ticks should detect any errors
73
+ #
74
+ EM.next_tick do
75
+ EM.next_tick do
76
+ EM.next_tick do
77
+ EM.next_tick do
78
+ @log.should == [:foo]
79
+ EM.stop
80
+ end
81
+ end
82
+ end
83
+ end
84
+ }
85
+ end
86
+
87
+
88
+ it "should allow deferred resolution with a new promise" do
89
+ deferred2 = EM::Defer.new
90
+ EventMachine.run {
91
+ @promise.then(proc {|result|
92
+ result.should == :foo
93
+ EM.stop
94
+ }, @default_fail)
95
+
96
+ @deferred.resolve(deferred2.promise)
97
+ deferred2.resolve(:foo)
98
+ }
99
+ end
100
+
101
+
102
+ it "should not break if a callbacks registers another callback" do
103
+ EventMachine.run {
104
+ @promise.then(proc {|result|
105
+ @log << :outer
106
+ @promise.then(proc {|result|
107
+ @log << :inner
108
+ }, @default_fail)
109
+ }, @default_fail)
110
+
111
+ @deferred.resolve(:foo)
112
+
113
+ EM.next_tick do
114
+ EM.next_tick do
115
+ @log.should == [:outer, :inner]
116
+ EM.stop
117
+ end
118
+ end
119
+ }
120
+ end
121
+
122
+
123
+
124
+ it "can modify the result of a promise before returning" do
125
+ EventMachine.run {
126
+ proc { |name|
127
+ EM.defer { @deferred.resolve("Hello #{name}") }
128
+ @promise.then(proc {|result|
129
+ result.should == 'Hello Robin Hood'
130
+ result += "?"
131
+ result
132
+ })
133
+ }.call('Robin Hood').then(proc { |greeting|
134
+ greeting.should == 'Hello Robin Hood?'
135
+ EM.stop
136
+ }, @default_fail)
137
+ }
138
+ end
139
+
140
+ end
141
+
142
+
143
+ describe 'reject' do
144
+
145
+ it "should reject the promise and execute all error callbacks" do
146
+ EventMachine.run {
147
+ @promise.then(@default_fail, proc {|result|
148
+ @log << :first
149
+ })
150
+ @promise.then(@default_fail, proc {|result|
151
+ @log << :second
152
+ })
153
+
154
+ @deferred.reject(:foo)
155
+
156
+ EM.next_tick do
157
+ @log.should == [:first, :second]
158
+ EM.stop
159
+ end
160
+ }
161
+ end
162
+
163
+
164
+ it "should do nothing if a promise was previously rejected" do
165
+ EventMachine.run {
166
+ @promise.then(@default_fail, proc {|result|
167
+ @log << result
168
+ @log.should == [:baz]
169
+ @deferred.resolve(:bar)
170
+ })
171
+
172
+ @deferred.reject(:baz)
173
+ @deferred.resolve(:foo)
174
+
175
+ #
176
+ # 4 ticks should detect any errors
177
+ #
178
+ EM.next_tick do
179
+ EM.next_tick do
180
+ EM.next_tick do
181
+ EM.next_tick do
182
+ @log.should == [:baz]
183
+ EM.stop
184
+ end
185
+ end
186
+ end
187
+ end
188
+ }
189
+ end
190
+
191
+
192
+ it "should not defer rejection with a new promise" do
193
+ deferred2 = EM::Defer.new
194
+ EventMachine.run {
195
+ @promise.then(@default_fail, @default_fail)
196
+ begin
197
+ @deferred.reject(deferred2.promise)
198
+ rescue => e
199
+ e.is_a?(ArgumentError).should == true
200
+ EM.stop
201
+ end
202
+ }
203
+ end
204
+
205
+ end
206
+
207
+
208
+ describe EventMachine::Defer::Promise do
209
+
210
+ describe 'then' do
211
+
212
+ it "should allow registration of a success callback without an errback and resolve" do
213
+ EventMachine.run {
214
+ @promise.then(proc {|result|
215
+ @log << result
216
+ })
217
+
218
+ @deferred.resolve(:foo)
219
+
220
+ EM.next_tick do
221
+ @log.should == [:foo]
222
+ EM.stop
223
+ end
224
+ }
225
+ end
226
+
227
+
228
+ it "should allow registration of a success callback without an errback and reject" do
229
+ EventMachine.run {
230
+ @promise.then(proc {|result|
231
+ @log << result
232
+ })
233
+
234
+ @deferred.reject(:foo)
235
+
236
+ EM.next_tick do
237
+ @log.should == []
238
+ EM.stop
239
+ end
240
+ }
241
+ end
242
+
243
+
244
+ it "should allow registration of an errback without a success callback and reject" do
245
+ EventMachine.run {
246
+ @promise.then(nil, proc {|reason|
247
+ @log << reason
248
+ })
249
+
250
+ @deferred.reject(:foo)
251
+
252
+ EM.next_tick do
253
+ @log.should == [:foo]
254
+ EM.stop
255
+ end
256
+ }
257
+ end
258
+
259
+
260
+ it "should allow registration of an errback without a success callback and resolve" do
261
+ EventMachine.run {
262
+ @promise.then(nil, proc {|reason|
263
+ @log << reason
264
+ })
8
265
 
266
+ @deferred.resolve(:foo)
267
+
268
+ EM.next_tick do
269
+ @log.should == []
270
+ EM.stop
271
+ end
272
+ }
273
+ end
274
+
275
+
276
+ it "should resolve all callbacks with the original value" do
277
+ EventMachine.run {
278
+ @promise.then(proc {|result|
279
+ @log << result
280
+ :alt1
281
+ }, @default_fail)
282
+ @promise.then(proc {|result|
283
+ @log << result
284
+ 'ERROR'
285
+ }, @default_fail)
286
+ @promise.then(proc {|result|
287
+ @log << result
288
+ EM::Defer.reject('some reason')
289
+ }, @default_fail)
290
+ @promise.then(proc {|result|
291
+ @log << result
292
+ :alt2
293
+ }, @default_fail)
294
+
295
+ @deferred.resolve(:foo)
296
+
297
+ EM.next_tick do
298
+ @log.should == [:foo, :foo, :foo, :foo]
299
+ EM.stop
300
+ end
301
+ }
302
+ end
303
+
304
+
305
+ it "should reject all callbacks with the original reason" do
306
+ EventMachine.run {
307
+ @promise.then(@default_fail, proc {|result|
308
+ @log << result
309
+ :alt1
310
+ })
311
+ @promise.then(@default_fail, proc {|result|
312
+ @log << result
313
+ 'ERROR'
314
+ })
315
+ @promise.then(@default_fail, proc {|result|
316
+ @log << result
317
+ EM::Defer.reject('some reason')
318
+ })
319
+ @promise.then(@default_fail, proc {|result|
320
+ @log << result
321
+ :alt2
322
+ })
323
+
324
+ @deferred.reject(:foo)
325
+
326
+ EM.next_tick do
327
+ @log.should == [:foo, :foo, :foo, :foo]
328
+ EM.stop
329
+ end
330
+ }
331
+ end
332
+
333
+
334
+ it "should propagate resolution and rejection between dependent promises" do
335
+ EventMachine.run {
336
+ @promise.then(proc {|result|
337
+ @log << result
338
+ :bar
339
+ }, @default_fail).then(proc {|result|
340
+ @log << result
341
+ raise 'baz'
342
+ }, @default_fail).then(@default_fail, proc {|result|
343
+ @log << result.message
344
+ raise 'bob'
345
+ }).then(@default_fail, proc {|result|
346
+ @log << result.message
347
+ :done
348
+ }).then(proc {|result|
349
+ @log << result
350
+ }, @default_fail)
351
+
352
+ @deferred.resolve(:foo)
353
+
354
+ EM.next_tick do
355
+ EM.next_tick do
356
+ EM.next_tick do
357
+ EM.next_tick do
358
+ EM.next_tick do
359
+ @log.should == [:foo, :bar, 'baz', 'bob', :done]
360
+ EM.stop
361
+ end
362
+ end
363
+ end
364
+ end
365
+ end
366
+ }
367
+ end
368
+
369
+
370
+ it "should call error callback in the next turn even if promise is already rejected" do
371
+ EventMachine.run {
372
+ @deferred.reject(:foo)
373
+
374
+ @promise.then(nil, proc {|reason|
375
+ @log << reason
376
+ })
377
+
378
+ EM.next_tick do
379
+ @log.should == [:foo]
380
+ EM.stop
381
+ end
382
+ }
383
+ end
384
+
385
+
386
+ end
387
+
388
+ end
389
+
9
390
 
10
- it "should fulfill the promise and execute all success callbacks in the registration order" do
11
- EventMachine.run {
12
- proc { |name|
13
- deferred = EM::Defer.new
14
- EM.defer { deferred.resolve("Hello #{name}") }
15
- deferred.promise.then(proc {|result|
16
- result += "?"
17
- result
391
+
392
+ describe 'reject' do
393
+
394
+ it "should package a string into a rejected promise" do
395
+ EventMachine.run {
396
+ rejectedPromise = EM::Defer.reject('not gonna happen')
397
+
398
+ @promise.then(nil, proc {|reason|
399
+ @log << reason
18
400
  })
19
- }.call('Robin Hood').then(proc { |greeting|
20
- greeting.should == 'Hello Robin Hood?'
21
- EventMachine.stop
22
- }, proc { |reason|
23
- fail(reason)
24
- EventMachine.stop
25
- })
26
- }
401
+
402
+ @deferred.resolve(rejectedPromise)
403
+
404
+ EM.next_tick do
405
+ @log.should == ['not gonna happen']
406
+ EM.stop
407
+ end
408
+ }
409
+ end
410
+
411
+
412
+ it "should return a promise that forwards callbacks if the callbacks are missing" do
413
+ EventMachine.run {
414
+ rejectedPromise = EM::Defer.reject('not gonna happen')
415
+
416
+ @promise.then(nil, proc {|reason|
417
+ @log << reason
418
+ })
419
+
420
+ @deferred.resolve(rejectedPromise.then())
421
+
422
+ EM.next_tick do
423
+ EM.next_tick do
424
+ @log.should == ['not gonna happen']
425
+ EM.stop
426
+ end
427
+ end
428
+ }
429
+ end
430
+
27
431
  end
432
+
433
+
434
+
435
+ describe 'all' do
436
+
437
+ it "should resolve all of nothing" do
438
+ EventMachine.run {
439
+ EM::Defer.all().then(proc {|result|
440
+ @log << result
441
+ }, @default_fail)
442
+
443
+ EM.next_tick do
444
+ @log.should == [[]]
445
+ EM.stop
446
+ end
447
+ }
448
+ end
449
+
450
+ it "should take an array of promises and return a promise for an array of results" do
451
+ EventMachine.run {
452
+ deferred1 = EM::Defer.new
453
+ deferred2 = EM::Defer.new
454
+
455
+ EM::Defer.all(@promise, deferred1.promise, deferred2.promise).then(proc {|result|
456
+ result.should == [:foo, :bar, :baz]
457
+ EM.stop
458
+ }, @default_fail)
459
+
460
+ EM.defer { @deferred.resolve(:foo) }
461
+ EM.defer { deferred2.resolve(:baz) }
462
+ EM.defer { deferred1.resolve(:bar) }
463
+ }
464
+ end
465
+
466
+
467
+ it "should reject the derived promise if at least one of the promises in the array is rejected" do
468
+ EventMachine.run {
469
+ deferred1 = EM::Defer.new
470
+ deferred2 = EM::Defer.new
471
+
472
+ EM::Defer.all(@promise, deferred1.promise, deferred2.promise).then(@default_fail, proc {|reason|
473
+ reason.should == :baz
474
+ EM.stop
475
+ })
476
+
477
+ EM.defer { @deferred.resolve(:foo) }
478
+ EM.defer { deferred2.reject(:baz) }
479
+ }
480
+ end
481
+
482
+ end
483
+
28
484
 
29
485
 
30
486
  end
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.1
4
+ version: 1.0.2
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-10-21 00:00:00.000000000 Z
12
+ date: 2012-10-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine