promise 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README +21 -19
  2. data/VERSION +1 -1
  3. data/lib/future.rb +25 -8
  4. data/lib/promise.rb +42 -12
  5. metadata +10 -10
data/README CHANGED
@@ -1,26 +1,27 @@
1
1
  # Promising Future
2
- A glimpse of a promising future in which ruby supports delayed execution
2
+ A glimpse of a promising future in which Ruby supports lazy evaluation.
3
3
 
4
4
  ## Overview
5
+ [Promises and futures][] both transparently defer the execution of a block.
6
+ Promises evaluate the given block if and when its result is first needed.
7
+ Futures evaluate the given block optimistically in another thread.
5
8
 
6
9
  require 'promise'
7
- require 'future' # you can just require future if using both
8
-
10
+ require 'future' # you can just require 'future' if using both
11
+
9
12
  x = promise { 1 + 2 }
10
- y = future { sleep 10; 5 + 5 }
11
-
12
- puts x # => 3
13
- # ... do work for 5 seconds
14
- puts y # => 10, after blocking 5 seconds
15
-
16
- Promises and futures both transparantly delay the execution of a block.
17
- Futures run the evaluation of the block optimistically in another thread.
13
+ y = future { sleep 10 && 6 * 7 }
14
+
15
+ puts x #=> 3
16
+ sleep 5 # ... do work for 5 seconds ...
17
+ puts y #=> 42, after blocking 5 seconds
18
18
 
19
- Note that this is pretty useless in irb, which will evaluate everything
20
- as part of its read-eval-print loop.
19
+ Note that this is pretty useless in Ruby's interactive shell `irb`, as it
20
+ will eagerly evaluate everything as part of its read-eval-print loop,
21
+ forcing promises and futures to yield their results.
21
22
 
22
- Yardocs are available at <http://promise.rubyforge.org/>. Tested under MRI
23
- 1.8 and JRuby.
23
+ The library has been tested with Ruby 1.8.7, 1.9.1 and JRuby 1.5.0.
24
+ YARD documentation is available at <http://promise.rubyforge.org/>
24
25
 
25
26
  ## Classes
26
27
 
@@ -28,17 +29,18 @@ Yardocs are available at <http://promise.rubyforge.org/>. Tested under MRI
28
29
  * {Future}
29
30
 
30
31
  ## Installation
32
+ The library is distributed via [RubyGems](http://rubygems.org/):
31
33
 
32
- Promising future is distributed via gemcutter under the name 'promise'.
33
-
34
- gem install promise
34
+ $ gem install promise
35
35
 
36
36
  ## Source
37
37
  The source is available at <http://github.com/bhuga/promising-future>
38
38
 
39
39
  ## Author
40
- Ben Lavender (http://github.com/bhuga)
40
+ [Ben Lavender](http://github.com/bhuga)
41
41
 
42
42
  ## Unlicense
43
43
  Promising Future is free and unencumbered public domain software. For more
44
44
  information, see <http://unlicense.org/> or the accompanying UNLICENSE file.
45
+
46
+ [Promises and futures]: http://en.wikipedia.org/wiki/Futures_and_promises
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
@@ -6,13 +6,15 @@ require 'promise'
6
6
  # x = future { sleep 5; 1 + 2 }
7
7
  # # do stuff...
8
8
  # y = x * 2 # => 6. blocks unless 5 seconds has passed.
9
- #
9
+ #
10
10
  class Future < defined?(BasicObject) ? BasicObject : Object
11
11
 
12
- instance_methods.each { |m| undef_method m unless m =~ /__|object_id/ } unless defined?(BasicObject)
13
-
12
+ instance_methods.each { |m| undef_method m unless m =~ /__/ } unless defined?(BasicObject)
13
+
14
14
  ##
15
- # @param [Proc] block
15
+ # Create a new future
16
+ #
17
+ # @yield [] The block to evaluate optimistically
16
18
  # @return [Future]
17
19
  def initialize(block)
18
20
  @promise = promise &block
@@ -23,15 +25,26 @@ class Future < defined?(BasicObject) ? BasicObject : Object
23
25
 
24
26
  ##
25
27
  # The value of the future's evaluation. Blocks until result available.
28
+ #
26
29
  # @return [Any]
27
- def force
30
+ def __force__
28
31
  @thread.join
29
32
  @promise
30
33
  end
34
+ alias_method :force, :__force__
35
+
36
+ ##
37
+ # Does this promise support the given method?
38
+ #
39
+ # @param [Symbol]
40
+ # @return [true, false]
41
+ def respond_to?(method)
42
+ (method == :force) || (method == :__force__) || (__force__.respond_to?(method))
43
+ end
31
44
 
32
45
  # @private
33
46
  def method_missing(method, *args, &block)
34
- @promise.send(method, *args, &block)
47
+ @promise.send(method, *args, &block)
35
48
  end
36
49
 
37
50
 
@@ -40,9 +53,13 @@ end
40
53
 
41
54
  module Kernel
42
55
 
43
- # Create a new future
44
- # @example
56
+ # Create a new future
57
+ #
58
+ # @example Evaluate an operation in another thread
45
59
  # x = future { 3 + 3 }
60
+ # @return [Future]
61
+ # @yield [] A block to be optimistically evaluated in another thread
62
+ # @yieldreturn [Any] The return value of the block will be the evaluated value of the future.
46
63
  def future(&block)
47
64
  Future.new(block)
48
65
  end
@@ -11,43 +11,73 @@
11
11
  # x = promise { y = y + 5 }
12
12
  # x + 5 # => 15
13
13
  # x + 5 # => 15
14
- class Promise < defined?(BasicObject) ? BasicObject : Object
14
+ class Promise < defined?(BasicObject) ? BasicObject : ::Object
15
15
 
16
- instance_methods.each { |m| undef_method m unless m =~ /__|object_id/ } unless defined?(BasicObject)
16
+ instance_methods.each { |m| undef_method m unless m.to_s =~ /__/ }
17
17
 
18
- # Returns a new promise
18
+ NOT_SET = ::Object.new.freeze
19
+
20
+ ##
21
+ # Create a new promise
22
+ #
23
+ # @example Lazily evaluate a database call
24
+ # result = promise { @db.query("SELECT * FROM TABLE") }
19
25
  # @param [Proc] block
20
26
  # @return [Promise]
27
+ # @see Kernel#promise
21
28
  def initialize(block)
22
29
  if block.arity > 0
23
30
  raise ArgumentError, "Cannot store a promise that requires an argument"
24
31
  end
25
32
  @block = block
26
33
  @mutex = ::Mutex.new
34
+ @result = NOT_SET
35
+ @error = NOT_SET
27
36
  end
28
37
 
38
+ ##
29
39
  # Force the evaluation of this promise immediately
40
+ #
30
41
  # @return [Any]
31
- def force
32
- @mutex.synchronize do
33
- unless @result
34
- @result = @block.call
42
+ def __force__
43
+ @mutex.synchronize do
44
+ if @result == NOT_SET && @error == NOT_SET
45
+ begin
46
+ @result = @block.call
47
+ rescue ::Exception => e
48
+ @error = e
49
+ end
35
50
  end
36
- end
37
- @result
51
+ end if @result == NOT_SET && @error == NOT_SET
52
+ # BasicObject won't send raise to Kernel
53
+ @error.equal?(NOT_SET) ? @result : (::Kernel.raise @error)
54
+ end
55
+ alias_method :force, :__force__
56
+
57
+ ##
58
+ # Does this promise support the given method?
59
+ #
60
+ # @param [Symbol]
61
+ # @return [true, false]
62
+ def respond_to?(method)
63
+ (method == :force) || (method == :__force__) || (__force__.respond_to?(method))
38
64
  end
39
65
 
40
66
  def method_missing(method, *args, &block)
41
- force unless @result
67
+ __force__
42
68
  @result.send(method, *args, &block)
43
69
  end
44
70
  end
45
71
 
46
72
  module Kernel
47
-
73
+
48
74
  # Create a new promise
49
- # @example
75
+ #
76
+ # @example Lazily evaluate an arithmetic operation
50
77
  # x = promise { 3 + 3 }
78
+ # @return [Promise]
79
+ # @yield [] A block to be lazily evaluated
80
+ # @yieldreturn [Any] The return value of the block will be the lazily evaluated value of the promise.
51
81
  def promise(&block)
52
82
  Promise.new(block)
53
83
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 1
9
- version: 0.1.1
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ben Lavender
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-04 00:00:00 +02:00
17
+ date: 2010-06-22 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -26,9 +26,9 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  segments:
28
28
  - 1
29
- - 2
30
- - 9
31
- version: 1.2.9
29
+ - 3
30
+ - 0
31
+ version: 1.3.0
32
32
  type: :development
33
33
  version_requirements: *id001
34
34
  - !ruby/object:Gem::Dependency
@@ -41,11 +41,11 @@ dependencies:
41
41
  segments:
42
42
  - 0
43
43
  - 5
44
- - 2
45
- version: 0.5.2
44
+ - 6
45
+ version: 0.5.6
46
46
  type: :development
47
47
  version_requirements: *id002
48
- description: " A glimpse into a promising future, in which ruby supports delayed execution.\n Provides 'promise' and 'future' functions.\n"
48
+ description: " A glimpse of a promising future in which Ruby supports delayed execution.\n Provides global 'promise' and 'future' methods.\n"
49
49
  email: blavender@gmail.com
50
50
  executables: []
51
51