mr_darcy 0.1.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 (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