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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize { ... } ⇒ Promise

Creates a new promise.

Examples:

Lazily evaluate a database call

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

Yields:

  • The block to evaluate lazily.

See Also:



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

def initialize(&block)
  if block.arity > 0
    ::Kernel.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 (private)



95
96
97
# File 'lib/promise.rb', line 95

def method_missing(method, *args, &block)
  __force__.__send__(method, *args, &block)
end

Class Method Details

._load(obj) ⇒ Promise

Method used by Marshal to deserialize the object.

Parameters:

  • (Object)

Returns:



89
90
91
# File 'lib/promise.rb', line 89

def self._load(obj)
  ::Marshal.load(obj)
end

Instance Method Details

#__force__Object Also known as: force

Force the evaluation of this promise immediately

Returns:

  • (Object)


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

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

#_dump(limit) ⇒ Object

Method used by Marshal to serialize the object. Forces evaluation.

Parameters:

  • limit (Integer)

    – refer to Marshal doc

Returns:

  • (Object)


80
81
82
# File 'lib/promise.rb', line 80

def _dump(limit)
  ::Marshal.dump(__force__, limit)
end

#respond_to?(method, include_all = false) ⇒ Boolean

Does this promise support the given method?

Parameters:

  • (Symbol, Boolean)

Returns:

  • (Boolean)


64
65
66
67
68
69
70
71
72
73
# File 'lib/promise.rb', line 64

def respond_to?(method, include_all=false)
  # If the promised object implements marshal_dump, Marshal will use it in
  # preference to our _dump, so make sure that doesn't happen.
  return false if :marshal_dump.equal?(method)

  :_dump.equal?(method) ||  # for Marshal
    :force.equal?(method) ||
    :__force__.equal?(method) ||
    __force__.respond_to?(method, include_all)
end