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.
- data/README +21 -19
- data/VERSION +1 -1
- data/lib/future.rb +25 -8
- data/lib/promise.rb +42 -12
- metadata +10 -10
data/README
CHANGED
@@ -1,26 +1,27 @@
|
|
1
1
|
# Promising Future
|
2
|
-
A glimpse of a promising future in which
|
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
|
11
|
-
|
12
|
-
puts x
|
13
|
-
# ... do work for 5 seconds
|
14
|
-
puts y
|
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
|
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
|
-
|
23
|
-
|
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
|
-
|
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
|
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
|
+
0.2.0
|
data/lib/future.rb
CHANGED
@@ -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 =~ /__
|
13
|
-
|
12
|
+
instance_methods.each { |m| undef_method m unless m =~ /__/ } unless defined?(BasicObject)
|
13
|
+
|
14
14
|
##
|
15
|
-
#
|
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
|
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
|
-
#
|
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
|
data/lib/promise.rb
CHANGED
@@ -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 =~ /__
|
16
|
+
instance_methods.each { |m| undef_method m unless m.to_s =~ /__/ }
|
17
17
|
|
18
|
-
|
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
|
32
|
-
@mutex.synchronize do
|
33
|
-
|
34
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
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-
|
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
|
-
-
|
30
|
-
-
|
31
|
-
version: 1.
|
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
|
-
-
|
45
|
-
version: 0.5.
|
44
|
+
- 6
|
45
|
+
version: 0.5.6
|
46
46
|
type: :development
|
47
47
|
version_requirements: *id002
|
48
|
-
description: " A glimpse
|
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
|
|