Class: Lazy::Promise

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

Overview

A promise is just a magic object that springs to life when it is actually used for the first time, running the provided block and assuming the identity of the resulting object.

This impersonation isn’t perfect – a promise wrapping nil or false will still be considered true by Ruby – but it’s good enough for most purposes. If you do need to unwrap the result object for some reason (e.g. for truth testing or for simple efficiency), you may do so via Kernel.demand.

Formally, a promise is a placeholder for the result of a deferred computation.

Direct Known Subclasses

Future

Constant Summary collapse

DIVERGES =

create this once here, rather than creating a proc object for every evaluation

lambda { raise DivergenceError.new }

Instance Method Summary collapse

Constructor Details

#initialize(&computation) ⇒ Promise

:nodoc:



55
56
57
58
# File 'lib/lazy.rb', line 55

def initialize( &computation ) #:nodoc:
  @mutex = Mutex.new
  @computation = computation
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(*args, &block) ⇒ Object

:nodoc:



121
122
123
# File 'lib/lazy.rb', line 121

def method_missing( *args, &block ) #:nodoc:
  __result__.__send__( *args, &block )
end

Instance Method Details

#__result__Object

:nodoc:



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/lazy.rb', line 67

def __result__ #:nodoc:
  @mutex.synchronize do
    if @computation
      raise LazyException.new( @exception ) if @exception

      computation = @computation
      @computation = DIVERGES # trap divergence due to over-eager recursion

      begin
        @result = Lazy.demand( computation.call( self ) )
        @computation = nil
      rescue DivergenceError
        raise
      rescue Exception => exception
        # handle exceptions
        @exception = exception
        raise LazyException.new( @exception )
      end
    end

    @result
  end
end

#inspectObject

:nodoc:



91
92
93
94
95
96
97
98
99
# File 'lib/lazy.rb', line 91

def inspect #:nodoc:
  @mutex.synchronize do
    if @computation
      "#<#{ __class__ } computation=#{ @computation.inspect }>"
    else
      @result.inspect
    end
  end
end

#marshal_dumpObject



101
102
103
104
# File 'lib/lazy.rb', line 101

def marshal_dump
  __result__
  Marshal.dump( [ @exception, @result ] )
end

#marshal_load(str) ⇒ Object



106
107
108
109
110
# File 'lib/lazy.rb', line 106

def marshal_load( str )
  @mutex = Mutex.new
  ( @exception, @result ) = Marshal.load( str )
  @computation = DIVERGES if @exception
end

#respond_to?(message) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


112
113
114
115
116
117
118
119
# File 'lib/lazy.rb', line 112

def respond_to?( message ) #:nodoc:
  message = message.to_sym
  message == :__result__ or
  message == :inspect or
  message == :marshal_dump or
  message == :marshal_load or
  __result__.respond_to? message
end