Last active
August 16, 2017 10:26
-
-
Save Narnach/33661 to your computer and use it in GitHub Desktop.
First naive implementation of futures in Ruby
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
# Simple Future implementation, also known as a Promise in Javascript land. | |
# Based off an old gist ( https://gist.github.com/Narnach/33661 ) and modernized for Ruby 2. | |
# | |
# Wrap a block transparently in a Thread, and redirect any method calls to the `value` of that Thread, aka the return value of a Thread. | |
# This allows you to create code that runs async but becomes blocking when you try to interact with the result of it. | |
# | |
# future = Future.wrap { 1 + 2 } | |
# future + 3 # => 6 | |
# | |
# Inherit from BasicObject to not get all the usual cruft and allow _all_ method calls to be proxy'd to the value. | |
class Future < BasicObject | |
def initialize(thread) | |
@thread = thread | |
end | |
def self.wrap(&block) | |
new(::Thread.new(&block)) | |
end | |
# Allow comparison with the thread value | |
def ==(other) | |
@thread.value == other | |
end | |
# Allows `respond_to?` to work for method_missing implemented methods. Because all methods are implemented via method_missing, this is rather useful. | |
def respond_to_missing?(method, include_all=false) | |
@thread.value.respond_to?(method, include_all) | |
end | |
# Dispatch all method calls to the value of the thread. | |
def method_missing(*args, &block) | |
@thread.value.public_send(*args, &block) | |
end | |
end |
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
describe Future do | |
it 'should return what the block returns' do | |
val = Future.wrap { 1 + 2 } | |
val.should == 3 | |
end | |
it 'should allow transparent interaction with the return value' do | |
val = Future.wrap { sleep 0.01; 1 + 2 } | |
(val + 3).should == 6 | |
end | |
end |
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
# The snippet that started futures in Ruby | |
# Written by Wes Oldenbeuving, Erik Terpstra and Remco van 't Veer | |
# Created at the first meeting of ACK (for lack of a better name), | |
# the Amsterdam Coders Kollective. | |
def future(&block) | |
t = Thread.new(&block) | |
class << t | |
(instance_methods - %w[value __send__ __id__]).each do |meth| | |
eval("undef #{meth}") | |
end | |
def method_missing(*args, &block) | |
value.send(*args,&block) | |
end | |
end | |
t | |
end | |
f = future do | |
sleep 1 | |
123 | |
end | |
puts "present" | |
puts f * 5 | |
puts "future" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment