celluloid 0.13.0 → 0.14.0.pre

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