promise 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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