Skip to content

Commit 2fe40b9

Browse files
committed
Renamed new Promise methods to all?, any?, none?, and on? (added question marks).
1 parent 26ae888 commit 2fe40b9

File tree

2 files changed

+104
-68
lines changed

2 files changed

+104
-68
lines changed

lib/concurrent/promise.rb

Lines changed: 80 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,41 @@ module Concurrent
77

88
PromiseExecutionError = Class.new(StandardError)
99

10-
# Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A) and [Promises/A+](http://promises-aplus.github.io/promises-spec/) specifications.
10+
# Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A)
11+
# and [Promises/A+](http://promises-aplus.github.io/promises-spec/) specifications.
1112
#
1213
# > A promise represents the eventual value returned from the single completion of an operation.
1314
#
14-
# Promises are similar to futures and share many of the same behaviours. Promises are far more robust, however. Promises can be chained in a tree structure where each promise may have zero or more children. Promises are chained using the `then` method. The result of a call to `then` is always another promise. Promises are resolved asynchronously (with respect to the main thread) but in a strict order: parents are guaranteed to be resolved before their children, children before their younger siblings. The `then` method takes two parameters: an optional block to be executed upon parent resolution and an optional callable to be executed upon parent failure. The result of each promise is passed to each of its children upon resolution. When a promise is rejected all its children will be summarily rejected and will receive the reason.
15-
#
16-
# Promises have four possible states: *unscheduled*, *pending*, *rejected*, and *fulfilled*. A Promise created using `.new` will be *unscheduled*. It is scheduled by calling the `execute` method. Upon execution the Promise and all its children will be set to *pending*. When a promise is *pending* it will remain in that state until processing is complete. A completed Promise is either *rejected*, indicating that an exception was thrown during processing, or *fulfilled*, indicating it succeeded. If a Promise is *fulfilled* its `value` will be updated to reflect the result of the operation. If *rejected* the `reason` will be updated with a reference to the thrown exception. The predicate methods `unscheduled?`, `pending?`, `rejected?`, and `fulfilled?` can be called at any time to obtain the state of the Promise, as can the `state` method, which returns a symbol. A Promise created using `.execute` will be *pending*, a Promise created using `.fulfill(value)` will be *fulfilled* with the given value and a Promise created using `.reject(reason)` will be *rejected* with the given reason.
17-
#
18-
# Retrieving the value of a promise is done through the `value` (alias: `deref`) method. Obtaining the value of a promise is a potentially blocking operation. When a promise is *rejected* a call to `value` will return `nil` immediately. When a promise is *fulfilled* a call to `value` will immediately return the current value. When a promise is *pending* a call to `value` will block until the promise is either *rejected* or *fulfilled*. A *timeout* value can be passed to `value` to limit how long the call will block. If `nil` the call will block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the maximum number of seconds to block.
15+
# Promises are similar to futures and share many of the same behaviours. Promises are far more
16+
# robust, however. Promises can be chained in a tree structure where each promise may have zero
17+
# or more children. Promises are chained using the `then` method. The result of a call to `then`
18+
# is always another promise. Promises are resolved asynchronously (with respect to the main thread)
19+
# but in a strict order: parents are guaranteed to be resolved before their children, children
20+
# before their younger siblings. The `then` method takes two parameters: an optional block to
21+
# be executed upon parent resolution and an optional callable to be executed upon parent failure.
22+
# The result of each promise is passed to each of its children upon resolution. When a promise
23+
# is rejected all its children will be summarily rejected and will receive the reason.
24+
#
25+
# Promises have four possible states: *unscheduled*, *pending*, *rejected*, and *fulfilled*. A
26+
# Promise created using `.new` will be *unscheduled*. It is scheduled by calling the `execute`
27+
# method. Upon execution the Promise and all its children will be set to *pending*. When a promise
28+
# is *pending* it will remain in that state until processing is complete. A completed Promise is
29+
# either *rejected*, indicating that an exception was thrown during processing, or *fulfilled*,
30+
# indicating it succeeded. If a Promise is *fulfilled* its `value` will be updated to reflect
31+
# the result of the operation. If *rejected* the `reason` will be updated with a reference to
32+
# the thrown exception. The predicate methods `unscheduled?`, `pending?`, `rejected?`, and
33+
# `fulfilled?` can be called at any time to obtain the state of the Promise, as can the `state`
34+
# method, which returns a symbol. A Promise created using `.execute` will be *pending*, a Promise
35+
# created using `.fulfill(value)` will be *fulfilled* with the given value and a Promise created
36+
# using `.reject(reason)` will be *rejected* with the given reason.
37+
#
38+
# Retrieving the value of a promise is done through the `value` (alias: `deref`) method. Obtaining
39+
# the value of a promise is a potentially blocking operation. When a promise is *rejected* a call
40+
# to `value` will return `nil` immediately. When a promise is *fulfilled* a call to `value` will
41+
# immediately return the current value. When a promise is *pending* a call to `value` will block
42+
# until the promise is either *rejected* or *fulfilled*. A *timeout* value can be passed to `value`
43+
# to limit how long the call will block. If `nil` the call will block indefinitely. If `0` the call
44+
# will not block. Any other integer or float value will indicate the maximum number of seconds to block.
1945
#
2046
# Promises run on the global thread pool.
2147
#
@@ -30,13 +56,15 @@ module Concurrent
3056
# Then create one
3157
#
3258
# ```ruby
33-
# p = Promise.execute do
59+
# p = Concurrent::Promise.execute do
3460
# # do something
3561
# 42
3662
# end
3763
# ```
3864
#
39-
# Promises can be chained using the `then` method. The `then` method accepts a block, to be executed on fulfillment, and a callable argument to be executed on rejection. The result of the each promise is passed as the block argument to chained promises.
65+
# Promises can be chained using the `then` method. The `then` method accepts a block, to be executed
66+
# on fulfillment, and a callable argument to be executed on rejection. The result of the each promise
67+
# is passed as the block argument to chained promises.
4068
#
4169
# ```ruby
4270
# p = Concurrent::Promise.new{10}.then{|x| x * 2}.then{|result| result - 10 }.execute
@@ -57,7 +85,10 @@ module Concurrent
5785
# - if parent is *fulfilled* the child will be *pending*
5886
# - if parent is *rejected* the child will be *pending* (but will ultimately be *rejected*)
5987
#
60-
# Promises are executed asynchronously from the main thread. By the time a child Promise finishes initialization it may be in a different state that its parent (by the time a child is created its parent may have completed execution and changed state). Despite being asynchronous, however, the order of execution of Promise objects in a chain (or tree) is strictly defined.
88+
# Promises are executed asynchronously from the main thread. By the time a child Promise finishes
89+
# nitialization it may be in a different state that its parent (by the time a child is created its parent
90+
# may have completed execution and changed state). Despite being asynchronous, however, the order of
91+
# execution of Promise objects in a chain (or tree) is strictly defined.
6192
#
6293
# There are multiple ways to create and execute a new `Promise`. Both ways provide identical behavior:
6394
#
@@ -107,7 +138,8 @@ module Concurrent
107138
#
108139
# #### Rejection
109140
#
110-
# When a promise is rejected all its children will be rejected and will receive the rejection `reason` as the rejection callable parameter:
141+
# When a promise is rejected all its children will be rejected and will receive the rejection `reason`
142+
# as the rejection callable parameter:
111143
#
112144
# ```ruby
113145
# p = [ Concurrent::Promise.execute{ Thread.pass; raise StandardError } ]
@@ -121,11 +153,15 @@ module Concurrent
121153
# c2.state #=> :rejected
122154
# ```
123155
#
124-
# Once a promise is rejected it will continue to accept children that will receive immediately rejection (they will be executed asynchronously).
156+
# Once a promise is rejected it will continue to accept children that will receive immediately rejection
157+
# (they will be executed asynchronously).
125158
#
126159
# #### Aliases
127160
#
128-
# The `then` method is the most generic alias: it accepts a block to be executed upon parent fulfillment and a callable to be executed upon parent rejection. At least one of them should be passed. The default block is `{ |result| result }` that fulfills the child with the parent value. The default callable is `{ |reason| raise reason }` that rejects the child with the parent reason.
161+
# The `then` method is the most generic alias: it accepts a block to be executed upon parent fulfillment
162+
# and a callable to be executed upon parent rejection. At least one of them should be passed. The default
163+
# block is `{ |result| result }` that fulfills the child with the parent value. The default callable is
164+
# `{ |reason| raise reason }` that rejects the child with the parent reason.
129165
#
130166
# - `on_success { |result| ... }` is the same as `then {|result| ... }`
131167
# - `rescue { |reason| ... }` is the same as `then(Proc.new { |reason| ... } )`
@@ -292,13 +328,11 @@ def zip(*others)
292328
self.class.zip(self, *others)
293329
end
294330

295-
# Aggregate a collection of zero or more promises under a composite promise,
296-
# execute the aggregated promises and collect them into a standard Ruby array,
297-
# call the given Ruby `Ennnumerable` predicate (such as `any?`, `all?`, `none?`,
298-
# or `one?`) on the collection checking for the success or failure of each,
299-
# then executing the composite's `#then` handlers if the predicate returns
300-
# `true` or executing the composite's `#rescue` handlers if the predicate
301-
# returns false.
331+
# Aggregates a collection of promises and executes the `then` condition
332+
# if all aggregated promises succeed. Executes the `rescue` handler with
333+
# a `Concurrent::PromiseExecutionError` if any of the aggregated promises
334+
# fail. Upon execution will execute any of the aggregate promises that
335+
# were not already executed.
302336
#
303337
# @!macro [attach] promise_self_aggregate
304338
#
@@ -314,28 +348,7 @@ def zip(*others)
314348
# @param [Array] promises Zero or more promises to aggregate
315349
# @return [Promise] an unscheduled (not executed) promise that aggregates
316350
# the promises given as arguments
317-
def self.aggregate(method, *promises)
318-
composite = Promise.new do
319-
completed = promises.collect do |promise|
320-
promise.execute if promise.unscheduled?
321-
promise.wait
322-
promise
323-
end
324-
unless completed.empty? || completed.send(method){|promise| promise.fulfilled? }
325-
raise PromiseExecutionError
326-
end
327-
end
328-
composite
329-
end
330-
331-
# Aggregates a collection of promises and executes the `then` condition
332-
# if all aggregated promises succeed. Executes the `rescue` handler with
333-
# a `Concurrent::PromiseExecutionError` if any of the aggregated promises
334-
# fail. Upon execution will execute any of the aggregate promises that
335-
# were not already executed.
336-
#
337-
# @!macro promise_self_aggregate
338-
def self.all(*promises)
351+
def self.all?(*promises)
339352
aggregate(:all?, *promises)
340353
end
341354

@@ -346,7 +359,7 @@ def self.all(*promises)
346359
# were not already executed.
347360
#
348361
# @!macro promise_self_aggregate
349-
def self.any(*promises)
362+
def self.any?(*promises)
350363
aggregate(:any?, *promises)
351364
end
352365

@@ -357,7 +370,7 @@ def self.any(*promises)
357370
# were not already executed.
358371
#
359372
# @!macro promise_self_aggregate
360-
def self.none(*promises)
373+
def self.none?(*promises)
361374
aggregate(:none?, *promises)
362375
end
363376

@@ -368,12 +381,35 @@ def self.none(*promises)
368381
# the aggregate promises that were not already executed.
369382
#
370383
# @!macro promise_self_aggregate
371-
def self.one(*promises)
384+
def self.one?(*promises)
372385
aggregate(:one?, *promises)
373386
end
374387

375388
protected
376389

390+
# Aggregate a collection of zero or more promises under a composite promise,
391+
# execute the aggregated promises and collect them into a standard Ruby array,
392+
# call the given Ruby `Ennnumerable` predicate (such as `any?`, `all?`, `none?`,
393+
# or `one?`) on the collection checking for the success or failure of each,
394+
# then executing the composite's `#then` handlers if the predicate returns
395+
# `true` or executing the composite's `#rescue` handlers if the predicate
396+
# returns false.
397+
#
398+
# @!macro promise_self_aggregate
399+
def self.aggregate(method, *promises)
400+
composite = Promise.new do
401+
completed = promises.collect do |promise|
402+
promise.execute if promise.unscheduled?
403+
promise.wait
404+
promise
405+
end
406+
unless completed.empty? || completed.send(method){|promise| promise.fulfilled? }
407+
raise PromiseExecutionError
408+
end
409+
end
410+
composite
411+
end
412+
377413
def set_pending
378414
mutex.synchronize do
379415
@state = :pending

0 commit comments

Comments
 (0)