Skip to content

Instantly share code, notes, and snippets.

@myobie
Created November 21, 2014 20:52
Show Gist options
  • Save myobie/a8e0a7496df62f5a65a7 to your computer and use it in GitHub Desktop.
Save myobie/a8e0a7496df62f5a65a7 to your computer and use it in GitHub Desktop.
require "monitor"
class Promise
include MonitorMixin
AlreadyComplete = Class.new(StandardError)
NOTHING = Object.new.freeze
def initialize
super()
@ons = { complete: [], exception: [] }
@state = :pending
@value = NOTHING
@exception = nil
@monitor = new_cond
if block_given?
yield(self)
end
end
def complete!(new_value, new_state = :complete)
synchronize do
fail AlreadyComplete if @state != :pending
@state = new_state
if @state == :complete
@value = new_value
@exception = nil
elsif @state == :exception
@value = nil
@exception = new_value
else
fail IllegalState
end
@monitor.broadcast
end
call_value = @state == :exception ? @exception : @value
@ons[@state].each do |cb|
cb.call(call_value)
end
@ons = nil
self
end
def pending?
synchronize { @state == :pending }
end
def value?
synchronize { not @value === NOTHING }
end
def state
synchronize { @state }
end
def value
return @value unless @value === NOTHING
synchronize do
@monitor.wait_while { @value === NOTHING }
end
@value
end
def exception?
!!exception
end
def exception
synchronize { @exception }
end
def on(state_type, promise = nil, &blk)
synchronize do
if @state == :pending
@ons[state_type].push(blk)
else
if @state == state_type
if promise
promise.complete! @value, state_type
else
blk.(@value)
end
end
end
end
self
end
def wait
value
self
end
end
def Promise(complete: nil, exception: nil, &blk)
if block_given?
Promise.new.on(:complete, &blk)
else
Promise.new do |promise|
promise.on(:complete, &complete) if complete
promise.on(:exception, &exception) if exception
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment