concurrent-ruby 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +275 -275
  3. data/lib/concurrent.rb +28 -28
  4. data/lib/concurrent/agent.rb +114 -114
  5. data/lib/concurrent/cached_thread_pool.rb +131 -129
  6. data/lib/concurrent/defer.rb +65 -65
  7. data/lib/concurrent/event.rb +60 -60
  8. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  9. data/lib/concurrent/executor.rb +96 -95
  10. data/lib/concurrent/fixed_thread_pool.rb +99 -95
  11. data/lib/concurrent/functions.rb +120 -120
  12. data/lib/concurrent/future.rb +42 -42
  13. data/lib/concurrent/global_thread_pool.rb +16 -16
  14. data/lib/concurrent/goroutine.rb +29 -29
  15. data/lib/concurrent/null_thread_pool.rb +22 -22
  16. data/lib/concurrent/obligation.rb +67 -67
  17. data/lib/concurrent/promise.rb +174 -174
  18. data/lib/concurrent/reactor.rb +166 -166
  19. data/lib/concurrent/reactor/drb_async_demux.rb +83 -83
  20. data/lib/concurrent/reactor/tcp_sync_demux.rb +131 -131
  21. data/lib/concurrent/supervisor.rb +105 -100
  22. data/lib/concurrent/thread_pool.rb +76 -76
  23. data/lib/concurrent/utilities.rb +32 -32
  24. data/lib/concurrent/version.rb +3 -3
  25. data/lib/concurrent_ruby.rb +1 -1
  26. data/md/agent.md +123 -123
  27. data/md/defer.md +174 -174
  28. data/md/event.md +32 -32
  29. data/md/executor.md +187 -187
  30. data/md/future.md +83 -83
  31. data/md/goroutine.md +52 -52
  32. data/md/obligation.md +32 -32
  33. data/md/promise.md +227 -227
  34. data/md/thread_pool.md +224 -224
  35. data/spec/concurrent/agent_spec.rb +386 -386
  36. data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
  37. data/spec/concurrent/defer_spec.rb +195 -195
  38. data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -256
  39. data/spec/concurrent/event_spec.rb +134 -134
  40. data/spec/concurrent/executor_spec.rb +200 -200
  41. data/spec/concurrent/fixed_thread_pool_spec.rb +83 -83
  42. data/spec/concurrent/functions_spec.rb +217 -217
  43. data/spec/concurrent/future_spec.rb +108 -108
  44. data/spec/concurrent/global_thread_pool_spec.rb +38 -38
  45. data/spec/concurrent/goroutine_spec.rb +67 -67
  46. data/spec/concurrent/null_thread_pool_spec.rb +57 -54
  47. data/spec/concurrent/obligation_shared.rb +132 -132
  48. data/spec/concurrent/promise_spec.rb +312 -312
  49. data/spec/concurrent/reactor/drb_async_demux_spec.rb +196 -196
  50. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +410 -410
  51. data/spec/concurrent/reactor_spec.rb +364 -364
  52. data/spec/concurrent/supervisor_spec.rb +269 -258
  53. data/spec/concurrent/thread_pool_shared.rb +204 -204
  54. data/spec/concurrent/utilities_spec.rb +74 -74
  55. data/spec/spec_helper.rb +32 -32
  56. metadata +20 -16
  57. checksums.yaml +0 -7
@@ -1,83 +1,83 @@
1
- # We're Sending You Back to the Future!
2
-
3
- Futures are inspired by [Clojure's](http://clojure.org/) [future](http://clojuredocs.org/clojure_core/clojure.core/future) keyword.
4
- A future represents a promise to complete an action at some time in the future. The action is atomic and permanent.
5
- The idea behind a future is to send an action off for asynchronous operation, do other stuff, then return and
6
- retrieve the result of the async operation at a later time. Futures run on the global thread pool (see below).
7
-
8
- Futures have three possible states: *pending*, *rejected*, and *fulfilled*. When a future is created it is set
9
- to *pending* and will remain in that state until processing is complete. A completed future is either *rejected*,
10
- indicating that an exception was thrown during processing, or *fulfilled*, indicating succedd. If a future is
11
- *fulfilled* its `value` will be updated to reflect the result of the operation. If *rejected* the `reason` will
12
- be updated with a reference to the thrown exception. The predicate methods `pending?`, `rejected`, and `fulfilled?`
13
- can be called at any time to obtain the state of the future, as can the `state` method, which returns a symbol.
14
-
15
- Retrieving the value of a future is done through the `value` (alias: `deref`) method. Obtaining the value of
16
- a future is a potentially blocking operation. When a future is *rejected* a call to `value` will return `nil`
17
- immediately. When a future is *fulfilled* a call to `value` will immediately return the current value.
18
- When a future is *pending* a call to `value` will block until the future is either *rejected* or *fulfilled*.
19
- A *timeout* value can be passed to `value` to limit how long the call will block. If `nil` the call will
20
- block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the
21
- maximum number of seconds to block.
22
-
23
- ## Examples
24
-
25
- A fulfilled example:
26
-
27
- ```ruby
28
- require 'concurrent'
29
-
30
- count = Concurrent::Future{ sleep(10); 10 }
31
- count.state #=> :pending
32
- count.pending? #=> true
33
-
34
- # do stuff...
35
-
36
- count.value(0) #=> nil (does not block)
37
-
38
- count.value #=> 10 (after blocking)
39
- count.state #=> :fulfilled
40
- count.fulfilled? #=> true
41
- deref count #=> 10
42
- ```
43
-
44
- A rejected example:
45
-
46
- ```ruby
47
- count = future{ sleep(10); raise StandardError.new("Boom!") }
48
- count.state #=> :pending
49
- pending?(count) #=> true
50
-
51
- deref(count) #=> nil (after blocking)
52
- rejected?(count) #=> true
53
- count.reason #=> #<StandardError: Boom!>
54
- ```
55
-
56
- ## Copyright
57
-
58
- *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
59
- It is free software and may be redistributed under the terms specified in the LICENSE file.
60
-
61
- ## License
62
-
63
- Released under the MIT license.
64
-
65
- http://www.opensource.org/licenses/mit-license.php
66
-
67
- > Permission is hereby granted, free of charge, to any person obtaining a copy
68
- > of this software and associated documentation files (the "Software"), to deal
69
- > in the Software without restriction, including without limitation the rights
70
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71
- > copies of the Software, and to permit persons to whom the Software is
72
- > furnished to do so, subject to the following conditions:
73
- >
74
- > The above copyright notice and this permission notice shall be included in
75
- > all copies or substantial portions of the Software.
76
- >
77
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
78
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
79
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
80
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
81
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
82
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
83
- > THE SOFTWARE.
1
+ # We're Sending You Back to the Future!
2
+
3
+ Futures are inspired by [Clojure's](http://clojure.org/) [future](http://clojuredocs.org/clojure_core/clojure.core/future) keyword.
4
+ A future represents a promise to complete an action at some time in the future. The action is atomic and permanent.
5
+ The idea behind a future is to send an action off for asynchronous operation, do other stuff, then return and
6
+ retrieve the result of the async operation at a later time. Futures run on the global thread pool (see below).
7
+
8
+ Futures have three possible states: *pending*, *rejected*, and *fulfilled*. When a future is created it is set
9
+ to *pending* and will remain in that state until processing is complete. A completed future is either *rejected*,
10
+ indicating that an exception was thrown during processing, or *fulfilled*, indicating succedd. If a future is
11
+ *fulfilled* its `value` will be updated to reflect the result of the operation. If *rejected* the `reason` will
12
+ be updated with a reference to the thrown exception. The predicate methods `pending?`, `rejected`, and `fulfilled?`
13
+ can be called at any time to obtain the state of the future, as can the `state` method, which returns a symbol.
14
+
15
+ Retrieving the value of a future is done through the `value` (alias: `deref`) method. Obtaining the value of
16
+ a future is a potentially blocking operation. When a future is *rejected* a call to `value` will return `nil`
17
+ immediately. When a future is *fulfilled* a call to `value` will immediately return the current value.
18
+ When a future is *pending* a call to `value` will block until the future is either *rejected* or *fulfilled*.
19
+ A *timeout* value can be passed to `value` to limit how long the call will block. If `nil` the call will
20
+ block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the
21
+ maximum number of seconds to block.
22
+
23
+ ## Examples
24
+
25
+ A fulfilled example:
26
+
27
+ ```ruby
28
+ require 'concurrent'
29
+
30
+ count = Concurrent::Future{ sleep(10); 10 }
31
+ count.state #=> :pending
32
+ count.pending? #=> true
33
+
34
+ # do stuff...
35
+
36
+ count.value(0) #=> nil (does not block)
37
+
38
+ count.value #=> 10 (after blocking)
39
+ count.state #=> :fulfilled
40
+ count.fulfilled? #=> true
41
+ deref count #=> 10
42
+ ```
43
+
44
+ A rejected example:
45
+
46
+ ```ruby
47
+ count = future{ sleep(10); raise StandardError.new("Boom!") }
48
+ count.state #=> :pending
49
+ pending?(count) #=> true
50
+
51
+ deref(count) #=> nil (after blocking)
52
+ rejected?(count) #=> true
53
+ count.reason #=> #<StandardError: Boom!>
54
+ ```
55
+
56
+ ## Copyright
57
+
58
+ *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
59
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
60
+
61
+ ## License
62
+
63
+ Released under the MIT license.
64
+
65
+ http://www.opensource.org/licenses/mit-license.php
66
+
67
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
68
+ > of this software and associated documentation files (the "Software"), to deal
69
+ > in the Software without restriction, including without limitation the rights
70
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
71
+ > copies of the Software, and to permit persons to whom the Software is
72
+ > furnished to do so, subject to the following conditions:
73
+ >
74
+ > The above copyright notice and this permission notice shall be included in
75
+ > all copies or substantial portions of the Software.
76
+ >
77
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
78
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
79
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
80
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
81
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
82
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
83
+ > THE SOFTWARE.
@@ -1,52 +1,52 @@
1
- # Go, Go, Gadget Goroutine!
2
-
3
- A goroutine is the simplest of the concurrency utilities in this library. It is inspired by
4
- [Go's](http://golang.org/) [goroutines](https://gobyexample.com/goroutines) and
5
- [Erlang's](http://www.erlang.org/) [spawn](http://erlangexamples.com/tag/spawn/) keyword. The
6
- `go` function is nothing more than a simple way to send a block to the global thread pool (see below)
7
- for processing.
8
-
9
- ## Examples
10
-
11
- ```ruby
12
- require 'concurrent'
13
-
14
- @expected = nil
15
-
16
- go(1, 2, 3){|a, b, c| sleep(1); @expected = [c, b, a] }
17
-
18
- sleep(0.1)
19
- @expected #=> nil
20
-
21
- sleep(2)
22
- @expected #=> [3, 2, 1]
23
- ```
24
-
25
- ## Copyright
26
-
27
- *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
28
- It is free software and may be redistributed under the terms specified in the LICENSE file.
29
-
30
- ## License
31
-
32
- Released under the MIT license.
33
-
34
- http://www.opensource.org/licenses/mit-license.php
35
-
36
- > Permission is hereby granted, free of charge, to any person obtaining a copy
37
- > of this software and associated documentation files (the "Software"), to deal
38
- > in the Software without restriction, including without limitation the rights
39
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40
- > copies of the Software, and to permit persons to whom the Software is
41
- > furnished to do so, subject to the following conditions:
42
- >
43
- > The above copyright notice and this permission notice shall be included in
44
- > all copies or substantial portions of the Software.
45
- >
46
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
52
- > THE SOFTWARE.
1
+ # Go, Go, Gadget Goroutine!
2
+
3
+ A goroutine is the simplest of the concurrency utilities in this library. It is inspired by
4
+ [Go's](http://golang.org/) [goroutines](https://gobyexample.com/goroutines) and
5
+ [Erlang's](http://www.erlang.org/) [spawn](http://erlangexamples.com/tag/spawn/) keyword. The
6
+ `go` function is nothing more than a simple way to send a block to the global thread pool (see below)
7
+ for processing.
8
+
9
+ ## Examples
10
+
11
+ ```ruby
12
+ require 'concurrent'
13
+
14
+ @expected = nil
15
+
16
+ go(1, 2, 3){|a, b, c| sleep(1); @expected = [c, b, a] }
17
+
18
+ sleep(0.1)
19
+ @expected #=> nil
20
+
21
+ sleep(2)
22
+ @expected #=> [3, 2, 1]
23
+ ```
24
+
25
+ ## Copyright
26
+
27
+ *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
28
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
29
+
30
+ ## License
31
+
32
+ Released under the MIT license.
33
+
34
+ http://www.opensource.org/licenses/mit-license.php
35
+
36
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
37
+ > of this software and associated documentation files (the "Software"), to deal
38
+ > in the Software without restriction, including without limitation the rights
39
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40
+ > copies of the Software, and to permit persons to whom the Software is
41
+ > furnished to do so, subject to the following conditions:
42
+ >
43
+ > The above copyright notice and this permission notice shall be included in
44
+ > all copies or substantial portions of the Software.
45
+ >
46
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
52
+ > THE SOFTWARE.
@@ -1,32 +1,32 @@
1
- # Obligation
2
-
3
- TBD...
4
-
5
- ## Copyright
6
-
7
- *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
8
- It is free software and may be redistributed under the terms specified in the LICENSE file.
9
-
10
- ## License
11
-
12
- Released under the MIT license.
13
-
14
- http://www.opensource.org/licenses/mit-license.php
15
-
16
- > Permission is hereby granted, free of charge, to any person obtaining a copy
17
- > of this software and associated documentation files (the "Software"), to deal
18
- > in the Software without restriction, including without limitation the rights
19
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
- > copies of the Software, and to permit persons to whom the Software is
21
- > furnished to do so, subject to the following conditions:
22
- >
23
- > The above copyright notice and this permission notice shall be included in
24
- > all copies or substantial portions of the Software.
25
- >
26
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
- > THE SOFTWARE.
1
+ # Obligation
2
+
3
+ TBD...
4
+
5
+ ## Copyright
6
+
7
+ *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
8
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
9
+
10
+ ## License
11
+
12
+ Released under the MIT license.
13
+
14
+ http://www.opensource.org/licenses/mit-license.php
15
+
16
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
17
+ > of this software and associated documentation files (the "Software"), to deal
18
+ > in the Software without restriction, including without limitation the rights
19
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
+ > copies of the Software, and to permit persons to whom the Software is
21
+ > furnished to do so, subject to the following conditions:
22
+ >
23
+ > The above copyright notice and this permission notice shall be included in
24
+ > all copies or substantial portions of the Software.
25
+ >
26
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
+ > THE SOFTWARE.
@@ -1,227 +1,227 @@
1
- # Promises, Promises...
2
-
3
- A promise is the most powerful and versatile of the concurrency objects in this library.
4
- Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A)
5
- and [Promises/A+](http://promises-aplus.github.io/promises-spec/) specifications.
6
-
7
- > A promise represents the eventual value returned from the single completion of an operation.
8
-
9
- Promises are similar to futures and share many of the same behaviours. Promises are far more robust,
10
- however. Promises can be chained in a tree structure where each promise may have zero or more children.
11
- Promises are chained using the `then` method. The result of a call to `then` is always another promise.
12
- Promises are resolved asynchronously in the order they are added to the tree. Parents are guaranteed
13
- to be resolved before their children. The result of each promise is passed to each of its children
14
- upon resolution. When a promise is rejected all its children will be summarily rejected.
15
-
16
- Promises have three possible states: *pending*, *rejected*, and *fulfilled*. When a promise is created it is set
17
- to *pending* and will remain in that state until processing is complete. A completed promise is either *rejected*,
18
- indicating that an exception was thrown during processing, or *fulfilled*, indicating succedd. If a promise is
19
- *fulfilled* its `value` will be updated to reflect the result of the operation. If *rejected* the `reason` will
20
- be updated with a reference to the thrown exception. The predicate methods `pending?`, `rejected`, and `fulfilled?`
21
- can be called at any time to obtain the state of the promise, as can the `state` method, which returns a symbol.
22
-
23
- Retrieving the value of a promise is done through the `value` (alias: `deref`) method. Obtaining the value of
24
- a promise is a potentially blocking operation. When a promise is *rejected* a call to `value` will return `nil`
25
- immediately. When a promise is *fulfilled* a call to `value` will immediately return the current value.
26
- When a promise is *pending* a call to `value` will block until the promise is either *rejected* or *fulfilled*.
27
- A *timeout* value can be passed to `value` to limit how long the call will block. If `nil` the call will
28
- block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the
29
- maximum number of seconds to block.
30
-
31
- Promises run on the global thread pool.
32
-
33
- ## Examples
34
-
35
- Start by requiring promises
36
-
37
- ```ruby
38
- require 'concurrent'
39
- ```
40
-
41
- Then create one
42
-
43
- ```ruby
44
- p = Promise.new("Jerry", "D'Antonio") do |first, last|
45
- "#{last}, #{first}"
46
- end
47
-
48
- # -or-
49
-
50
- p = promise(10){|x| x * x * x }
51
- ```
52
-
53
- Promises can be chained using the `then` method. The `then` method
54
- accepts a block but no arguments. The result of the each promise is
55
- passed as the block argument to chained promises
56
-
57
- ```ruby
58
- p = promise(10){|x| x * 2}.then{|result| result - 10 }
59
- ```
60
-
61
- And so on, and so on, and so on...
62
-
63
- ```ruby
64
- p = promise(10){|x| x * 2}.
65
- then{|result| result - 10 }.
66
- then{|result| result * 3 }.
67
- then{|result| result % 5 }
68
- ```
69
-
70
- Promises are executed asynchronously so a newly-created promise *should* always be in the pending state
71
-
72
-
73
- ```ruby
74
- p = promise{ "Hello, world!" }
75
- p.state #=> :pending
76
- p.pending? #=> true
77
- ```
78
-
79
- Wait a little bit, and the promise will resolve and provide a value
80
-
81
- ```ruby
82
- p = promise{ "Hello, world!" }
83
- sleep(0.1)
84
-
85
- p.state #=> :fulfilled
86
- p.fulfilled? #=> true
87
-
88
- p.value #=> "Hello, world!"
89
-
90
- ```
91
-
92
- If an exception occurs, the promise will be rejected and will provide
93
- a reason for the rejection
94
-
95
- ```ruby
96
- p = promise{ raise StandardError.new("Here comes the Boom!") }
97
- sleep(0.1)
98
-
99
- p.state #=> :rejected
100
- p.rejected? #=> true
101
-
102
- p.reason=> #=> "#<StandardError: Here comes the Boom!>"
103
- ```
104
-
105
- ### Rejection
106
-
107
- Much like the economy, rejection exhibits a trickle-down effect. When
108
- a promise is rejected all its children will be rejected
109
-
110
- ```ruby
111
- p = [ promise{ Thread.pass; raise StandardError } ]
112
-
113
- 10.times{|i| p << p.first.then{ i } }
114
- sleep(0.1)
115
-
116
- p.length #=> 11
117
- p.first.state #=> :rejected
118
- p.last.state #=> :rejected
119
- ```
120
-
121
- Once a promise is rejected it will not accept any children. Calls
122
- to `then` will continually return `self`
123
-
124
- ```ruby
125
- p = promise{ raise StandardError }
126
- sleep(0.1)
127
-
128
- p.object_id #=> 32960556
129
- p.then{}.object_id #=> 32960556
130
- p.then{}.object_id #=> 32960556
131
- ```
132
-
133
- ### Error Handling
134
-
135
- Promises support error handling callbacks is a style mimicing Ruby's
136
- own exception handling mechanism, namely `rescue`
137
-
138
-
139
- ```ruby
140
- promise{ "dangerous operation..." }.rescue{|ex| puts "Bam!" }
141
-
142
- # -or- (for the Java/C# crowd)
143
- promise{ "dangerous operation..." }.catch{|ex| puts "Boom!" }
144
-
145
- # -or- (for the hipsters)
146
- promise{ "dangerous operation..." }.on_error{|ex| puts "Pow!" }
147
- ```
148
-
149
- As with Ruby's `rescue` mechanism, a promise's `rescue` method can
150
- accept an optional Exception class argument (defaults to `Exception`
151
- when not specified)
152
-
153
-
154
- ```ruby
155
- promise{ "dangerous operation..." }.rescue(ArgumentError){|ex| puts "Bam!" }
156
- ```
157
-
158
- Calls to `rescue` can also be chained
159
-
160
- ```ruby
161
- promise{ "dangerous operation..." }.
162
- rescue(ArgumentError){|ex| puts "Bam!" }.
163
- rescue(NoMethodError){|ex| puts "Boom!" }.
164
- rescue(StandardError){|ex| puts "Pow!" }
165
- ```
166
-
167
- When there are multiple `rescue` handlers the first one to match the thrown
168
- exception will be triggered
169
-
170
- ```ruby
171
- promise{ raise NoMethodError }.
172
- rescue(ArgumentError){|ex| puts "Bam!" }.
173
- rescue(NoMethodError){|ex| puts "Boom!" }.
174
- rescue(StandardError){|ex| puts "Pow!" }
175
-
176
- sleep(0.1)
177
-
178
- #=> Boom!
179
- ```
180
-
181
- Trickle-down rejection also applies to rescue handlers. When a promise is rejected,
182
- for any reason, its rescue handlers will be triggered. Rejection of the parent counts.
183
-
184
- ```ruby
185
- promise{ Thread.pass; raise StandardError }.
186
- then{ true }.rescue{ puts 'Boom!' }.
187
- then{ true }.rescue{ puts 'Boom!' }.
188
- then{ true }.rescue{ puts 'Boom!' }.
189
- then{ true }.rescue{ puts 'Boom!' }.
190
- then{ true }.rescue{ puts 'Boom!' }
191
- sleep(0.1)
192
-
193
- #=> Boom!
194
- #=> Boom!
195
- #=> Boom!
196
- #=> Boom!
197
- #=> Boom!
198
- ```
199
-
200
- ## Copyright
201
-
202
- *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
203
- It is free software and may be redistributed under the terms specified in the LICENSE file.
204
-
205
- ## License
206
-
207
- Released under the MIT license.
208
-
209
- http://www.opensource.org/licenses/mit-license.php
210
-
211
- > Permission is hereby granted, free of charge, to any person obtaining a copy
212
- > of this software and associated documentation files (the "Software"), to deal
213
- > in the Software without restriction, including without limitation the rights
214
- > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
215
- > copies of the Software, and to permit persons to whom the Software is
216
- > furnished to do so, subject to the following conditions:
217
- >
218
- > The above copyright notice and this permission notice shall be included in
219
- > all copies or substantial portions of the Software.
220
- >
221
- > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
222
- > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
223
- > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
224
- > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
225
- > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
226
- > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
227
- > THE SOFTWARE.
1
+ # Promises, Promises...
2
+
3
+ A promise is the most powerful and versatile of the concurrency objects in this library.
4
+ Promises are inspired by the JavaScript [Promises/A](http://wiki.commonjs.org/wiki/Promises/A)
5
+ and [Promises/A+](http://promises-aplus.github.io/promises-spec/) specifications.
6
+
7
+ > A promise represents the eventual value returned from the single completion of an operation.
8
+
9
+ Promises are similar to futures and share many of the same behaviours. Promises are far more robust,
10
+ however. Promises can be chained in a tree structure where each promise may have zero or more children.
11
+ Promises are chained using the `then` method. The result of a call to `then` is always another promise.
12
+ Promises are resolved asynchronously in the order they are added to the tree. Parents are guaranteed
13
+ to be resolved before their children. The result of each promise is passed to each of its children
14
+ upon resolution. When a promise is rejected all its children will be summarily rejected.
15
+
16
+ Promises have three possible states: *pending*, *rejected*, and *fulfilled*. When a promise is created it is set
17
+ to *pending* and will remain in that state until processing is complete. A completed promise is either *rejected*,
18
+ indicating that an exception was thrown during processing, or *fulfilled*, indicating succedd. If a promise is
19
+ *fulfilled* its `value` will be updated to reflect the result of the operation. If *rejected* the `reason` will
20
+ be updated with a reference to the thrown exception. The predicate methods `pending?`, `rejected`, and `fulfilled?`
21
+ can be called at any time to obtain the state of the promise, as can the `state` method, which returns a symbol.
22
+
23
+ Retrieving the value of a promise is done through the `value` (alias: `deref`) method. Obtaining the value of
24
+ a promise is a potentially blocking operation. When a promise is *rejected* a call to `value` will return `nil`
25
+ immediately. When a promise is *fulfilled* a call to `value` will immediately return the current value.
26
+ When a promise is *pending* a call to `value` will block until the promise is either *rejected* or *fulfilled*.
27
+ A *timeout* value can be passed to `value` to limit how long the call will block. If `nil` the call will
28
+ block indefinitely. If `0` the call will not block. Any other integer or float value will indicate the
29
+ maximum number of seconds to block.
30
+
31
+ Promises run on the global thread pool.
32
+
33
+ ## Examples
34
+
35
+ Start by requiring promises
36
+
37
+ ```ruby
38
+ require 'concurrent'
39
+ ```
40
+
41
+ Then create one
42
+
43
+ ```ruby
44
+ p = Promise.new("Jerry", "D'Antonio") do |first, last|
45
+ "#{last}, #{first}"
46
+ end
47
+
48
+ # -or-
49
+
50
+ p = promise(10){|x| x * x * x }
51
+ ```
52
+
53
+ Promises can be chained using the `then` method. The `then` method
54
+ accepts a block but no arguments. The result of the each promise is
55
+ passed as the block argument to chained promises
56
+
57
+ ```ruby
58
+ p = promise(10){|x| x * 2}.then{|result| result - 10 }
59
+ ```
60
+
61
+ And so on, and so on, and so on...
62
+
63
+ ```ruby
64
+ p = promise(10){|x| x * 2}.
65
+ then{|result| result - 10 }.
66
+ then{|result| result * 3 }.
67
+ then{|result| result % 5 }
68
+ ```
69
+
70
+ Promises are executed asynchronously so a newly-created promise *should* always be in the pending state
71
+
72
+
73
+ ```ruby
74
+ p = promise{ "Hello, world!" }
75
+ p.state #=> :pending
76
+ p.pending? #=> true
77
+ ```
78
+
79
+ Wait a little bit, and the promise will resolve and provide a value
80
+
81
+ ```ruby
82
+ p = promise{ "Hello, world!" }
83
+ sleep(0.1)
84
+
85
+ p.state #=> :fulfilled
86
+ p.fulfilled? #=> true
87
+
88
+ p.value #=> "Hello, world!"
89
+
90
+ ```
91
+
92
+ If an exception occurs, the promise will be rejected and will provide
93
+ a reason for the rejection
94
+
95
+ ```ruby
96
+ p = promise{ raise StandardError.new("Here comes the Boom!") }
97
+ sleep(0.1)
98
+
99
+ p.state #=> :rejected
100
+ p.rejected? #=> true
101
+
102
+ p.reason=> #=> "#<StandardError: Here comes the Boom!>"
103
+ ```
104
+
105
+ ### Rejection
106
+
107
+ Much like the economy, rejection exhibits a trickle-down effect. When
108
+ a promise is rejected all its children will be rejected
109
+
110
+ ```ruby
111
+ p = [ promise{ Thread.pass; raise StandardError } ]
112
+
113
+ 10.times{|i| p << p.first.then{ i } }
114
+ sleep(0.1)
115
+
116
+ p.length #=> 11
117
+ p.first.state #=> :rejected
118
+ p.last.state #=> :rejected
119
+ ```
120
+
121
+ Once a promise is rejected it will not accept any children. Calls
122
+ to `then` will continually return `self`
123
+
124
+ ```ruby
125
+ p = promise{ raise StandardError }
126
+ sleep(0.1)
127
+
128
+ p.object_id #=> 32960556
129
+ p.then{}.object_id #=> 32960556
130
+ p.then{}.object_id #=> 32960556
131
+ ```
132
+
133
+ ### Error Handling
134
+
135
+ Promises support error handling callbacks is a style mimicing Ruby's
136
+ own exception handling mechanism, namely `rescue`
137
+
138
+
139
+ ```ruby
140
+ promise{ "dangerous operation..." }.rescue{|ex| puts "Bam!" }
141
+
142
+ # -or- (for the Java/C# crowd)
143
+ promise{ "dangerous operation..." }.catch{|ex| puts "Boom!" }
144
+
145
+ # -or- (for the hipsters)
146
+ promise{ "dangerous operation..." }.on_error{|ex| puts "Pow!" }
147
+ ```
148
+
149
+ As with Ruby's `rescue` mechanism, a promise's `rescue` method can
150
+ accept an optional Exception class argument (defaults to `Exception`
151
+ when not specified)
152
+
153
+
154
+ ```ruby
155
+ promise{ "dangerous operation..." }.rescue(ArgumentError){|ex| puts "Bam!" }
156
+ ```
157
+
158
+ Calls to `rescue` can also be chained
159
+
160
+ ```ruby
161
+ promise{ "dangerous operation..." }.
162
+ rescue(ArgumentError){|ex| puts "Bam!" }.
163
+ rescue(NoMethodError){|ex| puts "Boom!" }.
164
+ rescue(StandardError){|ex| puts "Pow!" }
165
+ ```
166
+
167
+ When there are multiple `rescue` handlers the first one to match the thrown
168
+ exception will be triggered
169
+
170
+ ```ruby
171
+ promise{ raise NoMethodError }.
172
+ rescue(ArgumentError){|ex| puts "Bam!" }.
173
+ rescue(NoMethodError){|ex| puts "Boom!" }.
174
+ rescue(StandardError){|ex| puts "Pow!" }
175
+
176
+ sleep(0.1)
177
+
178
+ #=> Boom!
179
+ ```
180
+
181
+ Trickle-down rejection also applies to rescue handlers. When a promise is rejected,
182
+ for any reason, its rescue handlers will be triggered. Rejection of the parent counts.
183
+
184
+ ```ruby
185
+ promise{ Thread.pass; raise StandardError }.
186
+ then{ true }.rescue{ puts 'Boom!' }.
187
+ then{ true }.rescue{ puts 'Boom!' }.
188
+ then{ true }.rescue{ puts 'Boom!' }.
189
+ then{ true }.rescue{ puts 'Boom!' }.
190
+ then{ true }.rescue{ puts 'Boom!' }
191
+ sleep(0.1)
192
+
193
+ #=> Boom!
194
+ #=> Boom!
195
+ #=> Boom!
196
+ #=> Boom!
197
+ #=> Boom!
198
+ ```
199
+
200
+ ## Copyright
201
+
202
+ *Concurrent Ruby* is Copyright &copy; 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
203
+ It is free software and may be redistributed under the terms specified in the LICENSE file.
204
+
205
+ ## License
206
+
207
+ Released under the MIT license.
208
+
209
+ http://www.opensource.org/licenses/mit-license.php
210
+
211
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
212
+ > of this software and associated documentation files (the "Software"), to deal
213
+ > in the Software without restriction, including without limitation the rights
214
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
215
+ > copies of the Software, and to permit persons to whom the Software is
216
+ > furnished to do so, subject to the following conditions:
217
+ >
218
+ > The above copyright notice and this permission notice shall be included in
219
+ > all copies or substantial portions of the Software.
220
+ >
221
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
222
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
223
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
224
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
225
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
226
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
227
+ > THE SOFTWARE.