Skip to content

Commit 705325e

Browse files
authored
Merge pull request #654 from davishmcclurg/davishmcclurg/promise-zip
Promise.zip execution changes
2 parents 50ed4a5 + 0559cba commit 705325e

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

lib/concurrent/promise.rb

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,24 @@ def flat_map(&block)
383383
# Builds a promise that produces the result of promises in an Array
384384
# and fails if any of them fails.
385385
#
386-
# @param [Array<Promise>] promises
386+
# @overload zip(*promises)
387+
# @param [Array<Promise>] promises
388+
#
389+
# @overload zip(*promises, opts)
390+
# @param [Array<Promise>] promises
391+
# @param [Hash] opts the configuration options
392+
# @option opts [Executor] :executor (ImmediateExecutor.new) when set use the given `Executor` instance.
393+
# @option opts [Boolean] :execute (true) execute promise before returning
387394
#
388395
# @return [Promise<Array>]
389396
def self.zip(*promises)
390-
zero = fulfill([], executor: ImmediateExecutor.new)
397+
opts = promises.last.is_a?(::Hash) ? promises.pop.dup : {}
398+
opts[:executor] ||= ImmediateExecutor.new
399+
zero = if !opts.key?(:execute) || opts.delete(:execute)
400+
fulfill([], opts)
401+
else
402+
Promise.new(opts) { [] }
403+
end
391404

392405
promises.reduce(zero) do |p1, p2|
393406
p1.flat_map do |results|
@@ -401,7 +414,14 @@ def self.zip(*promises)
401414
# Builds a promise that produces the result of self and others in an Array
402415
# and fails if any of them fails.
403416
#
404-
# @param [Array<Promise>] others
417+
# @overload zip(*promises)
418+
# @param [Array<Promise>] others
419+
#
420+
# @overload zip(*promises, opts)
421+
# @param [Array<Promise>] others
422+
# @param [Hash] opts the configuration options
423+
# @option opts [Executor] :executor (ImmediateExecutor.new) when set use the given `Executor` instance.
424+
# @option opts [Boolean] :execute (true) execute promise before returning
405425
#
406426
# @return [Promise<Array>]
407427
def zip(*others)

spec/concurrent/promise_spec.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,32 @@ def get_ivar_from_args(opts)
357357
let(:promise2) { Promise.new(executor: :immediate) { 2 } }
358358
let(:promise3) { Promise.new(executor: :immediate) { [3] } }
359359

360+
it 'executes the returned Promise by default' do
361+
composite = promise1.zip(promise2, promise3)
362+
363+
expect(composite).to be_fulfilled
364+
end
365+
366+
it 'executes the returned Promise when execute is true' do
367+
composite = promise1.zip(promise2, promise3, execute: true)
368+
369+
expect(composite).to be_fulfilled
370+
end
371+
372+
it 'does not execute the returned Promise when execute is false' do
373+
composite = promise1.zip(promise2, promise3, execute: false)
374+
375+
expect(composite).to be_unscheduled
376+
end
377+
378+
it 'allows setting executor for Promise chain' do
379+
new_executor = Concurrent::SingleThreadExecutor.new
380+
promise = promise1.zip(promise2, promise3, executor: new_executor)
381+
382+
promise = promise.instance_variable_get(:@parent) until promise.send(:root?)
383+
expect(promise.instance_variable_get(:@executor)).to be(new_executor)
384+
end
385+
360386
it 'yields the results as an array' do
361387
composite = promise1.zip(promise2, promise3).execute.wait
362388

@@ -375,6 +401,32 @@ def get_ivar_from_args(opts)
375401
let(:promise2) { Promise.new(executor: :immediate) { 2 } }
376402
let(:promise3) { Promise.new(executor: :immediate) { [3] } }
377403

404+
it 'executes the returned Promise by default' do
405+
composite = Promise.zip(promise1, promise2, promise3)
406+
407+
expect(composite).to be_fulfilled
408+
end
409+
410+
it 'executes the returned Promise when execute is true' do
411+
composite = Promise.zip(promise1, promise2, promise3, execute: true)
412+
413+
expect(composite).to be_fulfilled
414+
end
415+
416+
it 'does not execute the returned Promise when execute is false' do
417+
composite = Promise.zip(promise1, promise2, promise3, execute: false)
418+
419+
expect(composite).to be_unscheduled
420+
end
421+
422+
it 'allows setting executor for Promise chain' do
423+
new_executor = Concurrent::SingleThreadExecutor.new
424+
promise = Promise.zip(promise1, promise2, promise3, executor: new_executor)
425+
426+
promise = promise.instance_variable_get(:@parent) until promise.send(:root?)
427+
expect(promise.instance_variable_get(:@executor)).to be(new_executor)
428+
end
429+
378430
it 'yields the results as an array' do
379431
composite = Promise.zip(promise1, promise2, promise3).execute.wait
380432

0 commit comments

Comments
 (0)