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
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
@!visibility private
# File lib/concurrent-ruby/concurrent/promises.rb, line 1204 def apply(args, block) internal_state.apply args, block end
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
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
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
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
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
@!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
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
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
@!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
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
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
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
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
@!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
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
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
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
@!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
@!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
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
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
Returns self, since this is a future @return [Future]
# File lib/concurrent-ruby/concurrent/promises.rb, line 1219 def to_future self end
@return [String] Short string representation.
Concurrent::Promises::AbstractEventFuture#to_s
# 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
@!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
@!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
@!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
@!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
@!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
Private Instance Methods
# 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
# 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
# File lib/concurrent-ruby/concurrent/promises.rb, line 1273 def callback_on_fulfillment(state, args, callback) state.apply args, callback if state.fulfilled? end
# File lib/concurrent-ruby/concurrent/promises.rb, line 1277 def callback_on_rejection(state, args, callback) state.apply args, callback unless state.fulfilled? end
# File lib/concurrent-ruby/concurrent/promises.rb, line 1281 def callback_on_resolution(state, args, callback) callback.call(*state.result, *args) end
# 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
# File lib/concurrent-ruby/concurrent/promises.rb, line 1236 def run_test(v) v if v.is_a?(Future) end
# 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