celluloid 0.12.0 → 0.13.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.
- data/README.md +36 -23
- data/lib/celluloid/actor.rb +74 -47
- data/lib/celluloid/autostart.rb +16 -0
- data/lib/celluloid/calls.rb +52 -52
- data/lib/celluloid/condition.rb +70 -0
- data/lib/celluloid/core_ext.rb +1 -1
- data/lib/celluloid/cpu_counter.rb +7 -1
- data/lib/celluloid/fsm.rb +49 -16
- data/lib/celluloid/future.rb +5 -2
- data/lib/celluloid/internal_pool.rb +62 -44
- data/lib/celluloid/legacy.rb +46 -0
- data/lib/celluloid/links.rb +0 -5
- data/lib/celluloid/logger.rb +14 -4
- data/lib/celluloid/logging/incident.rb +21 -0
- data/lib/celluloid/logging/incident_logger.rb +129 -0
- data/lib/celluloid/logging/incident_reporter.rb +48 -0
- data/lib/celluloid/logging/log_event.rb +20 -0
- data/lib/celluloid/logging/ring_buffer.rb +65 -0
- data/lib/celluloid/logging.rb +5 -0
- data/lib/celluloid/mailbox.rb +2 -1
- data/lib/celluloid/method.rb +5 -0
- data/lib/celluloid/pool_manager.rb +21 -8
- data/lib/celluloid/proxies/actor_proxy.rb +11 -11
- data/lib/celluloid/proxies/async_proxy.rb +5 -1
- data/lib/celluloid/responses.rb +8 -6
- data/lib/celluloid/stack_dump.rb +94 -0
- data/lib/celluloid/supervision_group.rb +5 -3
- data/lib/celluloid/system_events.rb +11 -0
- data/lib/celluloid/tasks/task_fiber.rb +17 -9
- data/lib/celluloid/tasks/task_thread.rb +24 -14
- data/lib/celluloid/tasks.rb +59 -0
- data/lib/celluloid/thread_handle.rb +10 -1
- data/lib/celluloid/version.rb +1 -1
- data/lib/celluloid.rb +146 -87
- data/spec/support/actor_examples.rb +242 -114
- data/spec/support/example_actor_class.rb +17 -5
- data/spec/support/task_examples.rb +11 -2
- metadata +58 -14
- data/lib/celluloid/boot.rb +0 -9
- data/lib/celluloid/task.rb +0 -22
|
@@ -30,11 +30,27 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
30
30
|
actor.greet.should == "Hi, I'm Troy McClure"
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
it "supports synchronous calls with blocks" do
|
|
34
|
+
actor = actor_class.new "Blocky Ralboa"
|
|
35
|
+
|
|
36
|
+
block_executed = false
|
|
37
|
+
actor.run { block_executed = true }
|
|
38
|
+
block_executed.should be_true
|
|
39
|
+
end
|
|
40
|
+
|
|
33
41
|
it "supports synchronous calls via #method" do
|
|
34
42
|
method = actor_class.new("Troy McClure").method(:greet)
|
|
35
43
|
method.call.should == "Hi, I'm Troy McClure"
|
|
36
44
|
end
|
|
37
45
|
|
|
46
|
+
it "supports #arity calls via #method" do
|
|
47
|
+
method = actor_class.new("Troy McClure").method(:greet)
|
|
48
|
+
method.arity.should == 0
|
|
49
|
+
|
|
50
|
+
method = actor_class.new("Troy McClure").method(:change_name)
|
|
51
|
+
method.arity.should == 1
|
|
52
|
+
end
|
|
53
|
+
|
|
38
54
|
it "supports future(:method) syntax for synchronous future calls" do
|
|
39
55
|
actor = actor_class.new "Troy McClure"
|
|
40
56
|
future = actor.future :greet
|
|
@@ -77,75 +93,11 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
77
93
|
actor.respond_to?(:zomg_private, true).should be_true
|
|
78
94
|
end
|
|
79
95
|
|
|
80
|
-
it "
|
|
81
|
-
actor = actor_class.new "
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
end.to raise_exception(NoMethodError)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
it "reraises exceptions which occur during synchronous calls in the caller" do
|
|
89
|
-
actor = actor_class.new "James Dean" # is this in bad taste?
|
|
90
|
-
|
|
91
|
-
expect do
|
|
92
|
-
actor.crash
|
|
93
|
-
end.to raise_exception(ExampleCrash)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
describe "when #abort is called" do
|
|
97
|
-
it "raises exceptions in the caller but keeps running" do
|
|
98
|
-
actor = actor_class.new "Al Pacino"
|
|
99
|
-
|
|
100
|
-
e = nil
|
|
101
|
-
line_no = nil
|
|
102
|
-
|
|
103
|
-
expect do
|
|
104
|
-
begin
|
|
105
|
-
line_no = __LINE__; actor.crash_with_abort "You die motherfucker!", :bar
|
|
106
|
-
rescue => ex
|
|
107
|
-
e = ex
|
|
108
|
-
raise
|
|
109
|
-
end
|
|
110
|
-
end.to raise_exception(ExampleCrash, "You die motherfucker!")
|
|
111
|
-
|
|
112
|
-
e.backtrace.any? { |line| line.include?([__FILE__, line_no].join(':')) }.should be_true # Check the backtrace is appropriate to the caller
|
|
113
|
-
e.foo.should be == :bar # Check the exception maintains instance variables
|
|
114
|
-
|
|
115
|
-
actor.should be_alive
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
it "converts strings to runtime errors" do
|
|
119
|
-
actor = actor_class.new "Al Pacino"
|
|
120
|
-
expect do
|
|
121
|
-
actor.crash_with_abort_raw "foo"
|
|
122
|
-
end.to raise_exception(RuntimeError, "foo")
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
it "crashes the caller if we pass neither String nor Exception" do
|
|
126
|
-
actor = actor_class.new "Al Pacino"
|
|
127
|
-
expect do
|
|
128
|
-
actor.crash_with_abort_raw 10
|
|
129
|
-
end.to raise_exception(TypeError, "Exception object/String expected, but Fixnum received")
|
|
130
|
-
|
|
131
|
-
actor.greet rescue nil # Ensure our actor has died.
|
|
132
|
-
actor.should_not be_alive
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
it "raises DeadActorError if methods are synchronously called on a dead actor" do
|
|
137
|
-
actor = actor_class.new "James Dean"
|
|
138
|
-
actor.crash rescue nil
|
|
139
|
-
|
|
140
|
-
expect do
|
|
141
|
-
actor.greet
|
|
142
|
-
end.to raise_exception(Celluloid::DeadActorError)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
it "supports method! syntax for asynchronous calls" do
|
|
146
|
-
actor = actor_class.new "Troy McClure"
|
|
147
|
-
actor.change_name! "Charlie Sheen"
|
|
148
|
-
actor.greet.should == "Hi, I'm Charlie Sheen"
|
|
96
|
+
it "calls the user defined finalizer" do
|
|
97
|
+
actor = actor_class.new "Mr. Bean"
|
|
98
|
+
actor.wrapped_object.should_receive(:my_finalizer)
|
|
99
|
+
actor.terminate
|
|
100
|
+
Celluloid::Actor.join(actor)
|
|
149
101
|
end
|
|
150
102
|
|
|
151
103
|
it "supports async(:method) syntax for asynchronous calls" do
|
|
@@ -160,19 +112,13 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
160
112
|
actor.greet.should == "Hi, I'm Charlie Sheen"
|
|
161
113
|
end
|
|
162
114
|
|
|
163
|
-
it "supports method! syntax for asynchronous calls to itself" do
|
|
164
|
-
actor = actor_class.new "Troy McClure"
|
|
165
|
-
actor.change_name_with_a_bang "Charlie Sheen"
|
|
166
|
-
actor.greet.should == "Hi, I'm Charlie Sheen"
|
|
167
|
-
end
|
|
168
|
-
|
|
169
115
|
it "supports async.method syntax for asynchronous calls to itself" do
|
|
170
116
|
actor = actor_class.new "Troy McClure"
|
|
171
117
|
actor.change_name_async "Charlie Sheen"
|
|
172
118
|
actor.greet.should == "Hi, I'm Charlie Sheen"
|
|
173
119
|
end
|
|
174
120
|
|
|
175
|
-
it "allows an actor to call private methods asynchronously
|
|
121
|
+
it "allows an actor to call private methods asynchronously" do
|
|
176
122
|
actor = actor_class.new "Troy McClure"
|
|
177
123
|
actor.call_private
|
|
178
124
|
actor.private_called.should be_true
|
|
@@ -184,11 +130,12 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
184
130
|
actor.run do
|
|
185
131
|
Celluloid.actor?
|
|
186
132
|
end.should be_true
|
|
133
|
+
actor.should be_actor
|
|
187
134
|
end
|
|
188
135
|
|
|
189
136
|
it "inspects properly" do
|
|
190
137
|
actor = actor_class.new "Troy McClure"
|
|
191
|
-
actor.inspect.should match(/Celluloid::
|
|
138
|
+
actor.inspect.should match(/Celluloid::ActorProxy\(/)
|
|
192
139
|
actor.inspect.should match(/#{actor_class}/)
|
|
193
140
|
actor.inspect.should include('@name="Troy McClure"')
|
|
194
141
|
actor.inspect.should_not include("@celluloid")
|
|
@@ -207,22 +154,111 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
207
154
|
actor.wrapped_object.should be_a actor_class
|
|
208
155
|
end
|
|
209
156
|
|
|
210
|
-
|
|
157
|
+
it "warns about leaked wrapped objects via #inspect" do
|
|
158
|
+
actor = actor_class.new "Troy McClure"
|
|
159
|
+
|
|
160
|
+
actor.inspect.should_not include Celluloid::BARE_OBJECT_WARNING_MESSAGE
|
|
161
|
+
actor.inspect_thunk.should_not include Celluloid::BARE_OBJECT_WARNING_MESSAGE
|
|
162
|
+
actor.wrapped_object.inspect.should include Celluloid::BARE_OBJECT_WARNING_MESSAGE
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "can override #send" do
|
|
166
|
+
actor = actor_class.new "Troy McClure"
|
|
167
|
+
actor.send('foo').should == 'oof'
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
context "mocking methods" do
|
|
211
171
|
let(:actor) { actor_class.new "Troy McClure" }
|
|
212
172
|
|
|
213
173
|
before do
|
|
214
174
|
actor.wrapped_object.should_receive(:external_hello).once.and_return "World"
|
|
215
175
|
end
|
|
216
176
|
|
|
217
|
-
it
|
|
177
|
+
it "works externally via the proxy" do
|
|
218
178
|
actor.external_hello.should == "World"
|
|
219
179
|
end
|
|
220
180
|
|
|
221
|
-
it
|
|
181
|
+
it "works internally when called on self" do
|
|
222
182
|
actor.internal_hello.should == "World"
|
|
223
183
|
end
|
|
224
184
|
end
|
|
225
185
|
|
|
186
|
+
context :exceptions do
|
|
187
|
+
it "reraises exceptions which occur during synchronous calls in the caller" do
|
|
188
|
+
actor = actor_class.new "James Dean" # is this in bad taste?
|
|
189
|
+
|
|
190
|
+
expect do
|
|
191
|
+
actor.crash
|
|
192
|
+
end.to raise_exception(ExampleCrash)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "includes both caller and receiver in exception traces" do
|
|
196
|
+
ExampleReceiver = Class.new do
|
|
197
|
+
include included_module
|
|
198
|
+
|
|
199
|
+
def receiver_method
|
|
200
|
+
raise ExampleCrash, "the spec purposely crashed me :("
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
ExampleCaller = Class.new do
|
|
205
|
+
include included_module
|
|
206
|
+
|
|
207
|
+
def caller_method
|
|
208
|
+
ExampleReceiver.new.receiver_method
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
ex = nil
|
|
213
|
+
begin
|
|
214
|
+
ExampleCaller.new.caller_method
|
|
215
|
+
rescue => ex
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
ex.should be_a ExampleCrash
|
|
219
|
+
ex.backtrace.grep(/`caller_method'/).should be_true
|
|
220
|
+
ex.backtrace.grep(/`receiver_method'/).should be_true
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it "raises DeadActorError if methods are synchronously called on a dead actor" do
|
|
224
|
+
actor = actor_class.new "James Dean"
|
|
225
|
+
actor.crash rescue nil
|
|
226
|
+
|
|
227
|
+
expect do
|
|
228
|
+
actor.greet
|
|
229
|
+
end.to raise_exception(Celluloid::DeadActorError)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
context :abort do
|
|
234
|
+
it "raises exceptions in the caller but keeps running" do
|
|
235
|
+
actor = actor_class.new "Al Pacino"
|
|
236
|
+
|
|
237
|
+
expect do
|
|
238
|
+
actor.crash_with_abort "You die motherfucker!", :bar
|
|
239
|
+
end.to raise_exception(ExampleCrash, "You die motherfucker!")
|
|
240
|
+
|
|
241
|
+
actor.should be_alive
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it "converts strings to runtime errors" do
|
|
245
|
+
actor = actor_class.new "Al Pacino"
|
|
246
|
+
expect do
|
|
247
|
+
actor.crash_with_abort_raw "foo"
|
|
248
|
+
end.to raise_exception(RuntimeError, "foo")
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it "crashes the caller if we pass neither String nor Exception" do
|
|
252
|
+
actor = actor_class.new "Al Pacino"
|
|
253
|
+
expect do
|
|
254
|
+
actor.crash_with_abort_raw 10
|
|
255
|
+
end.to raise_exception(TypeError, "Exception object/String expected, but Fixnum received")
|
|
256
|
+
|
|
257
|
+
Celluloid::Actor.join(actor)
|
|
258
|
+
actor.should_not be_alive
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
226
262
|
context :termination do
|
|
227
263
|
it "terminates" do
|
|
228
264
|
actor = actor_class.new "Arnold Schwarzenegger"
|
|
@@ -232,7 +268,7 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
232
268
|
actor.should_not be_alive
|
|
233
269
|
end
|
|
234
270
|
|
|
235
|
-
it "kills" do
|
|
271
|
+
it "kills" do # THOU SHALT ALWAYS KILL
|
|
236
272
|
actor = actor_class.new "Woody Harrelson"
|
|
237
273
|
actor.should be_alive
|
|
238
274
|
Celluloid::Actor.kill(actor)
|
|
@@ -262,7 +298,7 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
262
298
|
context :current_actor do
|
|
263
299
|
it "knows the current actor" do
|
|
264
300
|
actor = actor_class.new "Roger Daltrey"
|
|
265
|
-
actor.current_actor.should
|
|
301
|
+
actor.current_actor.should eq actor
|
|
266
302
|
end
|
|
267
303
|
|
|
268
304
|
it "raises NotActorError if called outside an actor" do
|
|
@@ -278,6 +314,24 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
278
314
|
@charlie = actor_class.new "Charlie Sheen"
|
|
279
315
|
end
|
|
280
316
|
|
|
317
|
+
let(:supervisor_class) do
|
|
318
|
+
Class.new do # like a boss
|
|
319
|
+
include included_module
|
|
320
|
+
trap_exit :lambaste_subordinate
|
|
321
|
+
|
|
322
|
+
def initialize(name)
|
|
323
|
+
@name = name
|
|
324
|
+
@subordinate_lambasted = false
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def subordinate_lambasted?; @subordinate_lambasted; end
|
|
328
|
+
|
|
329
|
+
def lambaste_subordinate(actor, reason)
|
|
330
|
+
@subordinate_lambasted = true
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
281
335
|
it "links to other actors" do
|
|
282
336
|
@kevin.link @charlie
|
|
283
337
|
@kevin.monitoring?(@charlie).should be_true
|
|
@@ -316,23 +370,20 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
316
370
|
end
|
|
317
371
|
|
|
318
372
|
it "traps exit messages from other actors" do
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
trap_exit :lambaste_subordinate
|
|
322
|
-
|
|
323
|
-
def initialize(name)
|
|
324
|
-
@name = name
|
|
325
|
-
@subordinate_lambasted = false
|
|
326
|
-
end
|
|
373
|
+
chuck = supervisor_class.new "Chuck Lorre"
|
|
374
|
+
chuck.link @charlie
|
|
327
375
|
|
|
328
|
-
|
|
376
|
+
expect do
|
|
377
|
+
@charlie.crash
|
|
378
|
+
end.to raise_exception(ExampleCrash)
|
|
329
379
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
end
|
|
380
|
+
sleep 0.1 # hax to prevent a race between exit handling and the next call
|
|
381
|
+
chuck.should be_subordinate_lambasted
|
|
382
|
+
end
|
|
334
383
|
|
|
335
|
-
|
|
384
|
+
it "traps exit messages from other actors in subclasses" do
|
|
385
|
+
supervisor_subclass = Class.new(supervisor_class)
|
|
386
|
+
chuck = supervisor_subclass.new "Chuck Lorre"
|
|
336
387
|
chuck.link @charlie
|
|
337
388
|
|
|
338
389
|
expect do
|
|
@@ -342,6 +393,18 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
342
393
|
sleep 0.1 # hax to prevent a race between exit handling and the next call
|
|
343
394
|
chuck.should be_subordinate_lambasted
|
|
344
395
|
end
|
|
396
|
+
|
|
397
|
+
it "unlinks from a dead linked actor" do
|
|
398
|
+
chuck = supervisor_class.new "Chuck Lorre"
|
|
399
|
+
chuck.link @charlie
|
|
400
|
+
|
|
401
|
+
expect do
|
|
402
|
+
@charlie.crash
|
|
403
|
+
end.to raise_exception(ExampleCrash)
|
|
404
|
+
|
|
405
|
+
sleep 0.1 # hax to prevent a race between exit handling and the next call
|
|
406
|
+
chuck.links.count.should == 0
|
|
407
|
+
end
|
|
345
408
|
end
|
|
346
409
|
|
|
347
410
|
context :signaling do
|
|
@@ -385,7 +448,7 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
385
448
|
obj = @signaler.new
|
|
386
449
|
obj.should_not be_signaled
|
|
387
450
|
|
|
388
|
-
obj.wait_for_signal
|
|
451
|
+
obj.async.wait_for_signal
|
|
389
452
|
obj.should_not be_signaled
|
|
390
453
|
|
|
391
454
|
obj.send_signal :foobar
|
|
@@ -411,15 +474,65 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
411
474
|
subject do
|
|
412
475
|
Class.new do
|
|
413
476
|
include included_module
|
|
414
|
-
|
|
415
|
-
|
|
477
|
+
|
|
478
|
+
attr_reader :tasks
|
|
479
|
+
|
|
480
|
+
def initialize
|
|
481
|
+
@tasks = []
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def log_task(task)
|
|
485
|
+
@tasks << task
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def exclusive_with_block_log_task(task)
|
|
489
|
+
exclusive do
|
|
490
|
+
sleep Celluloid::TIMER_QUANTUM
|
|
491
|
+
log_task(task)
|
|
492
|
+
end
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
def exclusive_log_task(task)
|
|
496
|
+
sleep Celluloid::TIMER_QUANTUM
|
|
497
|
+
log_task(task)
|
|
498
|
+
end
|
|
499
|
+
exclusive :exclusive_log_task
|
|
500
|
+
|
|
501
|
+
def check_not_exclusive
|
|
502
|
+
Celluloid.exclusive?
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
def check_exclusive
|
|
506
|
+
exclusive { Celluloid.exclusive? }
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def nested_exclusive_example
|
|
510
|
+
exclusive { exclusive { nil }; Celluloid.exclusive? }
|
|
416
511
|
end
|
|
417
|
-
exclusive :exclusive_example
|
|
418
512
|
end.new
|
|
419
513
|
end
|
|
420
514
|
|
|
421
|
-
it "
|
|
422
|
-
subject.
|
|
515
|
+
it "executes methods in the proper order with block form" do
|
|
516
|
+
subject.async.exclusive_with_block_log_task(:one)
|
|
517
|
+
subject.async.log_task(:two)
|
|
518
|
+
sleep Celluloid::TIMER_QUANTUM * 2
|
|
519
|
+
subject.tasks.should == [:one, :two]
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
it "executes methods in the proper order with a class-level annotation" do
|
|
523
|
+
subject.async.exclusive_log_task :one
|
|
524
|
+
subject.async.log_task :two
|
|
525
|
+
sleep Celluloid::TIMER_QUANTUM * 2
|
|
526
|
+
subject.tasks.should == [:one, :two]
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
it "knows when it's in exclusive mode" do
|
|
530
|
+
subject.check_not_exclusive.should be_false
|
|
531
|
+
subject.check_exclusive.should be_true
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
it "remains in exclusive mode inside nested blocks" do
|
|
535
|
+
subject.nested_exclusive_example.should be_true
|
|
423
536
|
end
|
|
424
537
|
end
|
|
425
538
|
|
|
@@ -448,8 +561,8 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
448
561
|
|
|
449
562
|
it "executes two methods in an exclusive order" do
|
|
450
563
|
actor = subject.new
|
|
451
|
-
actor.eat_donuts
|
|
452
|
-
actor.drink_coffee
|
|
564
|
+
actor.async.eat_donuts
|
|
565
|
+
actor.async.drink_coffee
|
|
453
566
|
sleep Celluloid::TIMER_QUANTUM * 2
|
|
454
567
|
actor.tasks.should == ['donuts', 'coffee']
|
|
455
568
|
end
|
|
@@ -489,7 +602,6 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
489
602
|
end
|
|
490
603
|
|
|
491
604
|
context :timers do
|
|
492
|
-
|
|
493
605
|
before do
|
|
494
606
|
@klass = Class.new do
|
|
495
607
|
include included_module
|
|
@@ -579,6 +691,22 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
579
691
|
sleep(interval + Celluloid::TIMER_QUANTUM) # wonky! #/
|
|
580
692
|
actor.should_not be_fired
|
|
581
693
|
end
|
|
694
|
+
|
|
695
|
+
it "allows delays from outside the actor" do
|
|
696
|
+
actor = @klass.new
|
|
697
|
+
|
|
698
|
+
interval = Celluloid::TIMER_QUANTUM * 10
|
|
699
|
+
started_at = Time.now
|
|
700
|
+
fired = false
|
|
701
|
+
|
|
702
|
+
timer = actor.after(interval) do
|
|
703
|
+
fired = true
|
|
704
|
+
end
|
|
705
|
+
fired.should be_false
|
|
706
|
+
|
|
707
|
+
sleep(interval + Celluloid::TIMER_QUANTUM) # wonky! #/
|
|
708
|
+
fired.should be_true
|
|
709
|
+
end
|
|
582
710
|
end
|
|
583
711
|
|
|
584
712
|
context :tasks do
|
|
@@ -631,13 +759,13 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
631
759
|
end
|
|
632
760
|
end
|
|
633
761
|
|
|
634
|
-
context :
|
|
762
|
+
context :mailbox_class do
|
|
635
763
|
class ExampleMailbox < Celluloid::Mailbox; end
|
|
636
764
|
|
|
637
765
|
subject do
|
|
638
766
|
Class.new do
|
|
639
767
|
include included_module
|
|
640
|
-
|
|
768
|
+
mailbox_class ExampleMailbox
|
|
641
769
|
end
|
|
642
770
|
end
|
|
643
771
|
|
|
@@ -651,23 +779,23 @@ shared_context "a Celluloid Actor" do |included_module|
|
|
|
651
779
|
end
|
|
652
780
|
end
|
|
653
781
|
|
|
654
|
-
context :
|
|
655
|
-
class
|
|
782
|
+
context :proxy_class do
|
|
783
|
+
class ExampleProxy < Celluloid::ActorProxy; end
|
|
656
784
|
|
|
657
785
|
subject do
|
|
658
786
|
Class.new do
|
|
659
787
|
include included_module
|
|
660
|
-
|
|
788
|
+
proxy_class ExampleProxy
|
|
661
789
|
end
|
|
662
790
|
end
|
|
663
791
|
|
|
664
|
-
it "
|
|
665
|
-
subject.new.
|
|
792
|
+
it "uses user-specified proxy" do
|
|
793
|
+
subject.new.__class__.should == ExampleProxy
|
|
666
794
|
end
|
|
667
795
|
|
|
668
|
-
it "retains custom
|
|
796
|
+
it "retains custom proxy when subclassed" do
|
|
669
797
|
subclass = Class.new(subject)
|
|
670
|
-
subclass.new.
|
|
798
|
+
subclass.new.__class__.should == ExampleProxy
|
|
671
799
|
end
|
|
672
800
|
end
|
|
673
801
|
|
|
@@ -3,6 +3,7 @@ module ExampleActorClass
|
|
|
3
3
|
Class.new do
|
|
4
4
|
include included_module
|
|
5
5
|
attr_reader :name
|
|
6
|
+
finalizer :my_finalizer
|
|
6
7
|
|
|
7
8
|
def initialize(name)
|
|
8
9
|
@name = name
|
|
@@ -13,10 +14,6 @@ module ExampleActorClass
|
|
|
13
14
|
@name = new_name
|
|
14
15
|
end
|
|
15
16
|
|
|
16
|
-
def change_name_with_a_bang(new_name)
|
|
17
|
-
change_name! new_name
|
|
18
|
-
end
|
|
19
|
-
|
|
20
17
|
def change_name_async(new_name)
|
|
21
18
|
async.change_name new_name
|
|
22
19
|
end
|
|
@@ -25,6 +22,10 @@ module ExampleActorClass
|
|
|
25
22
|
"Hi, I'm #{@name}"
|
|
26
23
|
end
|
|
27
24
|
|
|
25
|
+
def actor?
|
|
26
|
+
Celluloid.actor?
|
|
27
|
+
end
|
|
28
|
+
|
|
28
29
|
def run(*args)
|
|
29
30
|
yield(*args)
|
|
30
31
|
end
|
|
@@ -51,6 +52,14 @@ module ExampleActorClass
|
|
|
51
52
|
"Hello"
|
|
52
53
|
end
|
|
53
54
|
|
|
55
|
+
def inspect_thunk
|
|
56
|
+
inspect
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def send(string)
|
|
60
|
+
string.reverse
|
|
61
|
+
end
|
|
62
|
+
|
|
54
63
|
def method_missing(method_name, *args, &block)
|
|
55
64
|
if delegates?(method_name)
|
|
56
65
|
@delegate.send method_name, *args, &block
|
|
@@ -64,7 +73,7 @@ module ExampleActorClass
|
|
|
64
73
|
end
|
|
65
74
|
|
|
66
75
|
def call_private
|
|
67
|
-
zomg_private
|
|
76
|
+
async.zomg_private
|
|
68
77
|
end
|
|
69
78
|
|
|
70
79
|
def zomg_private
|
|
@@ -73,6 +82,9 @@ module ExampleActorClass
|
|
|
73
82
|
private :zomg_private
|
|
74
83
|
attr_reader :private_called
|
|
75
84
|
|
|
85
|
+
def my_finalizer
|
|
86
|
+
end
|
|
87
|
+
|
|
76
88
|
private
|
|
77
89
|
|
|
78
90
|
def delegates?(method_name)
|
|
@@ -14,11 +14,11 @@ shared_context "a Celluloid Task" do |task_class|
|
|
|
14
14
|
subject { task_class.new(task_type) { Celluloid::Task.suspend(suspend_state) } }
|
|
15
15
|
|
|
16
16
|
before :each do
|
|
17
|
-
Thread.current[:
|
|
17
|
+
Thread.current[:celluloid_actor] = actor
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
after :each do
|
|
21
|
-
Thread.current[:
|
|
21
|
+
Thread.current[:celluloid_actor] = nil
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it "begins with status :new" do
|
|
@@ -33,4 +33,13 @@ shared_context "a Celluloid Task" do |task_class|
|
|
|
33
33
|
subject.should_not be_running
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
it "raises exceptions outside" do
|
|
37
|
+
task = task_class.new(task_type) do
|
|
38
|
+
raise "failure"
|
|
39
|
+
end
|
|
40
|
+
expect do
|
|
41
|
+
task.resume
|
|
42
|
+
end.to raise_exception("failure")
|
|
43
|
+
end
|
|
44
|
+
|
|
36
45
|
end
|