mr_darcy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +95 -0
  6. data/Guardfile +14 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +267 -0
  9. data/Rakefile +6 -0
  10. data/lib/mr_darcy/context.rb +71 -0
  11. data/lib/mr_darcy/deferred.rb +25 -0
  12. data/lib/mr_darcy/drivers/celluloid.rb +23 -0
  13. data/lib/mr_darcy/drivers/synchronous.rb +15 -0
  14. data/lib/mr_darcy/drivers/thread.rb +22 -0
  15. data/lib/mr_darcy/drivers.rb +13 -0
  16. data/lib/mr_darcy/promise/base.rb +117 -0
  17. data/lib/mr_darcy/promise/celluloid.rb +52 -0
  18. data/lib/mr_darcy/promise/child_promise.rb +83 -0
  19. data/lib/mr_darcy/promise/dsl.rb +29 -0
  20. data/lib/mr_darcy/promise/em.rb +29 -0
  21. data/lib/mr_darcy/promise/state/base.rb +43 -0
  22. data/lib/mr_darcy/promise/state/rejected.rb +11 -0
  23. data/lib/mr_darcy/promise/state/resolved.rb +11 -0
  24. data/lib/mr_darcy/promise/state/unresolved.rb +19 -0
  25. data/lib/mr_darcy/promise/state.rb +25 -0
  26. data/lib/mr_darcy/promise/synchronous.rb +27 -0
  27. data/lib/mr_darcy/promise/thread.rb +64 -0
  28. data/lib/mr_darcy/promise.rb +31 -0
  29. data/lib/mr_darcy/role.rb +45 -0
  30. data/lib/mr_darcy/version.rb +3 -0
  31. data/lib/mr_darcy.rb +26 -0
  32. data/mr_darcy.gemspec +29 -0
  33. data/spec/acceptance/dci_bank_transfer_spec.rb +62 -0
  34. data/spec/acceptance/em_http_request_spec.rb +22 -0
  35. data/spec/acceptance/open-uri_http_request_spec.rb +21 -0
  36. data/spec/acceptance/simple_promise_spec.rb +25 -0
  37. data/spec/acceptance/simple_promise_with_chained_fail.rb +25 -0
  38. data/spec/acceptance/simple_promise_with_fail_spec.rb +25 -0
  39. data/spec/acceptance/simple_promise_with_then_spec.rb +25 -0
  40. data/spec/lib/mr_darcy/context_spec.rb +22 -0
  41. data/spec/lib/mr_darcy/promise/base_spec.rb +197 -0
  42. data/spec/lib/mr_darcy/promise/child_promise_spec.rb +169 -0
  43. data/spec/lib/mr_darcy/promise/dsl_spec.rb +43 -0
  44. data/spec/lib/mr_darcy/promise/state/base_spec.rb +24 -0
  45. data/spec/lib/mr_darcy/promise/state/rejected_spec.rb +12 -0
  46. data/spec/lib/mr_darcy/promise/state/resolved_spec.rb +12 -0
  47. data/spec/lib/mr_darcy/promise/state/unresolved_spec.rb +22 -0
  48. data/spec/lib/mr_darcy/promise/state_spec.rb +30 -0
  49. data/spec/lib/mr_darcy/promise/synchronous_spec.rb +21 -0
  50. data/spec/lib/mr_darcy/promise_spec.rb +72 -0
  51. data/spec/lib/mr_darcy/role_spec.rb +89 -0
  52. data/spec/lib/mr_darcy_spec.rb +19 -0
  53. data/spec/spec_helper.rb +10 -0
  54. data/spec/support/context_helpers.rb +19 -0
  55. data/spec/support/shared_examples_for_promise.rb +47 -0
  56. data/spec/support/shared_examples_for_thennable.rb +10 -0
  57. metadata +279 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 200c16f28a04c2608e104d084400e44c55f84e78
4
+ data.tar.gz: 2c4132617b62c2713cedcc37d560c55a180e6251
5
+ SHA512:
6
+ metadata.gz: baa8c75ad0f00c458e6610b389a52b29d345b705d02f71ca845a8df4297deb31c3c7c5b6b556ef3338b179a807f8e5f53121308d30eb0111f045bdbf6f1bd044
7
+ data.tar.gz: c73abc19ded59554f375cbf4e34a74fa946e114d2a34d90711e568f0b47179b5535675fb6448614706024108b33ef27cc41f701347a086d9943bf4476a0970e6
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ - 2.1.1
3
+ - 2.1.0
4
+ - 2.0.0
5
+ - jruby-20mode
6
+ - rbx
7
+
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'pry-byebug', platforms: [:mri_20, :mri_21]
4
+
5
+ # Specify your gem's dependencies in mr_darcy.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,95 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mr_darcy (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.3.5)
10
+ byebug (2.6.0)
11
+ columnize (~> 0.3)
12
+ debugger-linecache (~> 1.2)
13
+ celluloid (0.15.2)
14
+ timers (~> 1.1.0)
15
+ celluloid-io (0.15.0)
16
+ celluloid (>= 0.15.0)
17
+ nio4r (>= 0.5.0)
18
+ coderay (1.1.0)
19
+ columnize (0.3.6)
20
+ cookiejar (0.3.0)
21
+ debugger-linecache (1.2.0)
22
+ diff-lcs (1.2.5)
23
+ em-http-request (1.0.3)
24
+ addressable (>= 2.2.3)
25
+ cookiejar
26
+ em-socksify
27
+ eventmachine (>= 1.0.0.beta.4)
28
+ http_parser.rb (>= 0.5.3)
29
+ em-socksify (0.2.1)
30
+ eventmachine (>= 1.0.0.beta.4)
31
+ eventmachine (1.0.3)
32
+ ffi (1.9.3)
33
+ formatador (0.2.4)
34
+ guard (2.4.0)
35
+ formatador (>= 0.2.4)
36
+ listen (~> 2.1)
37
+ lumberjack (~> 1.0)
38
+ pry (>= 0.9.12)
39
+ thor (>= 0.18.1)
40
+ guard-bundler (2.0.0)
41
+ bundler (~> 1.0)
42
+ guard (~> 2.2)
43
+ guard-rspec (4.2.6)
44
+ guard (~> 2.1)
45
+ rspec (>= 2.14, < 4.0)
46
+ http_parser.rb (0.6.0)
47
+ listen (2.5.0)
48
+ celluloid (>= 0.15.2)
49
+ celluloid-io (>= 0.15.0)
50
+ rb-fsevent (>= 0.9.3)
51
+ rb-inotify (>= 0.9)
52
+ lumberjack (1.0.4)
53
+ method_source (0.8.2)
54
+ nio4r (1.0.0)
55
+ pry (0.9.12.6)
56
+ coderay (~> 1.0)
57
+ method_source (~> 0.8)
58
+ slop (~> 3.4)
59
+ pry-byebug (1.3.1)
60
+ byebug (~> 2.6)
61
+ pry (~> 0.9.12)
62
+ rake (10.1.1)
63
+ rb-fsevent (0.9.4)
64
+ rb-inotify (0.9.3)
65
+ ffi (>= 0.5.0)
66
+ rspec (2.14.1)
67
+ rspec-core (~> 2.14.0)
68
+ rspec-expectations (~> 2.14.0)
69
+ rspec-mocks (~> 2.14.0)
70
+ rspec-core (2.14.7)
71
+ rspec-expectations (2.14.5)
72
+ diff-lcs (>= 1.1.3, < 2.0)
73
+ rspec-mocks (2.14.5)
74
+ slop (3.4.7)
75
+ terminal-notifier-guard (1.5.3)
76
+ thor (0.18.1)
77
+ timers (1.1.0)
78
+
79
+ PLATFORMS
80
+ ruby
81
+
82
+ DEPENDENCIES
83
+ bundler (~> 1.5)
84
+ celluloid
85
+ em-http-request
86
+ eventmachine
87
+ guard
88
+ guard-bundler
89
+ guard-rspec
90
+ mr_darcy!
91
+ pry
92
+ pry-byebug
93
+ rake
94
+ rspec
95
+ terminal-notifier-guard
data/Guardfile ADDED
@@ -0,0 +1,14 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :bundler do
5
+ watch('Gemfile')
6
+ watch(/^.+\.gemspec/)
7
+ end
8
+
9
+ guard :rspec do
10
+ watch(%r{^spec/.+_spec\.rb$})
11
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
12
+ watch('spec/spec_helper.rb') { "spec" }
13
+ end
14
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 James Harton
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,267 @@
1
+ # MrDarcy
2
+
3
+ A mashup of Async Promises and DCI in ruby.
4
+
5
+ ![Build Status](https://www.codeship.io/projects/baa3c520-a0e3-0131-f32f-26748b0e5360/status)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'mr_darcy'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ ```sh
18
+ bundle
19
+ ```
20
+
21
+ Or install it yourself as:
22
+
23
+ ```sh
24
+ gem install mr_darcy
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### WARNING
30
+
31
+ MrDarcy is definitely experimental, and was mostly built over the weekend of
32
+ [RailsCamp NZ 5](http://camp.ruby.org.nz/) with the generous help of the
33
+ amazing and sexy [@breccan](https://twitter.com/breccan) and
34
+ [@eoinkelly](https://twitter.com/eoinkelly).
35
+
36
+ #### Should I use MrDarcy in Production?
37
+
38
+ No.
39
+
40
+ #### How can I help make MrDarcy production ready?
41
+
42
+ Run it in production. Report bugs.
43
+
44
+ ### Such promise. Many then.
45
+
46
+ Promises are a way of structuring batches of (async) functionality into a
47
+ pipeline, in such a way as to make them seem synchronous.
48
+
49
+ Here's an example:
50
+
51
+ ```ruby
52
+ # We're going to wrap an asynchronous web request using EventMachine
53
+ # in a promise:
54
+ data = MrDarcy.promise do
55
+ EM.run do
56
+ http = EM.HttpRequest.new('http://camp.ruby.org.nz/').get
57
+ http.errback do
58
+ reject http.error
59
+ EM.stop
60
+ end
61
+ http.callback do
62
+ resolve http.response
63
+ EM.stop
64
+ end
65
+ end
66
+ end.then do |response|
67
+ response.body
68
+ end.result
69
+
70
+ puts data
71
+ ```
72
+
73
+ What's cool about MrDarcy is that we can switch between different methods of
74
+ doing async ruby:
75
+ - Naive threads, using MRI's thread implementation.
76
+ - Reactor pattern, using [EventMachine](http://rubyeventmachine.com/) to
77
+ schedule promises on the a reactor thread.
78
+ - Actor pattern, using [Celluloid](http://celluloid.io/) to schedule
79
+ promises using Celluloid futures.
80
+
81
+ #### Key points to know about Promises
82
+
83
+ 1. You create them with a block, which is scheduled asynchronously, and
84
+ inside of which you can place your long-running executable. Inside this
85
+ block you call either `resolve <value>` or `reject <exception>` to resolve
86
+ or reject the promise.
87
+
88
+ ```ruby
89
+ MrDarcy.promise do
90
+ accellerate_the_delorean
91
+ if speed >= 88
92
+ resolve :time_flux_initiated
93
+ else
94
+ reject :engage_service_brake
95
+ end
96
+ end
97
+ ```
98
+
99
+ 2. All promises have `then` and `fail` methods, to which you pass a block to
100
+ be called when the promise resolves (`then`) or rejects (`fail`). These
101
+ methods return new promises, upon which you can chain more `then` and
102
+ `fail` calls.
103
+
104
+ ```ruby
105
+ MrDarcy.promise do
106
+ i = rand
107
+ i > 0.5 ? resolve i : reject i
108
+ end.then |value|
109
+ # success
110
+ end.fail |value|
111
+ # failure
112
+ end
113
+ ```
114
+
115
+ 3. `fail` is used to catch errors asynchronously, and deal with them.
116
+ Therefore the result of a `fail` block will be a resolved promise.
117
+ If you wish to keep processing a failure then you can `raise` it
118
+ within the `fail` block to pass it along to the next `fail` block.
119
+
120
+ ```ruby
121
+ MrDarcy.promise do
122
+ reject 2
123
+ end.fail |value|
124
+ value * value
125
+ end.then |value|
126
+ # I am called with 4
127
+ end
128
+ ```
129
+
130
+ 4. Failures cascade until they're caught:
131
+
132
+ ```ruby
133
+ MrDarcy.promise do
134
+ reject :fail
135
+ end.then
136
+ # I am skipped
137
+ end.then
138
+ # as am I
139
+ end.fail
140
+ # I am called
141
+ end
142
+ ```
143
+
144
+ 5. If your block returns a new promise, then `then` or `fail` will defer
145
+ their resolution until the new promise is resolved:
146
+
147
+ ```ruby
148
+ MrDarcy.promise do
149
+ resolve 1
150
+ end.then do |value|
151
+ MrDarcy.promise do
152
+ resolve value * 2
153
+ end
154
+ end.then |value|
155
+ # I will be called with 2
156
+ end
157
+ ```
158
+
159
+ ### Sprinkle on some DCI goodness.
160
+
161
+ [DCI](http://fulloo.info) is a method of specifying interactions between
162
+ objects in a single location, by decorating or extending your data objects
163
+ within a context, running the interaction and then (optionally) removing
164
+ the extensions again.
165
+
166
+ Other takes on DCI in Ruby:
167
+ - [playhouse](https://github.com/enspiral/playhouse) is an app framework
168
+ for building entire apps with DCI from the lovable hippies at
169
+ [enspiral](http://www.enspiral.com/),
170
+
171
+ - [surrounded](https://github.com/saturnflyer/surrounded) by
172
+ [Jim Gay](https://github.com/saturnflyer) is a gem for doing DCI in
173
+ a simple, repeatable fashion.
174
+
175
+ MrDarcy is a little differnt to these approaches, as is builds an interesting
176
+ DSL on top of promises to create contexts that are alive as long as they need
177
+ to be to achieve their goal, even when code is being run asynchronously.
178
+
179
+ Here's how we define a classic bank trasfer example:
180
+
181
+ ```ruby
182
+ class BankTransfer < MrDarcy::Context
183
+ role :money_source do
184
+ def has_available_funds? amount
185
+ available_balance >= amount
186
+ end
187
+
188
+ def subtract_funds amount
189
+ self.available_balance = available_balance - amount
190
+ end
191
+ end
192
+
193
+ role :money_destination do
194
+ def receive_funds amount
195
+ self.available_balance = available_balance + amount
196
+ end
197
+ end
198
+
199
+ action :transfer do |amount|
200
+ if money_source.has_available_funds? amount
201
+ money_source.subtract_funds amount
202
+ money_destination.receive_funds amount
203
+ else
204
+ raise "insufficient funds"
205
+ end
206
+ amount
207
+ end
208
+ end
209
+ ```
210
+
211
+ - The `role` class method defines roles, which the context will expect to be
212
+ passed on object creation. They also define the extra behaviour (methods)
213
+ that we wish to see added to our role players at initialisation.
214
+
215
+ - The `action` class method defines our interactions. In other words, this
216
+ is where we define how the interaction will take place. These also define
217
+ instance methods on the class of the same name, which return a promise
218
+ when called.
219
+
220
+ - You can have as many roles and actions as needed by your context.
221
+
222
+ Let's transfer some funds between two accounts:
223
+
224
+ ```ruby
225
+ Account = Struct.new(:available_balance)
226
+ marty = Account.new(10)
227
+ doc_brown = Account.new(15)
228
+
229
+ context = BankTransfer.new money_source: marty, money_destination: doc_brown
230
+ context.transfer(5).then do |amount|
231
+ puts "Successfully transferred #{amount} from #{money_source} to #{money_destination}"
232
+ end
233
+
234
+ context.transfer(50).fail do |exception|
235
+ puts "Failed to transfer funds: #{exception.message}"
236
+ end
237
+ ```
238
+
239
+ What's super cool, however is that because promises can return and chain other
240
+ promises, we can come up with some pretty involved scenarios:
241
+
242
+ ```ruby
243
+ marty = Account.new(10)
244
+ jenn = Account.new(10)
245
+ doc_brown = Account.new(200)
246
+
247
+ context = BankTransfer.new money_source: marty, money_destination: jenn
248
+ context.transfer(20).fail do
249
+ # Oh no, Marty doesn't have enough money, let's borrow some from Doc.
250
+ BankTransfer.new(money_source: doc_brown, money_destination: marty) \
251
+ .transfer(20).then
252
+ # Thy transferring again.
253
+ context.transfer(20)
254
+ end
255
+ end
256
+ ```
257
+
258
+ I hope that's enough to get you started. Yup, it's a bit crazy, but it might
259
+ just work.
260
+
261
+ ## Contributing
262
+
263
+ 1. Fork it ( http://github.com/<my-github-username>/mr_darcy/fork )
264
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
265
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
266
+ 4. Push to the branch (`git push origin my-new-feature`)
267
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new :spec
5
+
6
+ task default: :spec
@@ -0,0 +1,71 @@
1
+ module MrDarcy
2
+ class Context
3
+
4
+ class << self
5
+ def role role_name, options={}, &block
6
+ self.roles[role_name] = Role.new(role_name, options, &block)
7
+ end
8
+
9
+ def action action_name, &block
10
+ define_method action_name do |*args|
11
+ self.then do |value|
12
+ self.instance_exec(*args, &block)
13
+ end
14
+ self
15
+ end
16
+ end
17
+
18
+ def roles
19
+ @roles ||= {}
20
+ end
21
+ end
22
+
23
+ def initialize role_players={}
24
+ @driver = role_players.delete(:driver) || MrDarcy.driver
25
+ @deferred = Deferred.new(driver: driver) {}
26
+ deferred.resolve nil
27
+
28
+ roles = self.class.roles
29
+ roles.each do |role_name, role|
30
+ player = role_players[role_name]
31
+ raise ArgumentError, "No role player for #{role_name} supplied" unless player
32
+
33
+ role.pollute(player)
34
+
35
+ self.singleton_class.send :define_method, role_name do
36
+ player
37
+ end
38
+ end
39
+ end
40
+
41
+ def then &block
42
+ deferred.then do |value|
43
+ self.instance_exec(value, &block)
44
+ end
45
+ self
46
+ end
47
+
48
+ def fail &block
49
+ deferred.fail do |value|
50
+ self.instance_exec(value, &block)
51
+ end
52
+ self
53
+ end
54
+
55
+ %w| result rejected? resolved? unresolved? |.map(&:to_sym).each do |method|
56
+ define_method method do
57
+ deferred.public_send method
58
+ end
59
+ end
60
+
61
+ def final
62
+ deferred.final
63
+ self
64
+ end
65
+
66
+ private
67
+
68
+ attr_accessor :deferred, :driver
69
+
70
+ end
71
+ end
@@ -0,0 +1,25 @@
1
+ module MrDarcy
2
+ class Deferred
3
+
4
+ attr_accessor :promise, :last_promise
5
+
6
+ %w| resolved? rejected? unresolved? resolve reject final result |.map(&:to_sym).each do |method|
7
+ define_method method do |*args|
8
+ promise.public_send method, *args
9
+ end
10
+ end
11
+
12
+ def then &block
13
+ self.last_promise = last_promise.then(&block)
14
+ end
15
+
16
+ def fail &block
17
+ self.last_promise = last_promise.fail(&block)
18
+ end
19
+
20
+ def initialize driver: MrDarcy.driver
21
+ self.promise = MrDarcy::Promise.new(driver: driver) {}
22
+ self.last_promise = promise
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ require 'celluloid/autostart'
2
+
3
+ module MrDarcy
4
+ module Drivers
5
+ module Celluloid
6
+ module_function
7
+
8
+ def dispatch(&block)
9
+ futures << ::Celluloid::Future.new(&block)
10
+ end
11
+
12
+ def wait
13
+ futures.each do |future|
14
+ future.value
15
+ end
16
+ end
17
+
18
+ def futures
19
+ @futures ||= []
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module MrDarcy
2
+ module Drivers
3
+ module Synchronous
4
+ module_function
5
+
6
+ def dispatch
7
+ yield
8
+ end
9
+
10
+ def wait
11
+ yield
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ require 'thread'
2
+
3
+ module MrDarcy
4
+ module Drivers
5
+ module Thread
6
+ module_function
7
+
8
+ def dispatch(&block)
9
+ @threads ||= []
10
+ @threads << ::Thread.new(&block)
11
+ end
12
+
13
+ def wait
14
+ @threads ||= []
15
+ @threads.each do |thread|
16
+ thread.join unless ::Thread.current == thread
17
+ end
18
+ yield
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module MrDarcy
2
+ module Drivers
3
+ autoload :Synchronous, File.expand_path('../drivers/synchronous.rb', __FILE__)
4
+ autoload :Thread, File.expand_path('../drivers/thread.rb', __FILE__)
5
+ autoload :Celluloid, File.expand_path('../drivers/celluloid.rb', __FILE__)
6
+
7
+ module_function
8
+
9
+ def all
10
+ [ Synchronous, Thread, Celluloid ]
11
+ end
12
+ end
13
+ end