Created
November 21, 2014 20:52
-
-
Save myobie/a8e0a7496df62f5a65a7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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