celluloid 0.13.0 → 0.14.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1 -2
  3. data/lib/celluloid.rb +84 -32
  4. data/lib/celluloid/actor.rb +35 -30
  5. data/lib/celluloid/autostart.rb +0 -13
  6. data/lib/celluloid/calls.rb +71 -23
  7. data/lib/celluloid/core_ext.rb +3 -14
  8. data/lib/celluloid/cpu_counter.rb +1 -1
  9. data/lib/celluloid/evented_mailbox.rb +82 -0
  10. data/lib/celluloid/fsm.rb +2 -0
  11. data/lib/celluloid/future.rb +4 -4
  12. data/lib/celluloid/internal_pool.rb +11 -8
  13. data/lib/celluloid/legacy.rb +14 -13
  14. data/lib/celluloid/logging/incident_logger.rb +2 -2
  15. data/lib/celluloid/mailbox.rb +16 -0
  16. data/lib/celluloid/method.rb +7 -7
  17. data/lib/celluloid/notifications.rb +1 -1
  18. data/lib/celluloid/proxies/abstract_proxy.rb +1 -1
  19. data/lib/celluloid/proxies/actor_proxy.rb +23 -27
  20. data/lib/celluloid/proxies/async_proxy.rb +18 -6
  21. data/lib/celluloid/proxies/block_proxy.rb +29 -0
  22. data/lib/celluloid/proxies/future_proxy.rb +9 -3
  23. data/lib/celluloid/proxies/sync_proxy.rb +31 -0
  24. data/lib/celluloid/receivers.rb +1 -1
  25. data/lib/celluloid/responses.rb +13 -1
  26. data/lib/celluloid/stack_dump.rb +8 -5
  27. data/lib/celluloid/supervision_group.rb +6 -4
  28. data/lib/celluloid/tasks.rb +63 -2
  29. data/lib/celluloid/tasks/task_fiber.rb +6 -46
  30. data/lib/celluloid/tasks/task_thread.rb +8 -44
  31. data/lib/celluloid/thread.rb +82 -0
  32. data/lib/celluloid/thread_handle.rb +3 -2
  33. data/lib/celluloid/version.rb +1 -1
  34. data/spec/support/actor_examples.rb +116 -53
  35. data/spec/support/example_actor_class.rb +7 -1
  36. data/spec/support/mailbox_examples.rb +29 -3
  37. data/spec/support/task_examples.rb +11 -9
  38. metadata +21 -29
@@ -0,0 +1,82 @@
1
+ require 'celluloid/fiber'
2
+
3
+ module Celluloid
4
+ class Thread < ::Thread
5
+ # FIXME: these should be replaced using APIs on Celluloid::Thread itself
6
+ # e.g. Thread.current[:celluloid_actor] => Thread.current.actor
7
+ CELLULOID_LOCALS = [
8
+ :celluloid_actor,
9
+ :celluloid_mailbox,
10
+ :celluloid_queue,
11
+ :celluloid_task,
12
+ :celluloid_chain_id
13
+ ]
14
+
15
+ # A roundabout way to avoid purging :celluloid_queue
16
+ EPHEMERAL_CELLULOID_LOCALS = CELLULOID_LOCALS - [:celluloid_queue]
17
+
18
+ def celluloid?
19
+ true
20
+ end
21
+
22
+ # Obtain the Celluloid::Actor object for this thread
23
+ def actor
24
+ self[:celluloid_actor]
25
+ end
26
+
27
+ # Obtain the Celluloid task object for this thread
28
+ def task
29
+ self[:celluloid_task]
30
+ end
31
+
32
+ # Obtain the Celluloid mailbox for this thread
33
+ def mailbox
34
+ self[:celluloid_mailbox]
35
+ end
36
+
37
+ # Obtain the call chain ID for this thread
38
+ def call_chain_id
39
+ self[:celluloid_chain_id]
40
+ end
41
+
42
+ #
43
+ # Override default thread local behavior, making thread locals actor-local
44
+ #
45
+
46
+ # Obtain an actor-local value
47
+ def [](key)
48
+ if CELLULOID_LOCALS.include?(key)
49
+ super(key)
50
+ else
51
+ actor = super(:celluloid_actor)
52
+ actor.locals[key] if actor
53
+ end
54
+ end
55
+
56
+ # Set an actor-local value
57
+ def []=(key, value)
58
+ if CELLULOID_LOCALS.include?(key)
59
+ super(key, value)
60
+ else
61
+ self[:celluloid_actor].locals[key] = value
62
+ end
63
+ end
64
+
65
+ # Obtain the keys to all actor-locals
66
+ def keys
67
+ actor = self[:celluloid_actor]
68
+ actor.locals.keys if actor
69
+ end
70
+
71
+ # Is the given actor local set?
72
+ def key?(key)
73
+ actor = self[:celluloid_actor]
74
+ actor.locals.has_key?(key) if actor
75
+ end
76
+
77
+ # Clear thread state so it can be reused via thread pools
78
+ def recycle
79
+ EPHEMERAL_CELLULOID_LOCALS.each { |local| self[local] = nil }
80
+ end
81
+ end
82
+ end
@@ -31,8 +31,9 @@ module Celluloid
31
31
  end
32
32
 
33
33
  # Join to a running thread, blocking until it terminates
34
- def join
35
- @mutex.synchronize { @join.wait(@mutex) if @thread }
34
+ def join(limit = nil)
35
+ raise ThreadError, "Target thread must not be current thread" if @thread == Thread.current
36
+ @mutex.synchronize { @join.wait(@mutex, limit) if @thread }
36
37
  self
37
38
  end
38
39
 
@@ -1,4 +1,4 @@
1
1
  module Celluloid
2
- VERSION = '0.13.0'
2
+ VERSION = '0.14.0.pre'
3
3
  def self.version; VERSION; end
4
4
  end
@@ -1,13 +1,22 @@
1
- shared_context "a Celluloid Actor" do |included_module|
1
+ shared_examples "a Celluloid Actor" do |included_module|
2
+ describe "using Fibers" do
3
+ include_examples "Celluloid::Actor examples", included_module, Celluloid::TaskFiber
4
+ end
5
+ describe "using Threads" do
6
+ include_examples "Celluloid::Actor examples", included_module, Celluloid::TaskThread
7
+ end
8
+ end
9
+
10
+ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
2
11
  class ExampleCrash < StandardError
3
12
  attr_accessor :foo
4
13
  end
5
14
 
6
- let(:actor_class) { ExampleActorClass.create(included_module) }
15
+ let(:actor_class) { ExampleActorClass.create(included_module, task_klass) }
7
16
 
8
17
  it "returns the actor's class, not the proxy's" do
9
18
  actor = actor_class.new "Troy McClure"
10
- actor.class.should == actor_class
19
+ actor.class.should eq(actor_class)
11
20
  end
12
21
 
13
22
  it "compares with the actor's class in a case statement" do
@@ -21,13 +30,13 @@ shared_context "a Celluloid Actor" do |included_module|
21
30
 
22
31
  it "can be stored in hashes" do
23
32
  actor = actor_class.new "Troy McClure"
24
- actor.hash.should_not == Kernel.hash
25
- actor.object_id.should_not == Kernel.object_id
33
+ actor.hash.should_not eq(Kernel.hash)
34
+ actor.object_id.should_not eq(Kernel.object_id)
26
35
  end
27
36
 
28
37
  it "supports synchronous calls" do
29
38
  actor = actor_class.new "Troy McClure"
30
- actor.greet.should == "Hi, I'm Troy McClure"
39
+ actor.greet.should eq("Hi, I'm Troy McClure")
31
40
  end
32
41
 
33
42
  it "supports synchronous calls with blocks" do
@@ -40,32 +49,33 @@ shared_context "a Celluloid Actor" do |included_module|
40
49
 
41
50
  it "supports synchronous calls via #method" do
42
51
  method = actor_class.new("Troy McClure").method(:greet)
43
- method.call.should == "Hi, I'm Troy McClure"
52
+ method.call.should eq("Hi, I'm Troy McClure")
44
53
  end
45
54
 
46
55
  it "supports #arity calls via #method" do
47
56
  method = actor_class.new("Troy McClure").method(:greet)
48
- method.arity.should == 0
57
+ method.arity.should be(0)
49
58
 
50
59
  method = actor_class.new("Troy McClure").method(:change_name)
51
- method.arity.should == 1
60
+ method.arity.should be(1)
52
61
  end
53
62
 
54
63
  it "supports future(:method) syntax for synchronous future calls" do
55
64
  actor = actor_class.new "Troy McClure"
56
65
  future = actor.future :greet
57
- future.value.should == "Hi, I'm Troy McClure"
66
+ future.value.should eq("Hi, I'm Troy McClure")
58
67
  end
59
68
 
60
69
  it "supports future.method syntax for synchronous future calls" do
61
70
  actor = actor_class.new "Troy McClure"
62
71
  future = actor.future.greet
63
- future.value.should == "Hi, I'm Troy McClure"
72
+ future.value.should eq("Hi, I'm Troy McClure")
64
73
  end
65
74
 
66
75
  it "handles circular synchronous calls" do
67
76
  klass = Class.new do
68
77
  include included_module
78
+ task_class task_klass
69
79
 
70
80
  def greet_by_proxy(actor)
71
81
  actor.greet
@@ -78,13 +88,13 @@ shared_context "a Celluloid Actor" do |included_module|
78
88
 
79
89
  ponycopter = klass.new
80
90
  actor = actor_class.new ponycopter
81
- ponycopter.greet_by_proxy(actor).should == "Hi, I'm a ponycopter!"
91
+ ponycopter.greet_by_proxy(actor).should eq("Hi, I'm a ponycopter!")
82
92
  end
83
93
 
84
94
  it "properly handles method_missing" do
85
95
  actor = actor_class.new "Method Missing"
86
96
  actor.should respond_to(:first)
87
- actor.first.should be == :bar
97
+ actor.first.should be :bar
88
98
  end
89
99
 
90
100
  it "properly handles respond_to with include_private" do
@@ -103,19 +113,19 @@ shared_context "a Celluloid Actor" do |included_module|
103
113
  it "supports async(:method) syntax for asynchronous calls" do
104
114
  actor = actor_class.new "Troy McClure"
105
115
  actor.async :change_name, "Charlie Sheen"
106
- actor.greet.should == "Hi, I'm Charlie Sheen"
116
+ actor.greet.should eq("Hi, I'm Charlie Sheen")
107
117
  end
108
118
 
109
119
  it "supports async.method syntax for asynchronous calls" do
110
120
  actor = actor_class.new "Troy McClure"
111
121
  actor.async.change_name "Charlie Sheen"
112
- actor.greet.should == "Hi, I'm Charlie Sheen"
122
+ actor.greet.should eq("Hi, I'm Charlie Sheen")
113
123
  end
114
124
 
115
125
  it "supports async.method syntax for asynchronous calls to itself" do
116
126
  actor = actor_class.new "Troy McClure"
117
127
  actor.change_name_async "Charlie Sheen"
118
- actor.greet.should == "Hi, I'm Charlie Sheen"
128
+ actor.greet.should eq("Hi, I'm Charlie Sheen")
119
129
  end
120
130
 
121
131
  it "allows an actor to call private methods asynchronously" do
@@ -129,6 +139,9 @@ shared_context "a Celluloid Actor" do |included_module|
129
139
  actor = actor_class.new "Troy McClure"
130
140
  actor.run do
131
141
  Celluloid.actor?
142
+ end.should be_false
143
+ actor.run_on_receiver do
144
+ Celluloid.actor?
132
145
  end.should be_true
133
146
  actor.should be_actor
134
147
  end
@@ -144,7 +157,7 @@ shared_context "a Celluloid Actor" do |included_module|
144
157
  it "inspects properly when dead" do
145
158
  actor = actor_class.new "Troy McClure"
146
159
  actor.terminate
147
- actor.inspect.should match(/Celluloid::Actor\(/)
160
+ actor.inspect.should match(/Celluloid::ActorProxy\(/)
148
161
  actor.inspect.should match(/#{actor_class}/)
149
162
  actor.inspect.should include('dead')
150
163
  end
@@ -164,7 +177,7 @@ shared_context "a Celluloid Actor" do |included_module|
164
177
 
165
178
  it "can override #send" do
166
179
  actor = actor_class.new "Troy McClure"
167
- actor.send('foo').should == 'oof'
180
+ actor.send('foo').should eq('oof')
168
181
  end
169
182
 
170
183
  context "mocking methods" do
@@ -175,16 +188,16 @@ shared_context "a Celluloid Actor" do |included_module|
175
188
  end
176
189
 
177
190
  it "works externally via the proxy" do
178
- actor.external_hello.should == "World"
191
+ actor.external_hello.should eq("World")
179
192
  end
180
193
 
181
194
  it "works internally when called on self" do
182
- actor.internal_hello.should == "World"
195
+ actor.internal_hello.should eq("World")
183
196
  end
184
197
  end
185
198
 
186
199
  context :exceptions do
187
- it "reraises exceptions which occur during synchronous calls in the caller" do
200
+ it "reraises exceptions which occur during synchronous calls in the sender" do
188
201
  actor = actor_class.new "James Dean" # is this in bad taste?
189
202
 
190
203
  expect do
@@ -192,9 +205,10 @@ shared_context "a Celluloid Actor" do |included_module|
192
205
  end.to raise_exception(ExampleCrash)
193
206
  end
194
207
 
195
- it "includes both caller and receiver in exception traces" do
208
+ it "includes both sender and receiver in exception traces" do
196
209
  ExampleReceiver = Class.new do
197
210
  include included_module
211
+ task_class task_klass
198
212
 
199
213
  def receiver_method
200
214
  raise ExampleCrash, "the spec purposely crashed me :("
@@ -203,20 +217,21 @@ shared_context "a Celluloid Actor" do |included_module|
203
217
 
204
218
  ExampleCaller = Class.new do
205
219
  include included_module
220
+ task_class task_klass
206
221
 
207
- def caller_method
222
+ def sender_method
208
223
  ExampleReceiver.new.receiver_method
209
224
  end
210
225
  end
211
226
 
212
227
  ex = nil
213
228
  begin
214
- ExampleCaller.new.caller_method
229
+ ExampleCaller.new.sender_method
215
230
  rescue => ex
216
231
  end
217
232
 
218
233
  ex.should be_a ExampleCrash
219
- ex.backtrace.grep(/`caller_method'/).should be_true
234
+ ex.backtrace.grep(/`sender_method'/).should be_true
220
235
  ex.backtrace.grep(/`receiver_method'/).should be_true
221
236
  end
222
237
 
@@ -231,7 +246,7 @@ shared_context "a Celluloid Actor" do |included_module|
231
246
  end
232
247
 
233
248
  context :abort do
234
- it "raises exceptions in the caller but keeps running" do
249
+ it "raises exceptions in the sender but keeps running" do
235
250
  actor = actor_class.new "Al Pacino"
236
251
 
237
252
  expect do
@@ -248,7 +263,7 @@ shared_context "a Celluloid Actor" do |included_module|
248
263
  end.to raise_exception(RuntimeError, "foo")
249
264
  end
250
265
 
251
- it "crashes the caller if we pass neither String nor Exception" do
266
+ it "crashes the sender if we pass neither String nor Exception" do
252
267
  actor = actor_class.new "Al Pacino"
253
268
  expect do
254
269
  actor.crash_with_abort_raw 10
@@ -308,6 +323,30 @@ shared_context "a Celluloid Actor" do |included_module|
308
323
  end
309
324
  end
310
325
 
326
+ context "thread locals" do
327
+ let(:example_class) do
328
+ Class.new do
329
+ include included_module
330
+ task_class task_klass
331
+
332
+ def initialize(value)
333
+ Thread.current[:example_thread_local] = value
334
+ end
335
+
336
+ def value
337
+ Thread.current[:example_thread_local]
338
+ end
339
+ end
340
+ end
341
+
342
+ let(:example_value) { "foobar" }
343
+
344
+ it "preserves thread locals between tasks" do
345
+ actor = example_class.new(example_value)
346
+ actor.value.should eq example_value
347
+ end
348
+ end
349
+
311
350
  context :linking do
312
351
  before :each do
313
352
  @kevin = actor_class.new "Kevin Bacon" # Some six degrees action here
@@ -317,6 +356,7 @@ shared_context "a Celluloid Actor" do |included_module|
317
356
  let(:supervisor_class) do
318
357
  Class.new do # like a boss
319
358
  include included_module
359
+ task_class task_klass
320
360
  trap_exit :lambaste_subordinate
321
361
 
322
362
  def initialize(name)
@@ -403,7 +443,7 @@ shared_context "a Celluloid Actor" do |included_module|
403
443
  end.to raise_exception(ExampleCrash)
404
444
 
405
445
  sleep 0.1 # hax to prevent a race between exit handling and the next call
406
- chuck.links.count.should == 0
446
+ chuck.links.count.should be(0)
407
447
  end
408
448
  end
409
449
 
@@ -411,6 +451,7 @@ shared_context "a Celluloid Actor" do |included_module|
411
451
  before do
412
452
  @signaler = Class.new do
413
453
  include included_module
454
+ task_class task_klass
414
455
 
415
456
  def initialize
416
457
  @waiting = false
@@ -466,7 +507,7 @@ shared_context "a Celluloid Actor" do |included_module|
466
507
  obj.should_not be_signaled
467
508
 
468
509
  obj.send_signal(:foobar).should be_true
469
- future.value.should == :foobar
510
+ future.value.should be(:foobar)
470
511
  end
471
512
  end
472
513
 
@@ -474,6 +515,7 @@ shared_context "a Celluloid Actor" do |included_module|
474
515
  subject do
475
516
  Class.new do
476
517
  include included_module
518
+ task_class task_klass
477
519
 
478
520
  attr_reader :tasks
479
521
 
@@ -516,14 +558,14 @@ shared_context "a Celluloid Actor" do |included_module|
516
558
  subject.async.exclusive_with_block_log_task(:one)
517
559
  subject.async.log_task(:two)
518
560
  sleep Celluloid::TIMER_QUANTUM * 2
519
- subject.tasks.should == [:one, :two]
561
+ subject.tasks.should eq([:one, :two])
520
562
  end
521
563
 
522
564
  it "executes methods in the proper order with a class-level annotation" do
523
565
  subject.async.exclusive_log_task :one
524
566
  subject.async.log_task :two
525
567
  sleep Celluloid::TIMER_QUANTUM * 2
526
- subject.tasks.should == [:one, :two]
568
+ subject.tasks.should eq([:one, :two])
527
569
  end
528
570
 
529
571
  it "knows when it's in exclusive mode" do
@@ -540,6 +582,7 @@ shared_context "a Celluloid Actor" do |included_module|
540
582
  subject do
541
583
  Class.new do
542
584
  include included_module
585
+ task_class task_klass
543
586
  exclusive
544
587
 
545
588
  attr_reader :tasks
@@ -564,7 +607,7 @@ shared_context "a Celluloid Actor" do |included_module|
564
607
  actor.async.eat_donuts
565
608
  actor.async.drink_coffee
566
609
  sleep Celluloid::TIMER_QUANTUM * 2
567
- actor.tasks.should == ['donuts', 'coffee']
610
+ actor.tasks.should eq(['donuts', 'coffee'])
568
611
  end
569
612
  end
570
613
 
@@ -572,6 +615,8 @@ shared_context "a Celluloid Actor" do |included_module|
572
615
  before do
573
616
  @receiver = Class.new do
574
617
  include included_module
618
+ task_class task_klass
619
+ execute_block_on_receiver :signal_myself
575
620
 
576
621
  def signal_myself(obj, &block)
577
622
  current_actor.mailbox << obj
@@ -584,12 +629,12 @@ shared_context "a Celluloid Actor" do |included_module|
584
629
  let(:message) { Object.new }
585
630
 
586
631
  it "allows unconditional receive" do
587
- receiver.signal_myself(message).should == message
632
+ receiver.signal_myself(message).should eq(message)
588
633
  end
589
634
 
590
635
  it "allows arbitrary selective receive" do
591
636
  received_obj = receiver.signal_myself(message) { |o| o == message }
592
- received_obj.should == message
637
+ received_obj.should eq(message)
593
638
  end
594
639
 
595
640
  it "times out after the given interval", :pending => ENV['CI'] do
@@ -605,6 +650,7 @@ shared_context "a Celluloid Actor" do |included_module|
605
650
  before do
606
651
  @klass = Class.new do
607
652
  include included_module
653
+ task_class task_klass
608
654
 
609
655
  def initialize
610
656
  @sleeping = false
@@ -653,9 +699,8 @@ shared_context "a Celluloid Actor" do |included_module|
653
699
  actor = @klass.new
654
700
 
655
701
  interval = Celluloid::TIMER_QUANTUM * 10
656
- started_at = Time.now
657
702
 
658
- timer = actor.fire_after(interval)
703
+ actor.fire_after(interval)
659
704
  actor.should_not be_fired
660
705
 
661
706
  sleep(interval + Celluloid::TIMER_QUANTUM) # wonky! #/
@@ -666,23 +711,21 @@ shared_context "a Celluloid Actor" do |included_module|
666
711
  actor = @klass.new
667
712
 
668
713
  interval = Celluloid::TIMER_QUANTUM * 10
669
- started_at = Time.now
670
714
 
671
- timer = actor.fire_every(interval)
672
- actor.fired.should be == 0
715
+ actor.fire_every(interval)
716
+ actor.fired.should be_zero
673
717
 
674
718
  sleep(interval + Celluloid::TIMER_QUANTUM) # wonky! #/
675
- actor.fired.should be == 1
719
+ actor.fired.should be 1
676
720
 
677
721
  2.times { sleep(interval + Celluloid::TIMER_QUANTUM) } # wonky! #/
678
- actor.fired.should be == 3
722
+ actor.fired.should be 3
679
723
  end
680
724
 
681
725
  it "cancels timers before they fire" do
682
726
  actor = @klass.new
683
727
 
684
728
  interval = Celluloid::TIMER_QUANTUM * 10
685
- started_at = Time.now
686
729
 
687
730
  timer = actor.fire_after(interval)
688
731
  actor.should_not be_fired
@@ -696,10 +739,9 @@ shared_context "a Celluloid Actor" do |included_module|
696
739
  actor = @klass.new
697
740
 
698
741
  interval = Celluloid::TIMER_QUANTUM * 10
699
- started_at = Time.now
700
742
  fired = false
701
743
 
702
- timer = actor.after(interval) do
744
+ actor.after(interval) do
703
745
  fired = true
704
746
  end
705
747
  fired.should be_false
@@ -713,6 +755,7 @@ shared_context "a Celluloid Actor" do |included_module|
713
755
  before do
714
756
  @klass = Class.new do
715
757
  include included_module
758
+ task_class task_klass
716
759
  attr_reader :blocker
717
760
 
718
761
  def initialize
@@ -741,21 +784,21 @@ shared_context "a Celluloid Actor" do |included_module|
741
784
  actor = @klass.new
742
785
 
743
786
  tasks = actor.tasks
744
- tasks.size.should == 1
787
+ tasks.size.should be 1
745
788
 
746
- future = actor.future(:blocking_call)
789
+ actor.future(:blocking_call)
747
790
  sleep 0.1 # hax! waiting for ^^^ call to actually start
748
791
 
749
792
  tasks = actor.tasks
750
- tasks.size.should == 2
793
+ tasks.size.should be 2
751
794
 
752
795
  blocking_task = tasks.find { |t| t.status != :running }
753
- blocking_task.should be_a Celluloid.task_class
754
- blocking_task.status.should == :callwait
796
+ blocking_task.should be_a task_klass
797
+ blocking_task.status.should be :callwait
755
798
 
756
799
  actor.blocker.unblock
757
800
  sleep 0.1 # hax again :(
758
- actor.tasks.size.should == 1
801
+ actor.tasks.size.should be 1
759
802
  end
760
803
  end
761
804
 
@@ -765,6 +808,7 @@ shared_context "a Celluloid Actor" do |included_module|
765
808
  subject do
766
809
  Class.new do
767
810
  include included_module
811
+ task_class task_klass
768
812
  mailbox_class ExampleMailbox
769
813
  end
770
814
  end
@@ -779,23 +823,42 @@ shared_context "a Celluloid Actor" do |included_module|
779
823
  end
780
824
  end
781
825
 
826
+ context :mailbox_limit do
827
+ subject do
828
+ Class.new do
829
+ include included_module
830
+ task_class task_klass
831
+ mailbox.max_size = 100
832
+ end
833
+ end
834
+
835
+ it "configures the mailbox limit" do
836
+ subject.new.mailbox.max_size.should == 100
837
+ end
838
+ end
839
+
782
840
  context :proxy_class do
783
- class ExampleProxy < Celluloid::ActorProxy; end
841
+ class ExampleProxy < Celluloid::ActorProxy
842
+ def subclass_proxy?
843
+ true
844
+ end
845
+ end
784
846
 
785
847
  subject do
786
848
  Class.new do
787
849
  include included_module
850
+ task_class task_klass
788
851
  proxy_class ExampleProxy
789
852
  end
790
853
  end
791
854
 
792
855
  it "uses user-specified proxy" do
793
- subject.new.__class__.should == ExampleProxy
856
+ subject.new.should be_subclass_proxy
794
857
  end
795
858
 
796
859
  it "retains custom proxy when subclassed" do
797
860
  subclass = Class.new(subject)
798
- subclass.new.__class__.should == ExampleProxy
861
+ subclass.new.should be_subclass_proxy
799
862
  end
800
863
  end
801
864