class Promise

Constants

BrokenError
Error
VERSION

Attributes

reason[R]
source[RW]
state[R]
value[R]

Public Class Methods

all(enumerable) click to toggle source
# File lib/promise.rb, line 23
def self.all(enumerable)
  Group.new(new, enumerable).promise
end
map_value(obj) { |value| ... } click to toggle source
# File lib/promise.rb, line 27
def self.map_value(obj)
  if obj.is_a?(Promise)
    obj.then { |value| yield value }
  else
    yield obj
  end
end
new() click to toggle source
# File lib/promise.rb, line 39
def initialize
  @state = :pending
end
resolve(obj = nil) click to toggle source
# File lib/promise.rb, line 18
def self.resolve(obj = nil)
  return obj if obj.is_a?(self)
  new.tap { |promise| promise.fulfill(obj) }
end
sync(obj) click to toggle source
# File lib/promise.rb, line 35
def self.sync(obj)
  obj.is_a?(Promise) ? obj.sync : obj
end

Public Instance Methods

catch(&block)
Alias for: rescue
fulfill(value = nil) click to toggle source
# File lib/promise.rb, line 86
def fulfill(value = nil)
  return self unless pending?

  if value.is_a?(Promise)
    case value.state
    when :fulfilled
      fulfill(value.value)
    when :rejected
      reject(value.reason)
    else
      @source = value
      value.subscribe(self, nil, nil)
    end
  else
    @source = nil

    @state = :fulfilled
    @value = value

    notify_fulfillment if defined?(@observers)
  end

  self
end
fulfilled?() click to toggle source
# File lib/promise.rb, line 47
def fulfilled?
  state.equal?(:fulfilled)
end
pending?() click to toggle source
# File lib/promise.rb, line 43
def pending?
  state.equal?(:pending)
end
reject(reason = nil) click to toggle source
# File lib/promise.rb, line 111
def reject(reason = nil)
  return self unless pending?

  @source = nil
  @state = :rejected
  @reason = reason_coercion(reason || Error)

  notify_rejection if defined?(@observers)

  self
end
rejected?() click to toggle source
# File lib/promise.rb, line 51
def rejected?
  state.equal?(:rejected)
end
rescue(&block) click to toggle source
# File lib/promise.rb, line 72
def rescue(&block)
  self.then(nil, block)
end
Also aliased as: catch
subscribe(observer, on_fulfill_arg, on_reject_arg) click to toggle source

Subscribe the given `observer` for status changes of a `Promise`.

The observer will be notified about state changes of the promise by calls to its `#promise_fulfilled` or `#promise_rejected` methods.

These methods will be called with two arguments, the first being the observed `Promise`, the second being the `on_fulfill_arg` or `on_reject_arg` given to `#subscribe`.

@param [Promise::Observer] observer @param [Object] on_fulfill_arg @param [Object] on_reject_arg

# File lib/promise.rb, line 145
def subscribe(observer, on_fulfill_arg, on_reject_arg)
  raise Error, 'Non-pending promises can not be observed' unless pending?

  unless observer.is_a?(Observer)
    raise ArgumentError, 'Expected `observer` to be a `Promise::Observer`'
  end

  @observers ||= []
  @observers.push(observer, on_fulfill_arg, on_reject_arg)
end
sync() click to toggle source
# File lib/promise.rb, line 77
def sync
  if pending?
    wait
    raise BrokenError if pending?
  end
  raise reason if rejected?
  value
end
then(on_fulfill = nil, on_reject = nil, &block) click to toggle source
# File lib/promise.rb, line 55
def then(on_fulfill = nil, on_reject = nil, &block)
  on_fulfill ||= block
  next_promise = self.class.new

  case state
  when :fulfilled
    defer { next_promise.promise_fulfilled(value, on_fulfill) }
  when :rejected
    defer { next_promise.promise_rejected(reason, on_reject) }
  else
    next_promise.source = self
    subscribe(next_promise, on_fulfill, on_reject)
  end

  next_promise
end
wait() click to toggle source

Override to support sync on a promise without a source or to wait for deferred callbacks on the source

# File lib/promise.rb, line 125
def wait
  while source
    saved_source = source
    saved_source.wait
    break if saved_source.equal?(source)
  end
end

Protected Instance Methods

defer() { || ... } click to toggle source

Override to defer calling the callback for Promises/A+ spec compliance

# File lib/promise.rb, line 159
def defer
  yield
end
promise_fulfilled(value, on_fulfill) click to toggle source
# File lib/promise.rb, line 163
def promise_fulfilled(value, on_fulfill)
  if on_fulfill
    settle_from_handler(value, &on_fulfill)
  else
    fulfill(value)
  end
end
promise_rejected(reason, on_reject) click to toggle source
# File lib/promise.rb, line 171
def promise_rejected(reason, on_reject)
  if on_reject
    settle_from_handler(reason, &on_reject)
  else
    reject(reason)
  end
end

Private Instance Methods

notify_fulfillment() click to toggle source
# File lib/promise.rb, line 191
def notify_fulfillment
  defer do
    @observers.each_slice(3) do |observer, on_fulfill_arg|
      observer.promise_fulfilled(value, on_fulfill_arg)
    end

    @observers = nil
  end
end
notify_rejection() click to toggle source
# File lib/promise.rb, line 201
def notify_rejection
  defer do
    @observers.each_slice(3) do |observer, _on_fulfill_arg, on_reject_arg|
      observer.promise_rejected(reason, on_reject_arg)
    end

    @observers = nil
  end
end
reason_coercion(reason) click to toggle source
# File lib/promise.rb, line 181
def reason_coercion(reason)
  case reason
  when Exception
    reason.set_backtrace(caller) unless reason.backtrace
  when Class
    reason = reason_coercion(reason.new) if reason <= Exception
  end
  reason
end
settle_from_handler(value) { |value| ... } click to toggle source
# File lib/promise.rb, line 211
def settle_from_handler(value)
  fulfill(yield(value))
rescue => ex
  reject(ex)
end