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.
@@ -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