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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 200c16f28a04c2608e104d084400e44c55f84e78
4
- data.tar.gz: 2c4132617b62c2713cedcc37d560c55a180e6251
3
+ metadata.gz: 76e4be46dc9cdd1c3940172e1fd429cb9ca06d1e
4
+ data.tar.gz: c8f1944c3cf626b51599edf3337a66bc146969c6
5
5
  SHA512:
6
- metadata.gz: baa8c75ad0f00c458e6610b389a52b29d345b705d02f71ca845a8df4297deb31c3c7c5b6b556ef3338b179a807f8e5f53121308d30eb0111f045bdbf6f1bd044
7
- data.tar.gz: c73abc19ded59554f375cbf4e34a74fa946e114d2a34d90711e568f0b47179b5535675fb6448614706024108b33ef27cc41f701347a086d9943bf4476a0970e6
6
+ metadata.gz: 37ea3db8c56a22d1f78ab6f004c06e4b4f96e98f5fb95a8824fd2adc7491c40fa957546008c8d98bfdd7899739b9d2df29e2cd48e4d51da966305dc756dc95aa
7
+ data.tar.gz: 3fdde3baecf7aa7fcb3a1b925084b09be2b742a405326344c83b644b9b4c21812b557ae17a3a3a0dfbdf4f8db1656dfb4ecd6016cf10c939667ad7da71dadf7e
data/.travis.yml CHANGED
@@ -1,7 +1,6 @@
1
1
  rvm:
2
2
  - 2.1.1
3
- - 2.1.0
4
3
  - 2.0.0
5
- - jruby-20mode
4
+ - jruby
6
5
  - rbx
7
6
 
data/lib/mr_darcy.rb CHANGED
@@ -17,10 +17,16 @@ module MrDarcy
17
17
  end
18
18
 
19
19
  def all_drivers
20
- %w| synchronous thread celluloid em |.map(&:to_sym)
20
+ drivers = %w| synchronous thread celluloid em |.map(&:to_sym)
21
+
22
+ drivers.delete :em if RUBY_ENGINE=='jruby'
23
+
24
+ drivers
21
25
  end
22
26
 
23
- def promise driver: driver, &block
27
+ def promise opts={}, &block
28
+ driver = opts[:driver] || self.driver
24
29
  MrDarcy::Promise.new driver: driver, &block
25
30
  end
31
+
26
32
  end
@@ -28,7 +28,7 @@ module MrDarcy
28
28
  roles = self.class.roles
29
29
  roles.each do |role_name, role|
30
30
  player = role_players[role_name]
31
- raise ArgumentError, "No role player for #{role_name} supplied" unless player
31
+ Kernel::raise ArgumentError, "No role player for #{role_name} supplied" unless player
32
32
 
33
33
  role.pollute(player)
34
34
 
@@ -5,7 +5,7 @@ module MrDarcy
5
5
 
6
6
  %w| resolved? rejected? unresolved? resolve reject final result |.map(&:to_sym).each do |method|
7
7
  define_method method do |*args|
8
- promise.public_send method, *args
8
+ last_promise.public_send method, *args
9
9
  end
10
10
  end
11
11
 
@@ -17,7 +17,8 @@ module MrDarcy
17
17
  self.last_promise = last_promise.fail(&block)
18
18
  end
19
19
 
20
- def initialize driver: MrDarcy.driver
20
+ def initialize opts={}
21
+ driver = opts[:driver] || MrDarcy.driver
21
22
  self.promise = MrDarcy::Promise.new(driver: driver) {}
22
23
  self.last_promise = promise
23
24
  end
@@ -12,7 +12,8 @@ module MrDarcy
12
12
 
13
13
  module_function
14
14
 
15
- def new driver: ::MrDarcy.driver, &block
15
+ def new opts={}, &block
16
+ driver = opts[:driver] || ::MrDarcy.driver
16
17
  case driver
17
18
  when :thread, :Thread
18
19
  ::MrDarcy::Promise::Thread.new block
@@ -7,21 +7,20 @@ module MrDarcy
7
7
  schedule_promise do
8
8
  evaluate_promise &block
9
9
  end
10
+ did_initialize
10
11
  end
11
12
 
12
13
  def then &block
13
- @child_promise ||= generate_child_promise
14
+ ensure_child_promise
14
15
  child_promise.resolve_block = block
15
- resolve_child_promise if resolved?
16
- reject_child_promise if rejected?
16
+ resolve_or_reject_child_as_needed
17
17
  child_promise.promise
18
18
  end
19
19
 
20
20
  def fail &block
21
- @child_promise ||= generate_child_promise
21
+ ensure_child_promise
22
22
  child_promise.reject_block = block
23
- resolve_child_promise if resolved?
24
- reject_child_promise if rejected?
23
+ resolve_or_reject_child_as_needed
25
24
  child_promise.promise
26
25
  end
27
26
 
@@ -35,7 +34,13 @@ module MrDarcy
35
34
 
36
35
  def raise
37
36
  r = result
38
- Kernel::raise r if rejected?
37
+ if rejected?
38
+ if r.is_a? Exception
39
+ super r
40
+ else
41
+ super RuntimeError, r
42
+ end
43
+ end
39
44
  end
40
45
 
41
46
  %w| resolved? unresolved? rejected? |.map(&:to_sym).each do |method|
@@ -45,20 +50,40 @@ module MrDarcy
45
50
  end
46
51
 
47
52
  def resolve value
53
+ do_resolve value
54
+ self
55
+ end
56
+
57
+ def reject exception
58
+ do_reject exception
59
+ self
60
+ end
61
+
62
+ private
63
+
64
+ attr_accessor :value, :state
65
+
66
+ def do_resolve value
67
+ will_resolve value
48
68
  set_value_to value
49
69
  state_machine_resolve
50
70
  resolve_child_promise
71
+ did_resolve value
51
72
  end
52
73
 
53
- def reject exception
74
+ def do_reject exception
75
+ will_reject value
54
76
  set_value_to exception
55
77
  state_machine_reject
56
78
  reject_child_promise
79
+ did_reject value
57
80
  end
58
81
 
59
- private
60
-
61
- attr_accessor :value, :child_promise, :state
82
+ def will_resolve value; end
83
+ def will_reject value; end
84
+ def did_resolve value; end
85
+ def did_reject value; end
86
+ def did_initialize; end
62
87
 
63
88
  def state
64
89
  @state ||= :unresolved
@@ -85,15 +110,16 @@ module MrDarcy
85
110
  end
86
111
 
87
112
  def resolve_child_promise
88
- schedule_promise do
89
- child_promise.parent_resolved(value) if has_child_promise?
90
- end
113
+ child_promise.parent_resolved(value) if has_child_promise?
91
114
  end
92
115
 
93
116
  def reject_child_promise
94
- schedule_promise do
95
- child_promise.parent_rejected(value) if has_child_promise?
96
- end
117
+ child_promise.parent_rejected(value) if has_child_promise?
118
+ end
119
+
120
+ def resolve_or_reject_child_as_needed
121
+ resolve_child_promise if resolved?
122
+ reject_child_promise if rejected?
97
123
  end
98
124
 
99
125
  def schedule_promise
@@ -102,7 +128,9 @@ module MrDarcy
102
128
 
103
129
  def evaluate_promise &block
104
130
  begin
105
- block.call DSL.new(self)
131
+ dsl = DSL.new(self)
132
+ dsl.instance_exec dsl, &block
133
+ # block.call DSL.new(self)
106
134
  rescue Exception => e
107
135
  reject e
108
136
  end
@@ -112,6 +140,14 @@ module MrDarcy
112
140
  Kernel::raise "Subclasses must implement me"
113
141
  end
114
142
 
143
+ def ensure_child_promise
144
+ @child_promise ||= generate_child_promise
145
+ end
146
+
147
+ def child_promise
148
+ @child_promise
149
+ end
150
+
115
151
  end
116
152
  end
117
153
  end
@@ -3,50 +3,110 @@ require 'celluloid/autostart'
3
3
  module MrDarcy
4
4
  module Promise
5
5
  class Celluloid < Base
6
+ class Actor
7
+ include ::Celluloid
8
+
9
+ def initialize
10
+ @complete = false
11
+ end
12
+
13
+ def schedule block
14
+ ::Celluloid::Future.new &block
15
+ end
16
+
17
+ def set_status status, value
18
+ case status
19
+ when :success
20
+ @success.call value
21
+ when :failure
22
+ @failure.call value
23
+ end
24
+ signal :complete
25
+ @complete = true
26
+ end
27
+
28
+ def on_success block
29
+ @success = block
30
+ end
31
+
32
+ def on_failure block
33
+ @failure = block
34
+ end
35
+
36
+ def await_completion
37
+ return if @complete
38
+ wait :complete
39
+ end
40
+ end
6
41
 
7
42
  def initialize *args
8
- @waiting = false
43
+ @complete = false
44
+ ensure_actor
45
+ actor.on_success proc { |v| do_resolve v }
46
+ actor.on_failure proc { |v| do_reject v }
9
47
  super
10
48
  end
11
49
 
12
50
  def resolve value
13
- super
14
- condition.signal if @waiting
51
+ actor.async.set_status :success, value
52
+ self
15
53
  end
16
54
 
17
- def reject exception
18
- super
19
- condition.signal if @waiting
55
+ def reject value
56
+ actor.async.set_status :failure, value
57
+ self
20
58
  end
21
59
 
22
60
  def result
23
- wait_until_not_unresolved
61
+ wait_until_complete
24
62
  value
25
63
  end
26
64
 
27
65
  def final
28
- wait_until_not_unresolved
66
+ wait_until_complete
29
67
  self
30
68
  end
31
69
 
32
70
  private
33
71
 
34
- def schedule_promise &block
35
- ::Celluloid::Future.new &block
72
+ def wait_until_complete
73
+ return if @complete
74
+ actor.alive? && actor.await_completion
75
+ @complete = true
36
76
  end
37
77
 
38
- def condition
39
- @condition ||= ::Celluloid::Condition.new
78
+ def will_resolve value
79
+ @complete = true
40
80
  end
41
81
 
42
- def wait_until_not_unresolved
43
- @waiting = true
44
- condition.wait if unresolved?
82
+ def will_reject value
83
+ @complete = true
84
+ end
85
+
86
+ def did_reject value
87
+ actor.async.terminate
88
+ end
89
+
90
+ def did_resolve value
91
+ actor.async.terminate
45
92
  end
46
93
 
47
94
  def generate_child_promise
48
- ChildPromise.new driver: :thread
95
+ ChildPromise.new driver: :celluloid
96
+ end
97
+
98
+ def ensure_actor
99
+ @actor ||= Actor.new
49
100
  end
101
+
102
+ def actor
103
+ @actor
104
+ end
105
+
106
+ def schedule_promise &block
107
+ actor.async.schedule block
108
+ end
109
+
50
110
  end
51
111
  end
52
112
  end
@@ -1,44 +1,49 @@
1
1
  module MrDarcy
2
2
  module Promise
3
- class ChildPromise < MrDarcy::Deferred
3
+ class ChildPromise
4
4
 
5
- attr_accessor :resolve_block, :reject_block
5
+ attr_accessor :resolve_block, :reject_block, :promise
6
6
 
7
7
  def initialize opts={}
8
- @driver = opts[:driver] if opts.has_key? :driver
9
- super
8
+ self.promise = MrDarcy.promise(opts) {}
10
9
  end
11
10
 
12
11
  def parent_resolved value
13
12
  begin
14
13
  return resolve_with value unless handles_resolve?
14
+
15
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
16
+ return defer_resolution_via new_value if thenable? new_value
17
+ resolve_with new_value
21
18
  rescue Exception => e
22
- reject_with e
19
+ handle_exception e
23
20
  end
24
21
  end
25
22
 
26
23
  def parent_rejected value
27
24
  begin
28
25
  return reject_with value unless handles_reject?
26
+
29
27
  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
28
+ return defer_resolution_via new_value if thenable? new_value
29
+ resolve_with new_value
35
30
  rescue Exception => e
36
- reject_with e
31
+ handle_exception e
37
32
  end
38
33
  end
39
34
 
40
35
  private
41
36
 
37
+ def handle_exception e
38
+ if promise.unresolved?
39
+ return reject_with e
40
+ elsif promise.resolved?
41
+ promise.then { raise e }
42
+ elsif promise.rejected?
43
+ promise.fail { raise e }
44
+ end
45
+ end
46
+
42
47
  def result_for which, value
43
48
  block = public_send("#{which}_block")
44
49
  if block
@@ -60,12 +65,12 @@ module MrDarcy
60
65
  object.respond_to?(:then) && object.respond_to?(:fail)
61
66
  end
62
67
 
63
- def defer_resolution_via child_promise
64
- child_promise.then do |value|
68
+ def defer_resolution_via new_promise
69
+ new_promise.then do |value|
65
70
  resolve_with value
66
71
  value
67
72
  end
68
- child_promise.fail do |exception|
73
+ new_promise.fail do |exception|
69
74
  reject_with exception
70
75
  exception
71
76
  end
@@ -2,28 +2,79 @@ require 'eventmachine'
2
2
 
3
3
  module MrDarcy
4
4
  module Promise
5
- class EM < Thread
5
+ class EM < Base
6
+ class DeferrableAdapter
7
+ include EventMachine::Deferrable
8
+ end
6
9
 
7
10
  def initialize *args
11
+ Kernel::raise "EventMachine driver is unsupported on JRuby, sorry" if RUBY_ENGINE=='jruby'
8
12
  unless EventMachine.reactor_running?
9
13
  ::Thread.new { EventMachine.run }
10
14
  ::Thread.pass until EventMachine.reactor_running?
11
15
  end
16
+ @wait_lock = Mutex.new
17
+ @wait_cond = ConditionVariable.new
18
+ @wait_lock.lock
19
+ deferrable_adapter.callback &method(:do_resolve)
20
+ deferrable_adapter.errback &method(:do_reject)
12
21
  super
13
22
  end
14
23
 
24
+ def resolve value
25
+ deferrable_adapter.set_deferred_status :succeeded, value
26
+ self
27
+ end
28
+
29
+ def reject value
30
+ deferrable_adapter.set_deferred_status :failed, value
31
+ self
32
+ end
33
+
34
+ def result
35
+ wait_if_unresolved
36
+ value
37
+ end
38
+
39
+ def final
40
+ wait_if_unresolved
41
+ self
42
+ end
43
+
15
44
  private
16
45
 
17
- def schedule_promise
18
- EventMachine.schedule proc do
19
- yield
20
- end
46
+ def wait_if_unresolved
47
+ @wait_cond.wait @wait_lock if unresolved?
48
+ end
49
+
50
+ def deferrable_adapter
51
+ @deferrable_adapter ||= DeferrableAdapter.new
52
+ end
53
+
54
+ def schedule_promise &block
55
+ EventMachine.defer block
56
+ end
57
+
58
+ def resolve_or_reject_child_as_needed
59
+ EventMachine.defer { super }
21
60
  end
22
61
 
23
62
  def generate_child_promise
24
63
  ChildPromise.new driver: :em
25
64
  end
26
65
 
66
+ def did_resolve value
67
+ notify_waiting
68
+ end
69
+
70
+ def did_reject value
71
+ notify_waiting
72
+ end
73
+
74
+ def notify_waiting
75
+ EventMachine.defer { @wait_cond.signal }
76
+ end
77
+
27
78
  end
28
79
  end
29
80
  end