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