Class: Promise

Inherits:
Object
  • Object
show all
Defined in:
lib/promise.rb

Overview

A delayed-execution promise. Promises are only executed once.

Examples:

x = promise { factorial 20 }
y = promise { fibonacci 10**6 }
a = x + 1     # => factorial 20 + 1 after factorial calculates
result = promise { a += y }
abort ""      # whew, we never needed to calculate y
y = 5
x = promise { y = y + 5 }
x + 5     # => 15
x + 5     # => 15

Constant Summary collapse

NOT_SET =
::Object.new.freeze

Instance Method Summary collapse

Constructor Details

#initialize(block) ⇒ Promise

Create a new promise

Examples:

Lazily evaluate a database call

result = promise { @db.query("SELECT * FROM TABLE") }

Parameters:

  • block (Proc)

See Also:



28
29
30
31
32
33
34
35
36
# File 'lib/promise.rb', line 28

def initialize(block)
  if block.arity > 0
    raise ArgumentError, "Cannot store a promise that requires an argument"
  end
  @block = block
  @mutex = ::Mutex.new
  @result = NOT_SET
  @error  = NOT_SET
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object



66
67
68
69
# File 'lib/promise.rb', line 66

def method_missing(method, *args, &block)
  __force__
  @result.send(method, *args, &block)
end

Instance Method Details

#__force__Any Also known as: force

Force the evaluation of this promise immediately

Returns:

  • (Any)


42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/promise.rb', line 42

def __force__
  @mutex.synchronize do
    if @result == NOT_SET && @error == NOT_SET
      begin
        @result = @block.call
      rescue ::Exception => e
        @error = e
      end
    end
  end if @result == NOT_SET && @error == NOT_SET
  # BasicObject won't send raise to Kernel
  @error.equal?(NOT_SET) ? @result : (::Kernel.raise @error)
end

#respond_to?(method) ⇒ true, false

Does this promise support the given method?

Parameters:

  • (Symbol)

Returns:

  • (true, false)


62
63
64
# File 'lib/promise.rb', line 62

def respond_to?(method)
  (method == :force) || (method == :__force__) || (__force__.respond_to?(method))
end