promise 0.2.0 → 0.2.1
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/AUTHORS +2 -0
- data/VERSION +1 -1
- data/lib/future.rb +29 -31
- data/lib/promise.rb +40 -35
- metadata +5 -5
data/AUTHORS
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/lib/future.rb
CHANGED
@@ -1,67 +1,65 @@
|
|
1
1
|
require 'promise'
|
2
2
|
|
3
3
|
##
|
4
|
-
# A delayed-execution result,
|
4
|
+
# A delayed-execution result, optimistically evaluated in a new thread.
|
5
|
+
#
|
5
6
|
# @example
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# x = future { sleep 5; 1 + 2 }
|
8
|
+
# # do stuff...
|
9
|
+
# y = x * 2 # => 6. blocks unless 5 seconds has passed.
|
9
10
|
#
|
10
11
|
class Future < defined?(BasicObject) ? BasicObject : Object
|
11
|
-
|
12
12
|
instance_methods.each { |m| undef_method m unless m =~ /__/ } unless defined?(BasicObject)
|
13
13
|
|
14
14
|
##
|
15
|
-
#
|
15
|
+
# Creates a new future.
|
16
16
|
#
|
17
|
-
# @yield
|
18
|
-
# @
|
19
|
-
def initialize(block)
|
20
|
-
@promise =
|
21
|
-
@thread
|
22
|
-
@promise.force
|
23
|
-
end
|
17
|
+
# @yield [] The block to evaluate optimistically.
|
18
|
+
# @see Kernel#future
|
19
|
+
def initialize(&block)
|
20
|
+
@promise = ::Promise.new(&block)
|
21
|
+
@thread = ::Thread.new { @promise.__force__ }
|
24
22
|
end
|
25
23
|
|
26
24
|
##
|
27
25
|
# The value of the future's evaluation. Blocks until result available.
|
28
26
|
#
|
29
|
-
# @return [
|
27
|
+
# @return [Object]
|
30
28
|
def __force__
|
31
|
-
@thread.join
|
29
|
+
@thread.join if @thread
|
32
30
|
@promise
|
33
31
|
end
|
34
32
|
alias_method :force, :__force__
|
35
33
|
|
36
34
|
##
|
37
|
-
# Does this
|
35
|
+
# Does this future support the given method?
|
38
36
|
#
|
39
37
|
# @param [Symbol]
|
40
|
-
# @return [
|
38
|
+
# @return [Boolean]
|
41
39
|
def respond_to?(method)
|
42
|
-
(method
|
40
|
+
:force.equal?(method) || :__force__.equal?(method) || __force__.respond_to?(method)
|
43
41
|
end
|
44
42
|
|
45
|
-
|
43
|
+
private
|
44
|
+
|
46
45
|
def method_missing(method, *args, &block)
|
47
|
-
|
46
|
+
__force__.__send__(method, *args, &block)
|
48
47
|
end
|
49
|
-
|
50
|
-
|
51
48
|
end
|
52
49
|
|
53
|
-
|
54
50
|
module Kernel
|
55
|
-
|
56
|
-
#
|
51
|
+
##
|
52
|
+
# Creates a new future.
|
57
53
|
#
|
58
54
|
# @example Evaluate an operation in another thread
|
59
|
-
#
|
60
|
-
#
|
61
|
-
# @yield
|
62
|
-
#
|
55
|
+
# x = future { 3 + 3 }
|
56
|
+
#
|
57
|
+
# @yield []
|
58
|
+
# A block to be optimistically evaluated in another thread.
|
59
|
+
# @yieldreturn [Object]
|
60
|
+
# The return value of the block will be the evaluated value of the future.
|
61
|
+
# @return [Future]
|
63
62
|
def future(&block)
|
64
|
-
Future.new(block)
|
63
|
+
Future.new(&block)
|
65
64
|
end
|
66
|
-
|
67
65
|
end
|
data/lib/promise.rb
CHANGED
@@ -1,36 +1,38 @@
|
|
1
1
|
##
|
2
2
|
# A delayed-execution promise. Promises are only executed once.
|
3
|
+
#
|
3
4
|
# @example
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
5
|
+
# x = promise { factorial 20 }
|
6
|
+
# y = promise { fibonacci 10**6 }
|
7
|
+
# a = x + 1 # => factorial 20 + 1 after factorial calculates
|
8
|
+
# result = promise { a += y }
|
9
|
+
# abort "" # whew, we never needed to calculate y
|
10
|
+
#
|
9
11
|
# @example
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
12
|
+
# y = 5
|
13
|
+
# x = promise { y = y + 5 }
|
14
|
+
# x + 5 # => 15
|
15
|
+
# x + 5 # => 15
|
16
|
+
#
|
14
17
|
class Promise < defined?(BasicObject) ? BasicObject : ::Object
|
18
|
+
NOT_SET = ::Object.new.freeze
|
15
19
|
|
16
20
|
instance_methods.each { |m| undef_method m unless m.to_s =~ /__/ }
|
17
21
|
|
18
|
-
NOT_SET = ::Object.new.freeze
|
19
|
-
|
20
22
|
##
|
21
|
-
#
|
23
|
+
# Creates a new promise.
|
22
24
|
#
|
23
25
|
# @example Lazily evaluate a database call
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# @
|
27
|
-
# @see
|
28
|
-
def initialize(block)
|
26
|
+
# result = promise { @db.query("SELECT * FROM TABLE") }
|
27
|
+
#
|
28
|
+
# @yield [] The block to evaluate lazily.
|
29
|
+
# @see Kernel#promise
|
30
|
+
def initialize(&block)
|
29
31
|
if block.arity > 0
|
30
32
|
raise ArgumentError, "Cannot store a promise that requires an argument"
|
31
33
|
end
|
32
|
-
@block
|
33
|
-
@mutex
|
34
|
+
@block = block
|
35
|
+
@mutex = ::Mutex.new
|
34
36
|
@result = NOT_SET
|
35
37
|
@error = NOT_SET
|
36
38
|
end
|
@@ -38,19 +40,19 @@ class Promise < defined?(BasicObject) ? BasicObject : ::Object
|
|
38
40
|
##
|
39
41
|
# Force the evaluation of this promise immediately
|
40
42
|
#
|
41
|
-
# @return [
|
43
|
+
# @return [Object]
|
42
44
|
def __force__
|
43
45
|
@mutex.synchronize do
|
44
|
-
if @result
|
46
|
+
if @result.equal?(NOT_SET) && @error.equal?(NOT_SET)
|
45
47
|
begin
|
46
48
|
@result = @block.call
|
47
49
|
rescue ::Exception => e
|
48
50
|
@error = e
|
49
51
|
end
|
50
52
|
end
|
51
|
-
end if @result
|
53
|
+
end if @result.equal?(NOT_SET) && @error.equal?(NOT_SET)
|
52
54
|
# BasicObject won't send raise to Kernel
|
53
|
-
@error.equal?(NOT_SET) ? @result :
|
55
|
+
@error.equal?(NOT_SET) ? @result : ::Kernel.raise(@error)
|
54
56
|
end
|
55
57
|
alias_method :force, :__force__
|
56
58
|
|
@@ -58,28 +60,31 @@ class Promise < defined?(BasicObject) ? BasicObject : ::Object
|
|
58
60
|
# Does this promise support the given method?
|
59
61
|
#
|
60
62
|
# @param [Symbol]
|
61
|
-
# @return [
|
63
|
+
# @return [Boolean]
|
62
64
|
def respond_to?(method)
|
63
|
-
(method
|
65
|
+
:force.equal?(method) || :__force__.equal?(method) || __force__.respond_to?(method)
|
64
66
|
end
|
65
67
|
|
68
|
+
private
|
69
|
+
|
66
70
|
def method_missing(method, *args, &block)
|
67
|
-
__force__
|
68
|
-
@result.send(method, *args, &block)
|
71
|
+
__force__.__send__(method, *args, &block)
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
75
|
module Kernel
|
73
|
-
|
74
|
-
#
|
76
|
+
##
|
77
|
+
# Creates a new promise.
|
75
78
|
#
|
76
79
|
# @example Lazily evaluate an arithmetic operation
|
77
|
-
#
|
78
|
-
#
|
79
|
-
# @yield
|
80
|
-
#
|
80
|
+
# x = promise { 3 + 3 }
|
81
|
+
#
|
82
|
+
# @yield []
|
83
|
+
# A block to be lazily evaluated.
|
84
|
+
# @yieldreturn [Object]
|
85
|
+
# The return value of the block will be the lazily evaluated value of the promise.
|
86
|
+
# @return [Promise]
|
81
87
|
def promise(&block)
|
82
|
-
Promise.new(block)
|
88
|
+
Promise.new(&block)
|
83
89
|
end
|
84
|
-
|
85
90
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 1
|
9
|
+
version: 0.2.1
|
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-29 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -41,8 +41,8 @@ dependencies:
|
|
41
41
|
segments:
|
42
42
|
- 0
|
43
43
|
- 5
|
44
|
-
-
|
45
|
-
version: 0.5.
|
44
|
+
- 8
|
45
|
+
version: 0.5.8
|
46
46
|
type: :development
|
47
47
|
version_requirements: *id002
|
48
48
|
description: " A glimpse of a promising future in which Ruby supports delayed execution.\n Provides global 'promise' and 'future' methods.\n"
|