Created
April 21, 2014 23:01
-
-
Save myobie/11159470 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' | |
require 'forwardable' | |
module Wunderlist | |
module SDK | |
AlreadyComplete = Class.new(StandardError) | |
class Future | |
include MonitorMixin | |
NOTHING = Object.new.freeze | |
def initialize | |
super() # you must do this first for MonitorMixin | |
@afters = [] | |
@errors = [] | |
@error = false | |
@thread = nil | |
@monitor = new_cond | |
@value = NOTHING | |
@meta = {} | |
end | |
def wait | |
!!value | |
end | |
def value? | |
!nothing? | |
end | |
def error? | |
!!@error | |
end | |
def nothing? | |
@value === NOTHING | |
end | |
def value | |
return @value if value? | |
synchronize do | |
@monitor.wait_while { nothing? } | |
end | |
@value | |
end | |
def complete!(response = nil) | |
raise(AlreadyComplete) if value? | |
synchronize do | |
@value = response | |
@monitor.broadcast | |
end | |
@afters.map { |cb| cb.call(@value) } | |
self | |
end | |
def error!(response = nil) | |
raise(AlreadyComplete) if value? | |
synchronize do | |
@error = true | |
@value = response | |
@monitor.broadcast | |
end | |
@errors.map { |cb| cb.call(@value) } | |
self | |
end | |
def self.wrap(future) | |
FutureWrapper.new(future) | |
end | |
def wrap | |
self.class.wrap(self) | |
end | |
def then(&blk) | |
synchronize do | |
@afters << blk | |
blk.call(@value) if value? && !error? | |
end | |
self | |
end | |
def error(&blk) | |
synchronize do | |
@errors << blk | |
blk.call(@value) if value? && error? | |
end | |
self | |
end | |
def [](key) | |
synchronize { @meta[key] } | |
end | |
def []=(key, value) | |
synchronize { @meta[key] = value } | |
end | |
def meta | |
synchronize { @meta } | |
end | |
end | |
class FutureWrapper | |
extend Forwardable | |
delegate [:wait, :complete?, :error?] => :@outer_future | |
def initialize(future) | |
@inner_future = future | |
@outer_future = Future.new | |
@inner_future.then do |*args| | |
@outer_future.complete! | |
end.error do |*args| | |
@outer_future.error! | |
end | |
end | |
def value | |
wait | |
@inner_future.value | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment