mr_darcy 0.1.0 → 0.2.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.
- 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
|