class Concurrent::Promises::Future

Represents a value which will become available in future. May reject with a reason instead, e.g. when the tasks raises an exception.

Public Instance Methods

&(other)
Alias for: zip
any(event_or_future) click to toggle source

Creates a new event which will be resolved when the first of receiver, `event_or_future` resolves. Returning future will have value nil if event_or_future is event and resolves first.

@return [Future]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1074
def any(event_or_future)
  AnyResolvedFuturePromise.new_blocked_by2(self, event_or_future, @DefaultExecutor).future
end
Also aliased as: |
apply(args, block) click to toggle source

@!visibility private

# File lib/concurrent-ruby/concurrent/promises.rb, line 1204
def apply(args, block)
  internal_state.apply args, block
end
delay() click to toggle source

Creates new future dependent on receiver which will not evaluate until touched, see {#touch}. In other words, it inserts delay into the chain of Futures making rest of it lazy evaluated.

@return [Future]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1084
def delay
  event = DelayPromise.new(@DefaultExecutor).event
  ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future
end
exception(*args) click to toggle source

Allows rejected Future to be risen with `raise` method. If the reason is not an exception `Runtime.new(reason)` is returned.

@example

raise Promises.rejected_future(StandardError.new("boom"))
raise Promises.rejected_future("or just boom")

@raise [Concurrent::Error] when raising not rejected future @return [Exception]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1002
def exception(*args)
  raise Concurrent::Error, 'it is not rejected' unless rejected?
  raise ArgumentError unless args.size <= 1
  reason = Array(internal_state.reason).flatten.compact
  if reason.size > 1
    ex = Concurrent::MultipleErrors.new reason
    ex.set_backtrace(caller)
    ex
  else
    ex = if reason[0].respond_to? :exception
           reason[0].exception(*args)
         else
           RuntimeError.new(reason[0]).exception(*args)
         end
    ex.set_backtrace Array(ex.backtrace) + caller
    ex
  end
end
flat(level = 1)
Alias for: flat_future
flat_event() click to toggle source

Creates new event which will be resolved when the returned event by receiver is. Be careful if the receiver rejects it will just resolve since Event does not hold reason.

@return [Event]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1119
def flat_event
  FlatEventPromise.new_blocked_by1(self, @DefaultExecutor).event
end
flat_future(level = 1) click to toggle source

Creates new future which will have result of the future returned by receiver. If receiver rejects it will have its rejection.

@param [Integer] level how many levels of futures should flatten @return [Future]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1109
def flat_future(level = 1)
  FlatFuturePromise.new_blocked_by1(self, level, @DefaultExecutor).future
end
Also aliased as: flat
fulfilled?() click to toggle source

Is it in fulfilled state? @return [Boolean]

# File lib/concurrent-ruby/concurrent/promises.rb, line 910
def fulfilled?
  state = internal_state
  state.resolved? && state.fulfilled?
end
inspect()
Alias for: to_s
on_fulfillment(*args, &callback) click to toggle source

@!macro promises.shortcut.using @return [self]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1125
def on_fulfillment(*args, &callback)
  on_fulfillment_using @DefaultExecutor, *args, &callback
end
on_fulfillment!(*args, &callback) click to toggle source

Stores the callback to be executed synchronously on resolving thread after it is fulfilled. Does nothing on rejection.

@!macro promises.param.args @!macro promise.param.callback @return [self] @yield [value, *args] to the callback.

# File lib/concurrent-ruby/concurrent/promises.rb, line 1136
def on_fulfillment!(*args, &callback)
  add_callback :callback_on_fulfillment, args, callback
end
on_fulfillment_using(executor, *args, &callback) click to toggle source

Stores the callback to be executed asynchronously on executor after it is fulfilled. Does nothing on rejection.

@!macro promises.param.executor @!macro promises.param.args @!macro promise.param.callback @return [self] @yield [value, *args] to the callback.

# File lib/concurrent-ruby/concurrent/promises.rb, line 1148
def on_fulfillment_using(executor, *args, &callback)
  add_callback :async_callback_on_fulfillment, executor, args, callback
end
on_rejection(*args, &callback) click to toggle source

@!macro promises.shortcut.using @return [self]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1154
def on_rejection(*args, &callback)
  on_rejection_using @DefaultExecutor, *args, &callback
end
on_rejection!(*args, &callback) click to toggle source

Stores the callback to be executed synchronously on resolving thread after it is rejected. Does nothing on fulfillment.

@!macro promises.param.args @!macro promise.param.callback @return [self] @yield [reason, *args] to the callback.

# File lib/concurrent-ruby/concurrent/promises.rb, line 1165
def on_rejection!(*args, &callback)
  add_callback :callback_on_rejection, args, callback
end
on_rejection_using(executor, *args, &callback) click to toggle source

Stores the callback to be executed asynchronously on executor after it is rejected. Does nothing on fulfillment.

@!macro promises.param.executor @!macro promises.param.args @!macro promise.param.callback @return [self] @yield [reason, *args] to the callback.

# File lib/concurrent-ruby/concurrent/promises.rb, line 1177
def on_rejection_using(executor, *args, &callback)
  add_callback :async_callback_on_rejection, executor, args, callback
end
reason(timeout = nil, timeout_value = nil) click to toggle source

Returns reason of future's rejection. @!macro promises.touches

@!macro promises.warn.blocks @!macro promises.warn.nil @!macro promises.param.timeout @!macro promises.param.timeout_value @return [Object, timeout_value] the reason, or timeout_value on timeout, or nil on fulfillment.

# File lib/concurrent-ruby/concurrent/promises.rb, line 955
def reason(timeout = nil, timeout_value = nil)
  if wait_until_resolved timeout
    internal_state.reason
  else
    timeout_value
  end
end
rejected?() click to toggle source

Is it in rejected state? @return [Boolean]

# File lib/concurrent-ruby/concurrent/promises.rb, line 917
def rejected?
  state = internal_state
  state.resolved? && !state.fulfilled?
end
rescue(*args, &task) click to toggle source

@!macro promises.shortcut.on @return [Future]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1041
def rescue(*args, &task)
  rescue_on @DefaultExecutor, *args, &task
end
rescue_on(executor, *args, &task) click to toggle source

Chains the task to be executed asynchronously on executor after it rejects. Does not run the task if it fulfills. It will resolve though, triggering any dependent futures.

@!macro promises.param.executor @!macro promises.param.args @!macro promise.param.task-future @return [Future] @yield [reason, *args] to the task.

# File lib/concurrent-ruby/concurrent/promises.rb, line 1053
def rescue_on(executor, *args, &task)
  RescuePromise.new_blocked_by1(self, @DefaultExecutor, executor, args, &task).future
end
result(timeout = nil) click to toggle source

Returns triplet fulfilled?, value, reason. @!macro promises.touches

@!macro promises.warn.blocks @!macro promises.param.timeout @return [Array(Boolean, Object, Object), nil] triplet of fulfilled?, value, reason, or nil

on timeout.
# File lib/concurrent-ruby/concurrent/promises.rb, line 970
def result(timeout = nil)
  internal_state.result if wait_until_resolved timeout
end
run(run_test = method(:run_test)) click to toggle source

Allows to use futures as green threads. The receiver has to evaluate to a future which represents what should be done next. It basically flattens indefinitely until non Future values is returned which becomes result of the returned future. Any encountered exception will become reason of the returned future.

@return [Future] @param [#call(value)] run_test

an object which when called returns either Future to keep running with
or nil, then the run completes with the value.
The run_test can be used to extract the Future from deeper structure,
or to distinguish Future which is a resulting value from a future
which is suppose to continue running.

@example

body = lambda do |v|
  v += 1
  v < 5 ? Promises.future(v, &body) : v
end
Promises.future(0, &body).run.value! # => 5
# File lib/concurrent-ruby/concurrent/promises.rb, line 1199
def run(run_test = method(:run_test))
  RunFuturePromise.new_blocked_by1(self, @DefaultExecutor, run_test).future
end
schedule(intended_time) click to toggle source

@!macro promise.method.schedule @return [Future]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1091
def schedule(intended_time)
  chain do
    event = ScheduledPromise.new(@DefaultExecutor, intended_time).event
    ZipFutureEventPromise.new_blocked_by2(self, event, @DefaultExecutor).future
  end.flat
end
then(*args, &task) click to toggle source

@!macro promises.shortcut.on @return [Future]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1023
def then(*args, &task)
  then_on @DefaultExecutor, *args, &task
end
then_on(executor, *args, &task) click to toggle source

Chains the task to be executed asynchronously on executor after it fulfills. Does not run the task if it rejects. It will resolve though, triggering any dependent futures.

@!macro promises.param.executor @!macro promises.param.args @!macro promise.param.task-future @return [Future] @yield [value, *args] to the task.

# File lib/concurrent-ruby/concurrent/promises.rb, line 1035
def then_on(executor, *args, &task)
  ThenPromise.new_blocked_by1(self, @DefaultExecutor, executor, args, &task).future
end
to_event() click to toggle source

Converts future to event which is resolved when future is resolved by fulfillment or rejection.

@return [Event]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1211
def to_event
  event = Promises.resolvable_event
ensure
  chain_resolvable(event)
end
to_future() click to toggle source

Returns self, since this is a future @return [Future]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1219
def to_future
  self
end
to_s() click to toggle source

@return [String] Short string representation.

# File lib/concurrent-ruby/concurrent/promises.rb, line 1224
def to_s
  if resolved?
    format '%s with %s>', super[0..-2], (fulfilled? ? value : reason).inspect
  else
    super
  end
end
Also aliased as: inspect
value(timeout = nil, timeout_value = nil) click to toggle source

@!macro promises.method.value

Return value of the future.
@!macro promises.touches

@!macro promises.warn.blocks
@!macro promises.warn.nil
@!macro promises.param.timeout
@!macro promises.param.timeout_value
  @param [Object] timeout_value a value returned by the method when it times out

@return [Object, nil, timeout_value] the value of the Future when fulfilled,

timeout_value on timeout,
nil on rejection.
# File lib/concurrent-ruby/concurrent/promises.rb, line 939
def value(timeout = nil, timeout_value = nil)
  if wait_until_resolved timeout
    internal_state.value
  else
    timeout_value
  end
end
value!(timeout = nil, timeout_value = nil) click to toggle source

@!macro promises.method.value @return [Object, nil, timeout_value] the value of the Future when fulfilled,

or nil on rejection,
or timeout_value on timeout.

@raise [Exception] {#reason} on rejection

# File lib/concurrent-ruby/concurrent/promises.rb, line 986
def value!(timeout = nil, timeout_value = nil)
  if wait_until_resolved! timeout
    internal_state.value
  else
    timeout_value
  end
end
wait!(timeout = nil) click to toggle source

@!macro promises.method.wait @raise [Exception] {#reason} on rejection

# File lib/concurrent-ruby/concurrent/promises.rb, line 976
def wait!(timeout = nil)
  result = wait_until_resolved!(timeout)
  timeout ? result : self
end
with_default_executor(executor) click to toggle source

@!macro promises.method.with_default_executor @return [Future]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1100
def with_default_executor(executor)
  FutureWrapperPromise.new_blocked_by1(self, executor).future
end
zip(other) click to toggle source

@!macro promises.method.zip @return [Future]

# File lib/concurrent-ruby/concurrent/promises.rb, line 1059
def zip(other)
  if other.is_a?(Future)
    ZipFuturesPromise.new_blocked_by2(self, other, @DefaultExecutor).future
  else
    ZipFutureEventPromise.new_blocked_by2(self, other, @DefaultExecutor).future
  end
end
Also aliased as: &
|(event_or_future)
Alias for: any

Private Instance Methods

async_callback_on_fulfillment(state, executor, args, callback) click to toggle source
# File lib/concurrent-ruby/concurrent/promises.rb, line 1261
def async_callback_on_fulfillment(state, executor, args, callback)
  with_async(executor, state, args, callback) do |st, ar, cb|
    callback_on_fulfillment st, ar, cb
  end
end
async_callback_on_rejection(state, executor, args, callback) click to toggle source
# File lib/concurrent-ruby/concurrent/promises.rb, line 1267
def async_callback_on_rejection(state, executor, args, callback)
  with_async(executor, state, args, callback) do |st, ar, cb|
    callback_on_rejection st, ar, cb
  end
end
callback_on_fulfillment(state, args, callback) click to toggle source
# File lib/concurrent-ruby/concurrent/promises.rb, line 1273
def callback_on_fulfillment(state, args, callback)
  state.apply args, callback if state.fulfilled?
end
callback_on_rejection(state, args, callback) click to toggle source
# File lib/concurrent-ruby/concurrent/promises.rb, line 1277
def callback_on_rejection(state, args, callback)
  state.apply args, callback unless state.fulfilled?
end
callback_on_resolution(state, args, callback) click to toggle source
# File lib/concurrent-ruby/concurrent/promises.rb, line 1281
def callback_on_resolution(state, args, callback)
  callback.call(*state.result, *args)
end
rejected_resolution(raise_on_reassign, state) click to toggle source
# File lib/concurrent-ruby/concurrent/promises.rb, line 1240
def rejected_resolution(raise_on_reassign, state)
  if raise_on_reassign
    if internal_state == RESERVED
      raise Concurrent::MultipleAssignmentError.new(
          "Future can be resolved only once. It is already reserved.")
    else
      raise Concurrent::MultipleAssignmentError.new(
          "Future can be resolved only once. It's #{result}, trying to set #{state.result}.",
          current_result: result,
          new_result:     state.result)
    end
  end
  return false
end
run_test(v) click to toggle source
# File lib/concurrent-ruby/concurrent/promises.rb, line 1236
def run_test(v)
  v if v.is_a?(Future)
end
wait_until_resolved!(timeout = nil) click to toggle source
# File lib/concurrent-ruby/concurrent/promises.rb, line 1255
def wait_until_resolved!(timeout = nil)
  result = wait_until_resolved(timeout)
  raise self if rejected?
  result
end