em-promise 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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::Defer.new
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
- promise = asyncGreet('Robin Hood')
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
- @gem install em-promise@
45
+ # Read the "Documentation":http://rubydoc.info/gems/em-promise/EventMachine/Q
46
+ # Then @gem install em-promise@
@@ -1,3 +1,3 @@
1
1
  require 'eventmachine'
2
2
 
3
- require 'em-promise/defer.rb'
3
+ require 'em-promise/q.rb'
@@ -1,28 +1,46 @@
1
1
 
2
2
 
3
3
  module EventMachine
4
- #
5
- # Creates a 'Deferred' object which represents a task which will finish in the future.
6
- #
7
- class Defer
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 = Defer.new
37
+ result = Q.defer
20
38
 
21
39
  callback ||= blk
22
40
 
23
- wrappedCallback = proc { |value|
41
+ wrappedCallback = proc { |val|
24
42
  begin
25
- result.resolve(callback.nil? ? value : callback.call(value))
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? ? Defer.reject(reason) : errback.call(reason))
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 arrays
43
- # => Everything else is locally scoped
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
- protected
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 = Defer.new
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? ? Defer.reject(@response) : errback.call(@response))
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
- def promise
126
- DeferredPromise.new( self )
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 'eventmachine'
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 Defer.reject(reason)
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
- # @returns [Promise] Returns a single promise that will be resolved with an array of values,
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 = Defer.new
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
- protected
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
- Defer.ref(value)
274
+ Deferred.ref(value) # Defined in Q (DRY)
214
275
  end
215
276
  end
216
277
 
@@ -1,5 +1,5 @@
1
1
  module EventMachine
2
2
  class Defer
3
- VERSION = "1.0.3"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -4,10 +4,10 @@ require 'bundler/setup'
4
4
  require 'em-promise'
5
5
 
6
6
 
7
- describe EventMachine::Defer do
7
+ describe EventMachine::Q do
8
8
 
9
9
  before :each do
10
- @deferred = EM::Defer.new
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::Defer.new
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::Defer.new
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::Defer::Promise do
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::Defer.reject('some reason')
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::Defer.reject('not gonna happen')
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::Defer.reject('not gonna happen')
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::Defer.all().then(proc {|result|
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::Defer.new
453
- deferred2 = EM::Defer.new
452
+ deferred1 = EM::Q.defer
453
+ deferred2 = EM::Q.defer
454
454
 
455
- EM::Defer.all(@promise, deferred1.promise, deferred2.promise).then(proc {|result|
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::Defer.new
470
- deferred2 = EM::Defer.new
469
+ deferred1 = EM::Q.defer
470
+ deferred2 = EM::Q.defer
471
471
 
472
- EM::Defer.all(@promise, deferred1.promise, deferred2.promise).then(@default_fail, proc {|reason|
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.3
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 00:00:00.000000000 Z
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/defer.rb
53
+ - lib/em-promise/q.rb
54
54
  - lib/em-promise/version.rb
55
55
  - lib/em-promise.rb
56
56
  - MIT-LICENSE