mr_darcy 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +95 -0
- data/Guardfile +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +267 -0
- data/Rakefile +6 -0
- data/lib/mr_darcy/context.rb +71 -0
- data/lib/mr_darcy/deferred.rb +25 -0
- data/lib/mr_darcy/drivers/celluloid.rb +23 -0
- data/lib/mr_darcy/drivers/synchronous.rb +15 -0
- data/lib/mr_darcy/drivers/thread.rb +22 -0
- data/lib/mr_darcy/drivers.rb +13 -0
- data/lib/mr_darcy/promise/base.rb +117 -0
- data/lib/mr_darcy/promise/celluloid.rb +52 -0
- data/lib/mr_darcy/promise/child_promise.rb +83 -0
- data/lib/mr_darcy/promise/dsl.rb +29 -0
- data/lib/mr_darcy/promise/em.rb +29 -0
- data/lib/mr_darcy/promise/state/base.rb +43 -0
- data/lib/mr_darcy/promise/state/rejected.rb +11 -0
- data/lib/mr_darcy/promise/state/resolved.rb +11 -0
- data/lib/mr_darcy/promise/state/unresolved.rb +19 -0
- data/lib/mr_darcy/promise/state.rb +25 -0
- data/lib/mr_darcy/promise/synchronous.rb +27 -0
- data/lib/mr_darcy/promise/thread.rb +64 -0
- data/lib/mr_darcy/promise.rb +31 -0
- data/lib/mr_darcy/role.rb +45 -0
- data/lib/mr_darcy/version.rb +3 -0
- data/lib/mr_darcy.rb +26 -0
- data/mr_darcy.gemspec +29 -0
- data/spec/acceptance/dci_bank_transfer_spec.rb +62 -0
- data/spec/acceptance/em_http_request_spec.rb +22 -0
- data/spec/acceptance/open-uri_http_request_spec.rb +21 -0
- data/spec/acceptance/simple_promise_spec.rb +25 -0
- data/spec/acceptance/simple_promise_with_chained_fail.rb +25 -0
- data/spec/acceptance/simple_promise_with_fail_spec.rb +25 -0
- data/spec/acceptance/simple_promise_with_then_spec.rb +25 -0
- data/spec/lib/mr_darcy/context_spec.rb +22 -0
- data/spec/lib/mr_darcy/promise/base_spec.rb +197 -0
- data/spec/lib/mr_darcy/promise/child_promise_spec.rb +169 -0
- data/spec/lib/mr_darcy/promise/dsl_spec.rb +43 -0
- data/spec/lib/mr_darcy/promise/state/base_spec.rb +24 -0
- data/spec/lib/mr_darcy/promise/state/rejected_spec.rb +12 -0
- data/spec/lib/mr_darcy/promise/state/resolved_spec.rb +12 -0
- data/spec/lib/mr_darcy/promise/state/unresolved_spec.rb +22 -0
- data/spec/lib/mr_darcy/promise/state_spec.rb +30 -0
- data/spec/lib/mr_darcy/promise/synchronous_spec.rb +21 -0
- data/spec/lib/mr_darcy/promise_spec.rb +72 -0
- data/spec/lib/mr_darcy/role_spec.rb +89 -0
- data/spec/lib/mr_darcy_spec.rb +19 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/context_helpers.rb +19 -0
- data/spec/support/shared_examples_for_promise.rb +47 -0
- data/spec/support/shared_examples_for_thennable.rb +10 -0
- metadata +279 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
module MrDarcy
|
2
|
+
module Promise
|
3
|
+
class Base
|
4
|
+
|
5
|
+
def initialize block
|
6
|
+
state
|
7
|
+
schedule_promise do
|
8
|
+
evaluate_promise &block
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def then &block
|
13
|
+
@child_promise ||= generate_child_promise
|
14
|
+
child_promise.resolve_block = block
|
15
|
+
resolve_child_promise if resolved?
|
16
|
+
reject_child_promise if rejected?
|
17
|
+
child_promise.promise
|
18
|
+
end
|
19
|
+
|
20
|
+
def fail &block
|
21
|
+
@child_promise ||= generate_child_promise
|
22
|
+
child_promise.reject_block = block
|
23
|
+
resolve_child_promise if resolved?
|
24
|
+
reject_child_promise if rejected?
|
25
|
+
child_promise.promise
|
26
|
+
end
|
27
|
+
|
28
|
+
def result
|
29
|
+
Kernel::raise "Subclasses must implement me"
|
30
|
+
end
|
31
|
+
|
32
|
+
def final
|
33
|
+
Kernel::raise "Subclasses must implement me"
|
34
|
+
end
|
35
|
+
|
36
|
+
def raise
|
37
|
+
r = result
|
38
|
+
Kernel::raise r if rejected?
|
39
|
+
end
|
40
|
+
|
41
|
+
%w| resolved? unresolved? rejected? |.map(&:to_sym).each do |method|
|
42
|
+
define_method method do |*args|
|
43
|
+
state_machine.public_send(method, *args)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def resolve value
|
48
|
+
set_value_to value
|
49
|
+
state_machine_resolve
|
50
|
+
resolve_child_promise
|
51
|
+
end
|
52
|
+
|
53
|
+
def reject exception
|
54
|
+
set_value_to exception
|
55
|
+
state_machine_reject
|
56
|
+
reject_child_promise
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
attr_accessor :value, :child_promise, :state
|
62
|
+
|
63
|
+
def state
|
64
|
+
@state ||= :unresolved
|
65
|
+
end
|
66
|
+
|
67
|
+
def set_value_to value
|
68
|
+
@value = value
|
69
|
+
end
|
70
|
+
|
71
|
+
def state_machine_resolve
|
72
|
+
state_machine.resolve
|
73
|
+
end
|
74
|
+
|
75
|
+
def state_machine_reject
|
76
|
+
state_machine.reject
|
77
|
+
end
|
78
|
+
|
79
|
+
def state_machine
|
80
|
+
State.state(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
def has_child_promise?
|
84
|
+
!!child_promise
|
85
|
+
end
|
86
|
+
|
87
|
+
def resolve_child_promise
|
88
|
+
schedule_promise do
|
89
|
+
child_promise.parent_resolved(value) if has_child_promise?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def reject_child_promise
|
94
|
+
schedule_promise do
|
95
|
+
child_promise.parent_rejected(value) if has_child_promise?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def schedule_promise
|
100
|
+
Kernel::raise "Subclasses must implement me"
|
101
|
+
end
|
102
|
+
|
103
|
+
def evaluate_promise &block
|
104
|
+
begin
|
105
|
+
block.call DSL.new(self)
|
106
|
+
rescue Exception => e
|
107
|
+
reject e
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def generate_child_promise
|
112
|
+
Kernel::raise "Subclasses must implement me"
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'celluloid/autostart'
|
2
|
+
|
3
|
+
module MrDarcy
|
4
|
+
module Promise
|
5
|
+
class Celluloid < Base
|
6
|
+
|
7
|
+
def initialize *args
|
8
|
+
@waiting = false
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def resolve value
|
13
|
+
super
|
14
|
+
condition.signal if @waiting
|
15
|
+
end
|
16
|
+
|
17
|
+
def reject exception
|
18
|
+
super
|
19
|
+
condition.signal if @waiting
|
20
|
+
end
|
21
|
+
|
22
|
+
def result
|
23
|
+
wait_until_not_unresolved
|
24
|
+
value
|
25
|
+
end
|
26
|
+
|
27
|
+
def final
|
28
|
+
wait_until_not_unresolved
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def schedule_promise &block
|
35
|
+
::Celluloid::Future.new &block
|
36
|
+
end
|
37
|
+
|
38
|
+
def condition
|
39
|
+
@condition ||= ::Celluloid::Condition.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def wait_until_not_unresolved
|
43
|
+
@waiting = true
|
44
|
+
condition.wait if unresolved?
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_child_promise
|
48
|
+
ChildPromise.new driver: :thread
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module MrDarcy
|
2
|
+
module Promise
|
3
|
+
class ChildPromise < MrDarcy::Deferred
|
4
|
+
|
5
|
+
attr_accessor :resolve_block, :reject_block
|
6
|
+
|
7
|
+
def initialize opts={}
|
8
|
+
@driver = opts[:driver] if opts.has_key? :driver
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def parent_resolved value
|
13
|
+
begin
|
14
|
+
return resolve_with value unless handles_resolve?
|
15
|
+
new_value = result_for :resolve, value
|
16
|
+
if thenable? new_value
|
17
|
+
defer_resolution_via new_value
|
18
|
+
else
|
19
|
+
resolve_with new_value
|
20
|
+
end
|
21
|
+
rescue Exception => e
|
22
|
+
reject_with e
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def parent_rejected value
|
27
|
+
begin
|
28
|
+
return reject_with value unless handles_reject?
|
29
|
+
new_value = result_for :reject, value
|
30
|
+
if thenable? new_value
|
31
|
+
defer_resolution_via new_value
|
32
|
+
else
|
33
|
+
resolve_with new_value
|
34
|
+
end
|
35
|
+
rescue Exception => e
|
36
|
+
reject_with e
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def result_for which, value
|
43
|
+
block = public_send("#{which}_block")
|
44
|
+
if block
|
45
|
+
block.call value
|
46
|
+
else
|
47
|
+
value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def handles_reject?
|
52
|
+
!!reject_block
|
53
|
+
end
|
54
|
+
|
55
|
+
def handles_resolve?
|
56
|
+
!!resolve_block
|
57
|
+
end
|
58
|
+
|
59
|
+
def thenable? object
|
60
|
+
object.respond_to?(:then) && object.respond_to?(:fail)
|
61
|
+
end
|
62
|
+
|
63
|
+
def defer_resolution_via child_promise
|
64
|
+
child_promise.then do |value|
|
65
|
+
resolve_with value
|
66
|
+
value
|
67
|
+
end
|
68
|
+
child_promise.fail do |exception|
|
69
|
+
reject_with exception
|
70
|
+
exception
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def resolve_with value
|
75
|
+
promise.resolve value
|
76
|
+
end
|
77
|
+
|
78
|
+
def reject_with exception
|
79
|
+
promise.reject exception
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module MrDarcy
|
2
|
+
module Promise
|
3
|
+
class DSL
|
4
|
+
|
5
|
+
def initialize promise
|
6
|
+
@promise = promise
|
7
|
+
end
|
8
|
+
|
9
|
+
def resolve(value)
|
10
|
+
promise.resolve value
|
11
|
+
end
|
12
|
+
|
13
|
+
def reject(exception)
|
14
|
+
promise.reject exception
|
15
|
+
end
|
16
|
+
|
17
|
+
%w| unresolved? resolved? rejected? then fail result final |.map(&:to_sym).each do |method|
|
18
|
+
define_method method do |*args|
|
19
|
+
promise.public_send method, *args
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_accessor :promise
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
|
3
|
+
module MrDarcy
|
4
|
+
module Promise
|
5
|
+
class EM < Thread
|
6
|
+
|
7
|
+
def initialize *args
|
8
|
+
unless EventMachine.reactor_running?
|
9
|
+
::Thread.new { EventMachine.run }
|
10
|
+
::Thread.pass until EventMachine.reactor_running?
|
11
|
+
end
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def schedule_promise
|
18
|
+
EventMachine.schedule proc do
|
19
|
+
yield
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate_child_promise
|
24
|
+
ChildPromise.new driver: :em
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module MrDarcy
|
2
|
+
module Promise
|
3
|
+
module State
|
4
|
+
class Base
|
5
|
+
attr_accessor :stateful
|
6
|
+
|
7
|
+
def initialize stateful
|
8
|
+
self.stateful = stateful
|
9
|
+
end
|
10
|
+
|
11
|
+
def unresolved?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def resolved?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def rejected?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
def resolve
|
24
|
+
raise "Can't resolve from #{get_state} state"
|
25
|
+
end
|
26
|
+
|
27
|
+
def reject
|
28
|
+
raise "Cant reject from #{get_state} state"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def get_state
|
34
|
+
stateful.send :state
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_state state
|
38
|
+
stateful.send :state=, state
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MrDarcy
|
2
|
+
module Promise
|
3
|
+
module State
|
4
|
+
autoload :Base, File.expand_path('../state/base', __FILE__)
|
5
|
+
autoload :Unresolved, File.expand_path('../state/unresolved', __FILE__)
|
6
|
+
autoload :Resolved, File.expand_path('../state/resolved', __FILE__)
|
7
|
+
autoload :Rejected, File.expand_path('../state/rejected', __FILE__)
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def state stateful
|
12
|
+
case stateful.send :state
|
13
|
+
when :unresolved
|
14
|
+
Unresolved.new stateful
|
15
|
+
when :resolved
|
16
|
+
Resolved.new stateful
|
17
|
+
when :rejected
|
18
|
+
Rejected.new stateful
|
19
|
+
else
|
20
|
+
raise "Unknown state #{stateful.state}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# This class implements a synchronous interface to promise execution.
|
2
|
+
# It's not much use, except for unit testing.
|
3
|
+
|
4
|
+
module MrDarcy
|
5
|
+
module Promise
|
6
|
+
class Synchronous < Base
|
7
|
+
|
8
|
+
def result
|
9
|
+
value
|
10
|
+
end
|
11
|
+
|
12
|
+
def final
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def schedule_promise
|
19
|
+
yield
|
20
|
+
end
|
21
|
+
|
22
|
+
def generate_child_promise
|
23
|
+
ChildPromise.new driver: :synchronous
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module MrDarcy
|
2
|
+
module Promise
|
3
|
+
class Thread < Base
|
4
|
+
|
5
|
+
def initialize *args
|
6
|
+
@wait_lock = Mutex.new
|
7
|
+
@wait_cond = ConditionVariable.new
|
8
|
+
@wait_lock.lock
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def result
|
13
|
+
wait_if_unresolved
|
14
|
+
value
|
15
|
+
end
|
16
|
+
|
17
|
+
def final
|
18
|
+
wait_if_unresolved
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def resolve value
|
23
|
+
super
|
24
|
+
@wait_cond.signal
|
25
|
+
end
|
26
|
+
|
27
|
+
def reject value
|
28
|
+
super
|
29
|
+
@wait_cond.signal
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def schedule_promise &block
|
35
|
+
::Thread.new &block
|
36
|
+
end
|
37
|
+
|
38
|
+
def wait_if_unresolved
|
39
|
+
@wait_cond.wait @wait_lock if unresolved?
|
40
|
+
end
|
41
|
+
|
42
|
+
def semaphore
|
43
|
+
@semaphore ||= Mutex.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_child_promise
|
47
|
+
ChildPromise.new driver: :thread
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_value_to value
|
51
|
+
semaphore.synchronize { super }
|
52
|
+
end
|
53
|
+
|
54
|
+
def state_machine_resolve
|
55
|
+
semaphore.synchronize { super }
|
56
|
+
end
|
57
|
+
|
58
|
+
def state_machine_reject
|
59
|
+
semaphore.synchronize { super }
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module MrDarcy
|
2
|
+
module Promise
|
3
|
+
autoload :State, File.expand_path('../promise/state', __FILE__)
|
4
|
+
autoload :Base, File.expand_path('../promise/base', __FILE__)
|
5
|
+
autoload :DSL, File.expand_path('../promise/dsl', __FILE__)
|
6
|
+
autoload :ChildPromise, File.expand_path('../promise/child_promise', __FILE__)
|
7
|
+
|
8
|
+
autoload :Synchronous, File.expand_path('../promise/synchronous', __FILE__)
|
9
|
+
autoload :Thread, File.expand_path('../promise/thread', __FILE__)
|
10
|
+
autoload :Celluloid, File.expand_path('../promise/celluloid', __FILE__)
|
11
|
+
autoload :EM, File.expand_path('../promise/em', __FILE__)
|
12
|
+
|
13
|
+
module_function
|
14
|
+
|
15
|
+
def new driver: ::MrDarcy.driver, &block
|
16
|
+
case driver
|
17
|
+
when :thread, :Thread
|
18
|
+
::MrDarcy::Promise::Thread.new block
|
19
|
+
when :synchronous, :Synchronous
|
20
|
+
::MrDarcy::Promise::Synchronous.new block
|
21
|
+
when :celluloid, :Celluloid
|
22
|
+
::MrDarcy::Promise::Celluloid.new block
|
23
|
+
when :em, :EM, :event_machine, :eventmachine, :EventMachine
|
24
|
+
::MrDarcy::Promise::EM.new block
|
25
|
+
else
|
26
|
+
raise "Unknown driver #{driver}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module MrDarcy
|
2
|
+
class Role
|
3
|
+
attr_accessor :name, :options
|
4
|
+
|
5
|
+
def initialize name, opts={}, &block
|
6
|
+
self.name = name
|
7
|
+
self.options = opts
|
8
|
+
@module = Module.new(&block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def pollute player
|
12
|
+
guard_against_false_players player
|
13
|
+
|
14
|
+
@module.instance_methods.each do |method_name|
|
15
|
+
implementation = @module.instance_method method_name
|
16
|
+
player.define_singleton_method method_name, implementation
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def clean player
|
21
|
+
@module.instance_methods.each do |method_name|
|
22
|
+
player.singleton_class.send :remove_method, method_name if player.respond_to? method_name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def guard_against_false_players player
|
29
|
+
options.each do |test_type, values|
|
30
|
+
case test_type
|
31
|
+
when :must_respond_to
|
32
|
+
Array(values).each do |method_name|
|
33
|
+
raise ArgumentError, "player must implement #{method_name}" unless player.respond_to? method_name
|
34
|
+
end
|
35
|
+
when :must_not_respond_to
|
36
|
+
Array(values).each do |method_name|
|
37
|
+
raise ArgumentError, "player must not implement #{method_name}" if player.respond_to? method_name
|
38
|
+
end
|
39
|
+
else
|
40
|
+
raise ArgumentError, "unknown restriction #{test_type}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/mr_darcy.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "mr_darcy/version"
|
2
|
+
require "mr_darcy/role"
|
3
|
+
require "mr_darcy/context"
|
4
|
+
require "mr_darcy/deferred"
|
5
|
+
require "mr_darcy/promise"
|
6
|
+
|
7
|
+
module MrDarcy
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def driver=(driver)
|
12
|
+
@driver=driver
|
13
|
+
end
|
14
|
+
|
15
|
+
def driver
|
16
|
+
@driver ||= :Thread
|
17
|
+
end
|
18
|
+
|
19
|
+
def all_drivers
|
20
|
+
%w| synchronous thread celluloid em |.map(&:to_sym)
|
21
|
+
end
|
22
|
+
|
23
|
+
def promise driver: driver, &block
|
24
|
+
MrDarcy::Promise.new driver: driver, &block
|
25
|
+
end
|
26
|
+
end
|
data/mr_darcy.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'mr_darcy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "mr_darcy"
|
8
|
+
spec.version = MrDarcy::VERSION
|
9
|
+
spec.authors = ["James Harton"]
|
10
|
+
spec.email = ["james@resistor.io"]
|
11
|
+
spec.summary = %q{A mashup of async Promises and DCI in Ruby.}
|
12
|
+
spec.description = <<-EOF
|
13
|
+
MrDarcy takes async promises from the javascript word, DCI from Jim
|
14
|
+
Gay's brain and sprinkles some ruby on top for great justice!
|
15
|
+
EOF
|
16
|
+
spec.homepage = "https://github.com/jamesotron/MrDarcy"
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0")
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
25
|
+
%w| rake rspec guard guard-rspec guard-bundler terminal-notifier-guard
|
26
|
+
pry eventmachine em-http-request celluloid |.each do |gem|
|
27
|
+
spec.add_development_dependency gem
|
28
|
+
end
|
29
|
+
end
|