mr_darcy 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/lib/mr_darcy.rb +8 -2
- data/lib/mr_darcy/context.rb +1 -1
- data/lib/mr_darcy/deferred.rb +3 -2
- data/lib/mr_darcy/promise.rb +2 -1
- data/lib/mr_darcy/promise/base.rb +54 -18
- data/lib/mr_darcy/promise/celluloid.rb +76 -16
- data/lib/mr_darcy/promise/child_promise.rb +24 -19
- data/lib/mr_darcy/promise/em.rb +56 -5
- data/lib/mr_darcy/promise/state/base.rb +2 -2
- data/lib/mr_darcy/promise/thread.rb +38 -19
- data/lib/mr_darcy/role.rb +26 -6
- data/lib/mr_darcy/version.rb +1 -1
- data/spec/acceptance/dci_bank_transfer_spec.rb +12 -16
- data/spec/acceptance/em_http_request_spec.rb +20 -17
- data/spec/acceptance/simple_promise_with_fail_spec.rb +2 -2
- data/spec/lib/mr_darcy/promise/base_spec.rb +1 -1
- data/spec/lib/mr_darcy/promise/child_promise_spec.rb +23 -27
- data/spec/lib/mr_darcy/promise/em_spec.rb +20 -0
- data/spec/lib/mr_darcy/promise_spec.rb +35 -11
- data/spec/lib/mr_darcy/role_spec.rb +1 -1
- data/spec/lib/mr_darcy_spec.rb +20 -0
- metadata +46 -44
@@ -21,11 +21,11 @@ module MrDarcy
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def resolve
|
24
|
-
raise "Can't resolve from #{get_state} state"
|
24
|
+
raise RuntimeError, "Can't resolve from #{get_state} state"
|
25
25
|
end
|
26
26
|
|
27
27
|
def reject
|
28
|
-
raise "Cant reject from #{get_state} state"
|
28
|
+
raise RuntimeError, "Cant reject from #{get_state} state"
|
29
29
|
end
|
30
30
|
|
31
31
|
private
|
@@ -1,11 +1,13 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'fiber'
|
3
|
+
|
1
4
|
module MrDarcy
|
2
5
|
module Promise
|
3
6
|
class Thread < Base
|
4
7
|
|
5
8
|
def initialize *args
|
6
|
-
@
|
7
|
-
@
|
8
|
-
@wait_lock.lock
|
9
|
+
@semaphore = Mutex.new
|
10
|
+
semaphore.synchronize { @complete = false }
|
9
11
|
super
|
10
12
|
end
|
11
13
|
|
@@ -19,43 +21,60 @@ module MrDarcy
|
|
19
21
|
self
|
20
22
|
end
|
21
23
|
|
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
24
|
private
|
33
25
|
|
34
26
|
def schedule_promise &block
|
35
27
|
::Thread.new &block
|
36
28
|
end
|
37
29
|
|
38
|
-
def
|
39
|
-
|
30
|
+
def did_resolve value
|
31
|
+
complete!
|
40
32
|
end
|
41
33
|
|
42
|
-
def
|
43
|
-
|
34
|
+
def did_reject value
|
35
|
+
complete!
|
36
|
+
end
|
37
|
+
|
38
|
+
def wait_if_unresolved
|
39
|
+
return if complete?
|
40
|
+
semaphore.synchronize do
|
41
|
+
@wait = ConditionVariable.new
|
42
|
+
@wait.wait(semaphore)
|
43
|
+
end
|
44
44
|
end
|
45
45
|
|
46
46
|
def generate_child_promise
|
47
47
|
ChildPromise.new driver: :thread
|
48
48
|
end
|
49
49
|
|
50
|
+
def complete?
|
51
|
+
semaphore.synchronize { @complete }
|
52
|
+
end
|
53
|
+
|
54
|
+
def complete!
|
55
|
+
semaphore.synchronize do
|
56
|
+
@complete = true
|
57
|
+
@wait.broadcast if @wait
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def semaphore
|
62
|
+
@semaphore
|
63
|
+
end
|
64
|
+
|
50
65
|
def set_value_to value
|
51
66
|
semaphore.synchronize { super }
|
52
67
|
end
|
53
68
|
|
54
|
-
def
|
69
|
+
def state_machine
|
70
|
+
semaphore.synchronize { super }
|
71
|
+
end
|
72
|
+
|
73
|
+
def child_promise
|
55
74
|
semaphore.synchronize { super }
|
56
75
|
end
|
57
76
|
|
58
|
-
def
|
77
|
+
def value
|
59
78
|
semaphore.synchronize { super }
|
60
79
|
end
|
61
80
|
|
data/lib/mr_darcy/role.rb
CHANGED
@@ -11,20 +11,23 @@ module MrDarcy
|
|
11
11
|
def pollute player
|
12
12
|
guard_against_false_players player
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
if jruby?
|
15
|
+
pollute_with_module_extension player
|
16
|
+
else
|
17
|
+
pollute_with_singleton_methods player
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
21
|
def clean player
|
21
|
-
|
22
|
-
player.singleton_class.send :remove_method, method_name if player.respond_to? method_name
|
23
|
-
end
|
22
|
+
clean_singleton_methods player unless jruby?
|
24
23
|
end
|
25
24
|
|
26
25
|
private
|
27
26
|
|
27
|
+
def jruby?
|
28
|
+
RUBY_ENGINE == 'jruby'
|
29
|
+
end
|
30
|
+
|
28
31
|
def guard_against_false_players player
|
29
32
|
options.each do |test_type, values|
|
30
33
|
case test_type
|
@@ -41,5 +44,22 @@ module MrDarcy
|
|
41
44
|
end
|
42
45
|
end
|
43
46
|
end
|
47
|
+
|
48
|
+
def pollute_with_module_extension player
|
49
|
+
player.send :extend, @module
|
50
|
+
end
|
51
|
+
|
52
|
+
def pollute_with_singleton_methods player
|
53
|
+
@module.instance_methods.each do |method_name|
|
54
|
+
implementation = @module.instance_method method_name
|
55
|
+
player.define_singleton_method method_name, implementation
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def clean_singleton_methods player
|
60
|
+
@module.instance_methods.each do |method_name|
|
61
|
+
player.singleton_class.send :remove_method, method_name if player.respond_to? method_name
|
62
|
+
end
|
63
|
+
end
|
44
64
|
end
|
45
65
|
end
|
data/lib/mr_darcy/version.rb
CHANGED
@@ -22,7 +22,7 @@ class BankTransfer < MrDarcy::Context
|
|
22
22
|
money_source.subtract_funds amount
|
23
23
|
money_destination.receive_funds amount
|
24
24
|
else
|
25
|
-
raise "insufficient funds"
|
25
|
+
raise RuntimeError, "insufficient funds"
|
26
26
|
end
|
27
27
|
amount
|
28
28
|
end
|
@@ -35,28 +35,24 @@ describe 'DCI Bank Transfer' do
|
|
35
35
|
let(:money_destination) { Account.new destination_balance }
|
36
36
|
|
37
37
|
MrDarcy.all_drivers.each do |driver|
|
38
|
-
|
39
|
-
|
40
|
-
let(:context) { BankTransfer.new money_source: money_source, money_destination: money_destination, driver: driver }
|
38
|
+
describe "Driver #{driver}" do
|
39
|
+
let(:context) { BankTransfer.new money_source: money_source, money_destination: money_destination, driver: driver }
|
41
40
|
|
42
|
-
|
43
|
-
|
41
|
+
When 'the source balance is 10' do
|
42
|
+
let(:source_balance) { 10 }
|
44
43
|
|
45
|
-
|
46
|
-
|
44
|
+
And 'the destination balance is 5' do
|
45
|
+
let(:destination_balance) { 5 }
|
47
46
|
|
48
|
-
|
49
|
-
|
47
|
+
When 'I transfer 8' do
|
48
|
+
subject { context.transfer(8).final }
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
50
|
+
its('money_source.available_balance') { should eq 2 }
|
51
|
+
its('money_destination.available_balance') { should eq 13 }
|
52
|
+
its(:result) { should eq 8 }
|
55
53
|
end
|
56
54
|
end
|
57
55
|
end
|
58
|
-
else
|
59
|
-
pending "not working with driver #{driver} :("
|
60
56
|
end
|
61
57
|
end
|
62
58
|
end
|
@@ -1,22 +1,25 @@
|
|
1
|
-
|
2
|
-
require '
|
3
|
-
require '
|
1
|
+
unless RUBY_ENGINE=='jruby'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'em-http-request'
|
4
5
|
|
5
|
-
describe "Wrapping em-http-request" do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
describe "Wrapping em-http-request" do
|
7
|
+
let(:promise) do
|
8
|
+
MrDarcy::Promise.new driver: :em do |p|
|
9
|
+
http = EM::HttpRequest.new('http://camp.ruby.org.nz/').get
|
10
|
+
http.errback do
|
11
|
+
p.reject http.error
|
12
|
+
end
|
13
|
+
http.callback do
|
14
|
+
p.resolve http.response
|
15
|
+
end
|
16
|
+
end.final
|
15
17
|
end
|
16
|
-
end
|
17
18
|
|
18
|
-
|
19
|
+
subject { promise }
|
20
|
+
|
21
|
+
it_should_behave_like 'a resolved promise'
|
22
|
+
its(:result) { should match /Rails Camp NZ/i }
|
23
|
+
end
|
19
24
|
|
20
|
-
it_should_behave_like 'a resolved promise'
|
21
|
-
its(:result) { should match /Rails Camp NZ/i }
|
22
25
|
end
|
@@ -4,8 +4,8 @@ describe "Promise with fail" do
|
|
4
4
|
|
5
5
|
MrDarcy.all_drivers.each do |driver|
|
6
6
|
describe "with driver #{driver}" do
|
7
|
-
let(:promise) { MrDarcy::Promise.new(driver: driver, &promise_block)
|
8
|
-
subject { promise }
|
7
|
+
let(:promise) { MrDarcy::Promise.new(driver: driver, &promise_block) }
|
8
|
+
subject { promise.fail { |v| v+1 } }
|
9
9
|
|
10
10
|
When 'the promise resolves' do
|
11
11
|
let(:promise_block) { proc { |p| p.resolve 1 } }
|
@@ -73,7 +73,7 @@ describe MrDarcy::Promise::Base do
|
|
73
73
|
before { mock_promise.reject :bad }
|
74
74
|
|
75
75
|
When 'the fail block re-fails' do
|
76
|
-
let(:fail_block) { proc { raise :bad } }
|
76
|
+
let(:fail_block) { proc { raise RuntimeError, :bad } }
|
77
77
|
|
78
78
|
it_behaves_like 'a rejected promise'
|
79
79
|
end
|
@@ -4,8 +4,6 @@ describe MrDarcy::Promise::ChildPromise do
|
|
4
4
|
let(:child_promise) { MrDarcy::Promise::ChildPromise.new driver: :Synchronous }
|
5
5
|
subject { child_promise }
|
6
6
|
|
7
|
-
it { should be_a MrDarcy::Deferred }
|
8
|
-
|
9
7
|
it { should respond_to :resolve_block }
|
10
8
|
it { should respond_to :reject_block }
|
11
9
|
|
@@ -26,37 +24,36 @@ describe MrDarcy::Promise::ChildPromise do
|
|
26
24
|
let(:resolve_block) { proc { :new_value } }
|
27
25
|
|
28
26
|
it 'resolves' do
|
29
|
-
expect { subject }.to change { child_promise.resolved? }.from(false).to(true)
|
27
|
+
expect { subject }.to change { child_promise.promise.resolved? }.from(false).to(true)
|
30
28
|
end
|
31
29
|
|
32
30
|
it 'sets the new value' do
|
33
|
-
expect { subject }.to change { child_promise.result }.to(:new_value)
|
31
|
+
expect { subject }.to change { child_promise.promise.result }.to(:new_value)
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
When 'the resolve block returns a new promise' do
|
38
|
-
let(:
|
39
|
-
let(:promise) { MrDarcy::Promise::Synchronous.new promise_block }
|
36
|
+
let(:promise) { MrDarcy::Promise::Synchronous.new proc {} }
|
40
37
|
let(:resolve_block) { proc { promise } }
|
41
38
|
|
42
39
|
it 'doesn\'t resolve' do
|
43
|
-
expect { subject }.not_to change { child_promise.resolved? }
|
40
|
+
expect { subject }.not_to change { child_promise.promise.resolved? }
|
44
41
|
end
|
45
42
|
|
46
43
|
it 'doesn\'t set the value' do
|
47
|
-
expect { subject }.not_to change { child_promise.result }
|
44
|
+
expect { subject }.not_to change { child_promise.promise.result }
|
48
45
|
end
|
49
46
|
|
50
47
|
When 'the promise eventually resolves' do
|
51
|
-
before
|
48
|
+
before { child_promise.parent_resolved resolve_value }
|
52
49
|
subject { promise.resolve :mr_good_stuff }
|
53
50
|
|
54
51
|
it 'resolves' do
|
55
|
-
expect { subject }.to change{ child_promise.resolved? }.from(false).to(true)
|
52
|
+
expect { subject }.to change{ child_promise.promise.resolved? }.from(false).to(true)
|
56
53
|
end
|
57
54
|
|
58
55
|
it 'has the new value' do
|
59
|
-
expect { subject }.to change { child_promise.result }.to(:mr_good_stuff)
|
56
|
+
expect { subject }.to change { child_promise.promise.result }.to(:mr_good_stuff)
|
60
57
|
end
|
61
58
|
end
|
62
59
|
|
@@ -65,11 +62,11 @@ describe MrDarcy::Promise::ChildPromise do
|
|
65
62
|
subject { promise.reject :mr_bad_stuff }
|
66
63
|
|
67
64
|
it 'rejects' do
|
68
|
-
expect { subject }.to change{ child_promise.rejected? }.from(false).to(true)
|
65
|
+
expect { subject }.to change{ child_promise.promise.rejected? }.from(false).to(true)
|
69
66
|
end
|
70
67
|
|
71
68
|
it 'has the new value' do
|
72
|
-
expect { subject }.to change { child_promise.result }.to(:mr_bad_stuff)
|
69
|
+
expect { subject }.to change { child_promise.promise.result }.to(:mr_bad_stuff)
|
73
70
|
end
|
74
71
|
end
|
75
72
|
end
|
@@ -78,12 +75,12 @@ describe MrDarcy::Promise::ChildPromise do
|
|
78
75
|
Otherwise do
|
79
76
|
it 'is resolved' do
|
80
77
|
subject
|
81
|
-
expect(child_promise).to be_resolved
|
78
|
+
expect(child_promise.promise).to be_resolved
|
82
79
|
end
|
83
80
|
|
84
81
|
it 'is resolved with the supplied value' do
|
85
82
|
subject
|
86
|
-
expect(child_promise.result).to eq(resolve_value)
|
83
|
+
expect(child_promise.promise.result).to eq(resolve_value)
|
87
84
|
end
|
88
85
|
end
|
89
86
|
end
|
@@ -105,25 +102,24 @@ describe MrDarcy::Promise::ChildPromise do
|
|
105
102
|
let(:reject_block) { proc { :new_value } }
|
106
103
|
|
107
104
|
it 'resolves' do
|
108
|
-
expect { subject }.to change { child_promise.resolved? }.from(false).to(true)
|
105
|
+
expect { subject }.to change { child_promise.promise.resolved? }.from(false).to(true)
|
109
106
|
end
|
110
107
|
|
111
108
|
it 'sets the new value' do
|
112
|
-
expect { subject }.to change { child_promise.result }.to(:new_value)
|
109
|
+
expect { subject }.to change { child_promise.promise.result }.to(:new_value)
|
113
110
|
end
|
114
111
|
end
|
115
112
|
|
116
113
|
When 'the reject block returns a new promise' do
|
117
|
-
let(:
|
118
|
-
let(:promise) { MrDarcy::Promise::Synchronous.new promise_block }
|
114
|
+
let(:promise) { MrDarcy::Promise::Synchronous.new proc {} }
|
119
115
|
let(:reject_block) { proc { promise } }
|
120
116
|
|
121
117
|
it 'doesn\'t reject' do
|
122
|
-
expect { subject }.not_to change { child_promise.rejected? }
|
118
|
+
expect { subject }.not_to change { child_promise.promise.rejected? }
|
123
119
|
end
|
124
120
|
|
125
121
|
it 'doesn\'t set the value' do
|
126
|
-
expect { subject }.not_to change { child_promise.result }
|
122
|
+
expect { subject }.not_to change { child_promise.promise.result }
|
127
123
|
end
|
128
124
|
|
129
125
|
When 'the promise eventually resolves' do
|
@@ -131,11 +127,11 @@ describe MrDarcy::Promise::ChildPromise do
|
|
131
127
|
subject { promise.resolve :mr_good_stuff }
|
132
128
|
|
133
129
|
it 'resolves' do
|
134
|
-
expect { subject }.to change{ child_promise.resolved? }.from(false).to(true)
|
130
|
+
expect { subject }.to change{ child_promise.promise.resolved? }.from(false).to(true)
|
135
131
|
end
|
136
132
|
|
137
133
|
it 'has the new value' do
|
138
|
-
expect { subject }.to change { child_promise.result }.to(:mr_good_stuff)
|
134
|
+
expect { subject }.to change { child_promise.promise.result }.to(:mr_good_stuff)
|
139
135
|
end
|
140
136
|
end
|
141
137
|
|
@@ -144,11 +140,11 @@ describe MrDarcy::Promise::ChildPromise do
|
|
144
140
|
subject { promise.reject :mr_bad_stuff }
|
145
141
|
|
146
142
|
it 'rejects' do
|
147
|
-
expect { subject }.to change{ child_promise.rejected? }.from(false).to(true)
|
143
|
+
expect { subject }.to change{ child_promise.promise.rejected? }.from(false).to(true)
|
148
144
|
end
|
149
145
|
|
150
146
|
it 'has the new value' do
|
151
|
-
expect { subject }.to change { child_promise.result }.to(:mr_bad_stuff)
|
147
|
+
expect { subject }.to change { child_promise.promise.result }.to(:mr_bad_stuff)
|
152
148
|
end
|
153
149
|
end
|
154
150
|
end
|
@@ -157,12 +153,12 @@ describe MrDarcy::Promise::ChildPromise do
|
|
157
153
|
Otherwise do
|
158
154
|
it 'is rejected' do
|
159
155
|
subject
|
160
|
-
expect(child_promise).to be_rejected
|
156
|
+
expect(child_promise.promise).to be_rejected
|
161
157
|
end
|
162
158
|
|
163
159
|
it 'is rejected with the supplied value' do
|
164
160
|
subject
|
165
|
-
expect(child_promise.result).to eq(reject_value)
|
161
|
+
expect(child_promise.promise.result).to eq(reject_value)
|
166
162
|
end
|
167
163
|
end
|
168
164
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MrDarcy::Promise::EM do
|
4
|
+
describe '#initialize' do
|
5
|
+
describe 'JRuby warning' do
|
6
|
+
subject { -> { MrDarcy::Promise::EM.new proc {} } }
|
7
|
+
|
8
|
+
When 'running on jruby' do
|
9
|
+
before { stub_const 'RUBY_ENGINE', 'jruby' }
|
10
|
+
|
11
|
+
it { should raise_error }
|
12
|
+
end
|
13
|
+
|
14
|
+
Otherwise do
|
15
|
+
it { should_not raise_error }
|
16
|
+
end unless RUBY_ENGINE == 'jruby'
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|