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 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