lib/promise.rb in promise-0.1.1 vs lib/promise.rb in promise-0.2.0

- old
+ new

@@ -9,46 +9,76 @@ # @example # y = 5 # x = promise { y = y + 5 } # x + 5 # => 15 # x + 5 # => 15 -class Promise < defined?(BasicObject) ? BasicObject : Object +class Promise < defined?(BasicObject) ? BasicObject : ::Object - instance_methods.each { |m| undef_method m unless m =~ /__|object_id/ } unless defined?(BasicObject) + instance_methods.each { |m| undef_method m unless m.to_s =~ /__/ } - # Returns a new promise + NOT_SET = ::Object.new.freeze + + ## + # Create a new promise + # + # @example Lazily evaluate a database call + # result = promise { @db.query("SELECT * FROM TABLE") } # @param [Proc] block # @return [Promise] + # @see Kernel#promise 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 + ## # Force the evaluation of this promise immediately + # # @return [Any] - def force - @mutex.synchronize do - unless @result - @result = @block.call + def __force__ + @mutex.synchronize do + if @result == NOT_SET && @error == NOT_SET + begin + @result = @block.call + rescue ::Exception => e + @error = e + end end - end - @result + end if @result == NOT_SET && @error == NOT_SET + # BasicObject won't send raise to Kernel + @error.equal?(NOT_SET) ? @result : (::Kernel.raise @error) end + alias_method :force, :__force__ + ## + # Does this promise support the given method? + # + # @param [Symbol] + # @return [true, false] + def respond_to?(method) + (method == :force) || (method == :__force__) || (__force__.respond_to?(method)) + end + def method_missing(method, *args, &block) - force unless @result + __force__ @result.send(method, *args, &block) end end module Kernel - + # Create a new promise - # @example + # + # @example Lazily evaluate an arithmetic operation # x = promise { 3 + 3 } + # @return [Promise] + # @yield [] A block to be lazily evaluated + # @yieldreturn [Any] The return value of the block will be the lazily evaluated value of the promise. def promise(&block) Promise.new(block) end end