celluloid 0.16.0 → 0.17.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.

Potentially problematic release.


This version of celluloid might be problematic. Click here for more details.

Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +333 -0
  3. data/README.md +1 -1
  4. data/culture/CODE_OF_CONDUCT.md +28 -0
  5. data/culture/Gemfile +9 -0
  6. data/culture/README.md +22 -0
  7. data/culture/Rakefile +5 -0
  8. data/culture/SYNC.md +70 -0
  9. data/culture/celluloid-culture.gemspec +18 -0
  10. data/culture/gems/README.md +39 -0
  11. data/culture/gems/dependencies.yml +78 -0
  12. data/culture/gems/loader.rb +101 -0
  13. data/culture/rubocop/README.md +38 -0
  14. data/culture/rubocop/lint.yml +8 -0
  15. data/culture/rubocop/metrics.yml +15 -0
  16. data/culture/rubocop/rubocop.yml +4 -0
  17. data/culture/rubocop/style.yml +48 -0
  18. data/culture/spec/gems_spec.rb +2 -0
  19. data/culture/spec/spec_helper.rb +0 -0
  20. data/culture/spec/sync_spec.rb +2 -0
  21. data/culture/sync.rb +56 -0
  22. data/culture/tasks/rspec.rake +5 -0
  23. data/culture/tasks/rubocop.rake +2 -0
  24. data/examples/basic_usage.rb +49 -0
  25. data/examples/futures.rb +38 -0
  26. data/examples/ring.rb +61 -0
  27. data/examples/simple_pmap.rb +14 -0
  28. data/examples/timers.rb +72 -0
  29. data/lib/celluloid.rb +142 -127
  30. data/lib/celluloid/actor.rb +47 -41
  31. data/lib/celluloid/actor_system.rb +75 -22
  32. data/lib/celluloid/autostart.rb +1 -1
  33. data/lib/celluloid/backported.rb +2 -0
  34. data/lib/celluloid/call/async.rb +16 -0
  35. data/lib/celluloid/call/block.rb +22 -0
  36. data/lib/celluloid/call/sync.rb +70 -0
  37. data/lib/celluloid/calls.rb +25 -114
  38. data/lib/celluloid/cell.rb +32 -20
  39. data/lib/celluloid/condition.rb +3 -3
  40. data/lib/celluloid/core_ext.rb +1 -1
  41. data/lib/celluloid/current.rb +2 -0
  42. data/lib/celluloid/deprecate.rb +18 -0
  43. data/lib/celluloid/exceptions.rb +1 -1
  44. data/lib/celluloid/fiber.rb +3 -3
  45. data/lib/celluloid/future.rb +7 -6
  46. data/lib/celluloid/group.rb +65 -0
  47. data/lib/celluloid/group/manager.rb +27 -0
  48. data/lib/celluloid/group/pool.rb +125 -0
  49. data/lib/celluloid/group/spawner.rb +71 -0
  50. data/lib/celluloid/logging.rb +5 -5
  51. data/lib/celluloid/mailbox.rb +14 -13
  52. data/lib/celluloid/mailbox/evented.rb +76 -0
  53. data/lib/celluloid/notices.rb +15 -0
  54. data/lib/celluloid/proxies.rb +12 -0
  55. data/lib/celluloid/proxy/abstract.rb +24 -0
  56. data/lib/celluloid/proxy/actor.rb +46 -0
  57. data/lib/celluloid/proxy/async.rb +36 -0
  58. data/lib/celluloid/proxy/block.rb +31 -0
  59. data/lib/celluloid/proxy/cell.rb +76 -0
  60. data/lib/celluloid/proxy/future.rb +40 -0
  61. data/lib/celluloid/proxy/sync.rb +44 -0
  62. data/lib/celluloid/rspec.rb +9 -10
  63. data/lib/celluloid/system_events.rb +16 -15
  64. data/lib/celluloid/{tasks.rb → task.rb} +21 -21
  65. data/lib/celluloid/task/fibered.rb +45 -0
  66. data/lib/celluloid/task/threaded.rb +59 -0
  67. data/lib/celluloid/test.rb +1 -1
  68. data/lib/celluloid/thread.rb +6 -1
  69. data/lib/celluloid/version.rb +3 -0
  70. data/spec/celluloid/actor_spec.rb +2 -2
  71. data/spec/celluloid/actor_system_spec.rb +35 -21
  72. data/spec/celluloid/block_spec.rb +3 -5
  73. data/spec/celluloid/calls_spec.rb +33 -11
  74. data/spec/celluloid/condition_spec.rb +16 -13
  75. data/spec/celluloid/evented_mailbox_spec.rb +1 -31
  76. data/spec/celluloid/future_spec.rb +13 -10
  77. data/spec/celluloid/group/elastic_spec.rb +0 -0
  78. data/spec/celluloid/group/manager_spec.rb +0 -0
  79. data/spec/celluloid/group/pool_spec.rb +8 -0
  80. data/spec/celluloid/group/spawner_spec.rb +8 -0
  81. data/spec/celluloid/mailbox/evented_spec.rb +27 -0
  82. data/spec/celluloid/mailbox_spec.rb +1 -3
  83. data/spec/celluloid/misc/leak_spec.rb +73 -0
  84. data/spec/celluloid/task/fibered_spec.rb +5 -0
  85. data/spec/celluloid/task/threaded_spec.rb +5 -0
  86. data/spec/celluloid/timer_spec.rb +14 -16
  87. data/spec/deprecate/actor_system_spec.rb +72 -0
  88. data/spec/deprecate/block_spec.rb +52 -0
  89. data/spec/deprecate/calls_spec.rb +57 -0
  90. data/spec/deprecate/evented_mailbox_spec.rb +34 -0
  91. data/spec/deprecate/future_spec.rb +32 -0
  92. data/spec/deprecate/internal_pool_spec.rb +4 -0
  93. data/spec/shared/actor_examples.rb +1237 -0
  94. data/spec/shared/group_examples.rb +121 -0
  95. data/{lib/celluloid/rspec → spec/shared}/mailbox_examples.rb +20 -17
  96. data/{lib/celluloid/rspec → spec/shared}/task_examples.rb +9 -8
  97. data/spec/spec_helper.rb +72 -16
  98. data/spec/support/coverage.rb +4 -0
  99. data/spec/support/crash_checking.rb +68 -0
  100. data/spec/support/debugging.rb +31 -0
  101. data/spec/support/env.rb +16 -0
  102. data/{lib/celluloid/rspec/example_actor_class.rb → spec/support/examples/actor_class.rb} +21 -2
  103. data/spec/support/examples/evented_mailbox_class.rb +27 -0
  104. data/spec/support/includer.rb +9 -0
  105. data/spec/support/logging.rb +63 -0
  106. data/spec/support/loose_threads.rb +65 -0
  107. data/spec/support/reset_class_variables.rb +27 -0
  108. data/spec/support/sleep_and_wait.rb +14 -0
  109. data/spec/support/split_logs.rb +1 -0
  110. data/spec/support/stubbing.rb +14 -0
  111. metadata +255 -95
  112. data/lib/celluloid/call_chain.rb +0 -13
  113. data/lib/celluloid/cpu_counter.rb +0 -34
  114. data/lib/celluloid/evented_mailbox.rb +0 -73
  115. data/lib/celluloid/fsm.rb +0 -186
  116. data/lib/celluloid/handlers.rb +0 -41
  117. data/lib/celluloid/internal_pool.rb +0 -159
  118. data/lib/celluloid/legacy.rb +0 -9
  119. data/lib/celluloid/links.rb +0 -36
  120. data/lib/celluloid/logger.rb +0 -93
  121. data/lib/celluloid/logging/incident.rb +0 -21
  122. data/lib/celluloid/logging/incident_logger.rb +0 -129
  123. data/lib/celluloid/logging/incident_reporter.rb +0 -48
  124. data/lib/celluloid/logging/log_event.rb +0 -20
  125. data/lib/celluloid/logging/ring_buffer.rb +0 -65
  126. data/lib/celluloid/method.rb +0 -32
  127. data/lib/celluloid/notifications.rb +0 -83
  128. data/lib/celluloid/pool_manager.rb +0 -146
  129. data/lib/celluloid/probe.rb +0 -73
  130. data/lib/celluloid/properties.rb +0 -24
  131. data/lib/celluloid/proxies/abstract_proxy.rb +0 -20
  132. data/lib/celluloid/proxies/actor_proxy.rb +0 -38
  133. data/lib/celluloid/proxies/async_proxy.rb +0 -31
  134. data/lib/celluloid/proxies/block_proxy.rb +0 -29
  135. data/lib/celluloid/proxies/cell_proxy.rb +0 -68
  136. data/lib/celluloid/proxies/future_proxy.rb +0 -35
  137. data/lib/celluloid/proxies/sync_proxy.rb +0 -36
  138. data/lib/celluloid/receivers.rb +0 -63
  139. data/lib/celluloid/registry.rb +0 -57
  140. data/lib/celluloid/responses.rb +0 -44
  141. data/lib/celluloid/rspec/actor_examples.rb +0 -1054
  142. data/lib/celluloid/signals.rb +0 -23
  143. data/lib/celluloid/stack_dump.rb +0 -133
  144. data/lib/celluloid/supervision_group.rb +0 -169
  145. data/lib/celluloid/supervisor.rb +0 -22
  146. data/lib/celluloid/task_set.rb +0 -49
  147. data/lib/celluloid/tasks/task_fiber.rb +0 -43
  148. data/lib/celluloid/tasks/task_thread.rb +0 -53
  149. data/lib/celluloid/thread_handle.rb +0 -50
  150. data/lib/celluloid/uuid.rb +0 -38
  151. data/spec/celluloid/cpu_counter_spec.rb +0 -82
  152. data/spec/celluloid/fsm_spec.rb +0 -107
  153. data/spec/celluloid/internal_pool_spec.rb +0 -52
  154. data/spec/celluloid/links_spec.rb +0 -45
  155. data/spec/celluloid/logging/ring_buffer_spec.rb +0 -38
  156. data/spec/celluloid/notifications_spec.rb +0 -120
  157. data/spec/celluloid/pool_spec.rb +0 -92
  158. data/spec/celluloid/probe_spec.rb +0 -121
  159. data/spec/celluloid/properties_spec.rb +0 -42
  160. data/spec/celluloid/registry_spec.rb +0 -64
  161. data/spec/celluloid/stack_dump_spec.rb +0 -64
  162. data/spec/celluloid/supervision_group_spec.rb +0 -65
  163. data/spec/celluloid/supervisor_spec.rb +0 -103
  164. data/spec/celluloid/tasks/task_fiber_spec.rb +0 -5
  165. data/spec/celluloid/tasks/task_thread_spec.rb +0 -5
  166. data/spec/celluloid/thread_handle_spec.rb +0 -26
  167. data/spec/celluloid/uuid_spec.rb +0 -11
@@ -1,50 +0,0 @@
1
- module Celluloid
2
- # An abstraction around threads from the InternalPool which ensures we don't
3
- # accidentally do things to threads which have been returned to the pool,
4
- # such as, say, killing them
5
- class ThreadHandle
6
- def initialize(actor_system, role = nil)
7
- @mutex = Mutex.new
8
- @join = ConditionVariable.new
9
-
10
- @thread = actor_system.get_thread do
11
- Thread.current.role = role
12
- begin
13
- yield
14
- ensure
15
- @mutex.synchronize do
16
- @thread = nil
17
- @join.broadcast
18
- end
19
- end
20
- end
21
- end
22
-
23
- # Is the thread running?
24
- def alive?
25
- @mutex.synchronize { @thread.alive? if @thread }
26
- end
27
-
28
- # Forcibly kill the thread
29
- def kill
30
- !!@mutex.synchronize { @thread.kill if @thread }
31
- self
32
- end
33
-
34
- # Join to a running thread, blocking until it terminates
35
- def join(limit = nil)
36
- raise ThreadError, "Target thread must not be current thread" if @thread == Thread.current
37
- @mutex.synchronize { @join.wait(@mutex, limit) if @thread }
38
- self
39
- end
40
-
41
- # Obtain the backtrace for this thread
42
- def backtrace
43
- @thread.backtrace
44
- rescue NoMethodError
45
- # undefined method `backtrace' for nil:NilClass
46
- # Swallow this in case this ThreadHandle was terminated and @thread was
47
- # set to nil
48
- end
49
- end
50
- end
@@ -1,38 +0,0 @@
1
- require 'securerandom'
2
-
3
- module Celluloid
4
- # Clearly Ruby doesn't have enough UUID libraries
5
- # This one aims to be fast and simple with good support for multiple threads
6
- # If there's a better UUID library I can use with similar multithreaded
7
- # performance, I certainly wouldn't mind using a gem for this!
8
- module UUID
9
- values = SecureRandom.hex(9).match(/(.{8})(.{4})(.{3})(.{3})/)
10
- PREFIX = "#{values[1]}-#{values[2]}-4#{values[3]}-8#{values[4]}".freeze
11
- BLOCK_SIZE = 0x10000
12
-
13
- @counter = 0
14
- @counter_mutex = Mutex.new
15
-
16
- def self.generate
17
- thread = Thread.current
18
-
19
- unless thread.uuid_limit
20
- @counter_mutex.synchronize do
21
- block_base = @counter
22
- @counter += BLOCK_SIZE
23
- thread.uuid_counter = block_base
24
- thread.uuid_limit = @counter - 1
25
- end
26
- end
27
-
28
- counter = thread.uuid_counter
29
- if thread.uuid_counter >= thread.uuid_limit
30
- thread.uuid_counter = thread.uuid_limit = nil
31
- else
32
- thread.uuid_counter += 1
33
- end
34
-
35
- "#{PREFIX}-#{sprintf("%012x", counter)}".freeze
36
- end
37
- end
38
- end
@@ -1,82 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Celluloid::CPUCounter do
4
- describe :cores do
5
- subject { described_class.cores }
6
-
7
- let(:num_cores) { 1024 }
8
-
9
- before do
10
- described_class.stub(:`) { fail 'backtick stub called' }
11
- ::IO.stub(:open).and_raise('IO.open stub called!')
12
- described_class.instance_variable_set('@cores', nil)
13
- end
14
-
15
- after { ENV['NUMBER_OF_PROCESSORS'] = nil }
16
-
17
- context 'from valid env value' do
18
- before { ENV['NUMBER_OF_PROCESSORS'] = num_cores.to_s }
19
- it { should eq num_cores }
20
- end
21
-
22
- context 'from invalid env value' do
23
- before { ENV['NUMBER_OF_PROCESSORS'] = '' }
24
- specify { expect { subject }.to raise_error(ArgumentError) }
25
- end
26
-
27
- context 'with no env value' do
28
- before { ENV['NUMBER_OF_PROCESSORS'] = nil }
29
-
30
- context 'when /sys/devices/system/cpu/present exists' do
31
- before do
32
- ::IO.should_receive(:read).with('/sys/devices/system/cpu/present')
33
- .and_return("dunno-whatever-#{num_cores - 1}")
34
- end
35
- it { should eq num_cores }
36
- end
37
-
38
- context 'when /sys/devices/system/cpu/present does NOT exist' do
39
- before do
40
- ::IO.should_receive(:read).with('/sys/devices/system/cpu/present')
41
- .and_raise(Errno::ENOENT)
42
- end
43
-
44
- context 'when /sys/devices/system/cpu/cpu* files exist' do
45
- before do
46
- cpu_entries = (1..num_cores).map { |n| "cpu#{n}" }
47
- cpu_entries << 'non-cpu-entry-to-ignore'
48
- Dir.should_receive(:[]).with('/sys/devices/system/cpu/cpu*')
49
- .and_return(cpu_entries)
50
- end
51
- it { should eq num_cores }
52
- end
53
-
54
- context 'when /sys/devices/system/cpu/cpu* files DO NOT exist' do
55
- before do
56
- Dir.should_receive(:[]).with('/sys/devices/system/cpu/cpu*')
57
- .and_return([])
58
- end
59
-
60
- context 'when sysctl blows up' do
61
- before { described_class.stub(:`).and_raise(Errno::EINTR) }
62
- specify { expect { subject }.to raise_error }
63
- end
64
-
65
- context 'when sysctl fails' do
66
- before { described_class.stub(:`).and_return(`false`) }
67
- it { should be nil }
68
- end
69
-
70
- context 'when sysctl succeeds' do
71
- before do
72
- described_class.should_receive(:`).with('sysctl -n hw.ncpu')
73
- .and_return(num_cores.to_s)
74
- `true`
75
- end
76
- it { should eq num_cores }
77
- end
78
- end
79
- end
80
- end
81
- end
82
- end
@@ -1,107 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Celluloid::FSM, actor_system: :global do
4
- before :all do
5
- class TestMachine
6
- include Celluloid::FSM
7
-
8
- def initialize
9
- super
10
- @fired = false
11
- end
12
-
13
- state :callbacked do
14
- @fired = true
15
- end
16
-
17
- state :pre_done, :to => :done
18
- state :another, :done
19
-
20
- def fired?; @fired end
21
- end
22
-
23
- class DummyActor
24
- include Celluloid
25
- end
26
-
27
- class CustomDefaultMachine
28
- include Celluloid::FSM
29
-
30
- default_state :foobar
31
- end
32
- end
33
-
34
- subject { TestMachine.new }
35
-
36
- it "starts in the default state" do
37
- subject.state.should eq(TestMachine.default_state)
38
- end
39
-
40
- it "transitions between states" do
41
- subject.state.should_not be :done
42
- subject.transition :done
43
- subject.state.should be :done
44
- end
45
-
46
- it "fires callbacks for states" do
47
- subject.should_not be_fired
48
- subject.transition :callbacked
49
- subject.should be_fired
50
- end
51
-
52
- it "allows custom default states" do
53
- CustomDefaultMachine.new.state.should be :foobar
54
- end
55
-
56
- it "supports constraints on valid state transitions" do
57
- subject.transition :pre_done
58
- expect { subject.transition :another }.to raise_exception ArgumentError
59
- end
60
-
61
- it "transitions to states after a specified delay" do
62
- interval = Celluloid::TIMER_QUANTUM * 10
63
-
64
- subject.attach DummyActor.new
65
- subject.transition :another
66
- subject.transition :done, :delay => interval
67
-
68
- subject.state.should be :another
69
- sleep interval + Celluloid::TIMER_QUANTUM
70
-
71
- subject.state.should be :done
72
- end
73
-
74
- it "cancels delayed state transitions if another transition is made" do
75
- interval = Celluloid::TIMER_QUANTUM * 10
76
-
77
- subject.attach DummyActor.new
78
- subject.transition :another
79
- subject.transition :done, :delay => interval
80
-
81
- subject.state.should be :another
82
- subject.transition :pre_done
83
- sleep interval + Celluloid::TIMER_QUANTUM
84
-
85
- subject.state.should be :pre_done
86
- end
87
-
88
- context "actor is not set" do
89
- context "transition is delayed" do
90
- it "raises an unattached error" do
91
- expect { subject.transition :another, :delay => 100 } \
92
- .to raise_error(Celluloid::FSM::UnattachedError)
93
- end
94
- end
95
- end
96
-
97
- context "transitioning to an invalid state" do
98
- it "raises an argument error" do
99
- expect { subject.transition :invalid_state }.to raise_error(ArgumentError)
100
- end
101
-
102
- it "should not call transition! if the state is :default" do
103
- subject.should_not_receive :transition!
104
- subject.transition :default
105
- end
106
- end
107
- end
@@ -1,52 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Celluloid::InternalPool do
4
- it "gets threads from the pool" do
5
- subject.get { sleep 1 }.should be_a Thread
6
- end
7
-
8
- it "puts threads back into the pool" do
9
- subject.idle_size.should be_zero
10
- subject.busy_size.should be_zero
11
-
12
- queue = Queue.new
13
- subject.get { queue.pop }
14
-
15
- subject.idle_size.should be_zero
16
- subject.busy_size.should eq 1
17
-
18
- queue << nil
19
- sleep 0.01 # hax
20
-
21
- subject.idle_size.should eq 1
22
- subject.busy_size.should eq 0
23
- end
24
-
25
- it "cleans thread locals from old threads" do
26
- thread = subject.get { Thread.current[:foo] = :bar }
27
-
28
- sleep 0.01 #hax
29
- thread[:foo].should be_nil
30
- end
31
-
32
- it "doesn't fail if a third-party thread is spawned" do
33
- subject.idle_size.should be_zero
34
- subject.busy_size.should be_zero
35
-
36
- subject.get { ::Thread.new { sleep 0.5 } }.should be_a(Celluloid::Thread)
37
-
38
- sleep 0.01 # hax
39
-
40
- subject.idle_size.should eq 1
41
- subject.busy_size.should eq 0
42
- end
43
-
44
- it "doesn't leak dead threads" do
45
- subject.max_idle = 0 # Instruct the pool to immediately shut down the thread.
46
- subject.get { true }.should be_a(Celluloid::Thread)
47
-
48
- sleep 0.01 # hax
49
-
50
- subject.to_a.should have(0).items
51
- end
52
- end
@@ -1,45 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Celluloid::Links do
4
- subject { Celluloid::Links.new }
5
-
6
- let(:mailbox_mock) do
7
- Class.new(Array) do
8
- attr_reader :address
9
- def initialize address
10
- @address = address
11
- end
12
- end
13
- end
14
-
15
- let(:first_actor) do
16
- Struct.new(:mailbox).new(mailbox_mock.new('foo123'))
17
- end
18
-
19
- let(:second_actor) do
20
- Struct.new(:mailbox).new(mailbox_mock.new('bar456'))
21
- end
22
-
23
- it 'is Enumerable' do
24
- subject.should be_an(Enumerable)
25
- end
26
-
27
- it 'adds actors by their mailbox address' do
28
- subject.include?(first_actor).should be_false
29
- subject << first_actor
30
- subject.include?(first_actor).should be_true
31
- end
32
-
33
- it 'removes actors by their mailbox address' do
34
- subject << first_actor
35
- subject.include?(first_actor).should be_true
36
- subject.delete first_actor
37
- subject.include?(first_actor).should be_false
38
- end
39
-
40
- it 'iterates over all actors' do
41
- subject << first_actor
42
- subject << second_actor
43
- subject.inject([]) { |all, a| all << a }.should == [first_actor, second_actor]
44
- end
45
- end
@@ -1,38 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Celluloid::RingBuffer do
4
- subject { Celluloid::RingBuffer.new(2) }
5
-
6
- it { should be_empty }
7
- it { should_not be_full }
8
-
9
- it 'should push and shift' do
10
- subject.push('foo')
11
- subject.push('foo2')
12
- subject.shift.should eq('foo')
13
- subject.shift.should eq('foo2')
14
- end
15
-
16
- it 'should push past the end' do
17
- subject.push('foo')
18
- subject.push('foo2')
19
- subject.push('foo3')
20
- subject.should be_full
21
- end
22
-
23
- it 'should shift the most recent' do
24
- (1..5).each { |i| subject.push(i) }
25
- subject.shift.should be 4
26
- subject.shift.should be 5
27
- subject.shift.should be_nil
28
- end
29
-
30
- it 'should return nil when shifting empty' do
31
- subject.should be_empty
32
- subject.shift.should be_nil
33
- end
34
-
35
- it 'should be thread-safe' do
36
- #TODO how to test?
37
- end
38
- end
@@ -1,120 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Celluloid::Notifications, actor_system: :global do
4
- class Admirer
5
- include Celluloid
6
- include Celluloid::Notifications
7
-
8
- attr_reader :mourning
9
- attr_reader :mourning_count
10
-
11
- def someone_died(topic, name)
12
- @mourning = name
13
- @mourning_count ||= 0
14
- @mourning_count += 1
15
- end
16
- end
17
-
18
- class President
19
- include Celluloid
20
- include Celluloid::Notifications
21
-
22
- def die
23
- publish("death", "Mr. President")
24
- end
25
- end
26
-
27
- it 'notifies relevant subscribers' do
28
- marilyn = Admirer.new
29
- jackie = Admirer.new
30
-
31
- marilyn.subscribe("death", :someone_died)
32
- jackie.subscribe("alive", :someone_died)
33
-
34
- president = President.new
35
-
36
- president.die
37
- marilyn.mourning.should eq("Mr. President")
38
- jackie.mourning.should_not eq("Mr. President")
39
- end
40
-
41
- it 'allows multiple subscriptions from the same actor' do
42
- marilyn = Admirer.new
43
-
44
- marilyn.subscribe("death", :someone_died)
45
- marilyn.subscribe("death", :someone_died)
46
-
47
- president = President.new
48
-
49
- president.die
50
- marilyn.mourning_count.should be(2)
51
- end
52
-
53
-
54
- it 'notifies subscribers' do
55
- marilyn = Admirer.new
56
- jackie = Admirer.new
57
-
58
- marilyn.subscribe("death", :someone_died)
59
- jackie.subscribe("death", :someone_died)
60
-
61
- president = President.new
62
-
63
- president.die
64
- marilyn.mourning.should eq("Mr. President")
65
- jackie.mourning.should eq("Mr. President")
66
- end
67
-
68
- it 'publishes even if there are no subscribers' do
69
- president = President.new
70
- president.die
71
- end
72
-
73
- it 'allows regex subscriptions' do
74
- marilyn = Admirer.new
75
-
76
- marilyn.subscribe(/(death|assassination)/, :someone_died)
77
-
78
- president = President.new
79
- president.die
80
- marilyn.mourning.should eq("Mr. President")
81
- end
82
-
83
- it 'allows unsubscribing' do
84
- marilyn = Admirer.new
85
-
86
- subscription = marilyn.subscribe("death", :someone_died)
87
- marilyn.unsubscribe(subscription)
88
-
89
- president = President.new
90
- president.die
91
- marilyn.mourning.should be_nil
92
- end
93
-
94
- it 'prunes dead subscriptions' do
95
- marilyn = Admirer.new
96
- jackie = Admirer.new
97
-
98
- marilyn.subscribe("death", :someone_died)
99
- jackie.subscribe("death", :someone_died)
100
-
101
- listeners = Celluloid::Notifications.notifier.listeners_for("death").size
102
- marilyn.terminate
103
- after_listeners = Celluloid::Notifications.notifier.listeners_for("death").size
104
-
105
- after_listeners.should == listeners - 1
106
- end
107
-
108
- it 'prunes multiple subscriptions from a dead actor' do
109
- marilyn = Admirer.new
110
-
111
- marilyn.subscribe("death", :someone_died)
112
- marilyn.subscribe("death", :someone_died)
113
-
114
- listeners = Celluloid::Notifications.notifier.listeners_for("death").size
115
- marilyn.terminate
116
- after_listeners = Celluloid::Notifications.notifier.listeners_for("death").size
117
-
118
- after_listeners.should eq(listeners - 2)
119
- end
120
- end