celluloid 0.12.0.pre → 0.12.0.pre2

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.
@@ -133,10 +133,15 @@ module Celluloid
133
133
  if block
134
134
  @mailbox_factory = block
135
135
  else
136
- @mailbox_factory = proc { klass.new }
136
+ mailbox_class(klass)
137
137
  end
138
138
  end
139
139
 
140
+ # Define the mailbox class for this class
141
+ def mailbox_class(klass)
142
+ @mailbox_factory = proc { klass.new }
143
+ end
144
+
140
145
  # Define the default task type for this class
141
146
  def task_class(klass)
142
147
  @task_class = klass
@@ -166,10 +171,10 @@ module Celluloid
166
171
  # Configuration options for Actor#new
167
172
  def actor_options
168
173
  {
169
- :mailbox => mailbox_factory,
170
- :exit_handler => @exit_handler,
174
+ :mailbox => mailbox_factory,
175
+ :exit_handler => @exit_handler,
171
176
  :exclusive_methods => @exclusive_methods,
172
- :task_class => @task_class,
177
+ :task_class => @task_class
173
178
  }
174
179
  end
175
180
 
@@ -370,7 +375,7 @@ module Celluloid
370
375
  end
371
376
 
372
377
  require 'celluloid/version'
373
- require 'celluloid/actor_proxy'
378
+
374
379
  require 'celluloid/calls'
375
380
  require 'celluloid/core_ext'
376
381
  require 'celluloid/cpu_counter'
@@ -390,6 +395,11 @@ require 'celluloid/task'
390
395
  require 'celluloid/thread_handle'
391
396
  require 'celluloid/uuid'
392
397
 
398
+ require 'celluloid/proxies/abstract_proxy'
399
+ require 'celluloid/proxies/actor_proxy'
400
+ require 'celluloid/proxies/async_proxy'
401
+ require 'celluloid/proxies/future_proxy'
402
+
393
403
  require 'celluloid/actor'
394
404
  require 'celluloid/future'
395
405
  require 'celluloid/pool_manager'
@@ -35,6 +35,11 @@ module Celluloid
35
35
  receiver << @call
36
36
  end
37
37
 
38
+ # Check if this future has a value yet
39
+ def ready?
40
+ @ready
41
+ end
42
+
38
43
  # Obtain the value for this Future
39
44
  def value(timeout = nil)
40
45
  ready = result = nil
@@ -91,9 +96,6 @@ module Celluloid
91
96
  end
92
97
  alias_method :<<, :signal
93
98
 
94
- # Is the future ready yet?
95
- def ready?; @ready; end
96
-
97
99
  # Inspect this Celluloid::Future
98
100
  alias_method :inspect, :to_s
99
101
 
@@ -0,0 +1,17 @@
1
+ module Celluloid
2
+ # Base class of all Celluloid proxies
3
+ class AbstractProxy < BasicObject
4
+ # Needed for storing proxies in data structures
5
+ needed = [:object_id, :__id__, :hash] - instance_methods
6
+ if needed.any?
7
+ include ::Kernel.dup.module_eval {
8
+ undef_method *(instance_methods - needed)
9
+ self
10
+ }
11
+
12
+ # rubinius bug? These methods disappear when we include hacked kernel
13
+ define_method :==, ::BasicObject.instance_method(:==) unless instance_methods.include?(:==)
14
+ alias_method(:equal?, :==) unless instance_methods.include?(:equal?)
15
+ end
16
+ end
17
+ end
@@ -1,33 +1,25 @@
1
1
  module Celluloid
2
- # A proxy object returned from Celluloid::Actor.spawn/spawn_link which
3
- # dispatches calls and casts to normal Ruby objects which are running inside
4
- # of their own threads.
5
- class ActorProxy < BasicObject
2
+ # A proxy object returned from Celluloid::Actor.new/new_link which converts
3
+ # the normal Ruby method protocol into an inter-actor message protocol
4
+ class ActorProxy < AbstractProxy
6
5
  attr_reader :mailbox, :thread
7
6
 
8
7
  def initialize(actor)
9
8
  @mailbox, @thread, @klass = actor.mailbox, actor.thread, actor.subject.class.to_s
10
9
  end
11
10
 
12
- def _send_(meth, *args, &block)
13
- Actor.call @mailbox, :__send__, meth, *args, &block
11
+ def class
12
+ Actor.call @mailbox, :__send__, :class
14
13
  end
15
14
 
16
- # Needed for storing proxies in data structures
17
- needed = [:object_id, :__id__, :hash] - instance_methods
18
- if needed.any?
19
- include ::Kernel.dup.module_eval {
20
- undef_method *(instance_methods - needed)
21
- self
22
- }
23
-
24
- # rubinius bug? These methods disappear when we include hacked kernel
25
- define_method :==, ::BasicObject.instance_method(:==) unless instance_methods.include?(:==)
26
- alias_method(:equal?, :==) unless instance_methods.include?(:equal?)
15
+ def _send_(meth, *args, &block)
16
+ Actor.call @mailbox, :__send__, meth, *args, &block
27
17
  end
28
18
 
29
- def class
30
- Actor.call @mailbox, :__send__, :class
19
+ def inspect
20
+ Actor.call @mailbox, :inspect
21
+ rescue DeadActorError
22
+ "#<Celluloid::Actor(#{@klass}) dead>"
31
23
  end
32
24
 
33
25
  def name
@@ -62,21 +54,22 @@ module Celluloid
62
54
  Actor.call @mailbox, :to_s
63
55
  end
64
56
 
65
- def inspect
66
- Actor.call @mailbox, :inspect
67
- rescue DeadActorError
68
- "#<Celluloid::Actor(#{@klass}) dead>"
69
- end
70
-
71
- # Make an asynchronous call to an actor, for those who don't like the
72
- # predicate syntax. TIMTOWTDI!
73
- def async(method_name, *args, &block)
74
- Actor.async @mailbox, method_name, *args, &block
57
+ # Obtain an async proxy or explicitly invoke a named async method
58
+ def async(method_name = nil, *args, &block)
59
+ if method_name
60
+ Actor.async @mailbox, method_name, *args, &block
61
+ else
62
+ AsyncProxy.new(@mailbox, @klass)
63
+ end
75
64
  end
76
65
 
77
- # Create a Celluloid::Future which calls a given method
78
- def future(method_name, *args, &block)
79
- Actor.future @mailbox, method_name, *args, &block
66
+ # Obtain a future proxy or explicitly invoke a named future method
67
+ def future(method_name = nil, *args, &block)
68
+ if method_name
69
+ Actor.future @mailbox, method_name, *args, &block
70
+ else
71
+ FutureProxy.new(@mailbox, @klass)
72
+ end
80
73
  end
81
74
 
82
75
  # Terminate the associated actor
@@ -0,0 +1,19 @@
1
+ module Celluloid
2
+ # A proxy which sends asynchronous calls to an actor
3
+ class AsyncProxy < AbstractProxy
4
+ attr_reader :mailbox
5
+
6
+ def initialize(mailbox, klass)
7
+ @mailbox, @klass = mailbox, klass
8
+ end
9
+
10
+ def inspect
11
+ "#<Celluloid::AsyncProxy(#{@klass})>"
12
+ end
13
+
14
+ # method_missing black magic to call bang predicate methods asynchronously
15
+ def method_missing(meth, *args, &block)
16
+ Actor.async @mailbox, meth, *args, &block
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Celluloid
2
+ # A proxy which creates future calls to an actor
3
+ class FutureProxy < AbstractProxy
4
+ attr_reader :mailbox
5
+
6
+ def initialize(mailbox, klass)
7
+ @mailbox, @klass = mailbox, klass
8
+ end
9
+
10
+ def inspect
11
+ "#<Celluloid::FutureProxy(#{@klass})>"
12
+ end
13
+
14
+ # method_missing black magic to call bang predicate methods asynchronously
15
+ def method_missing(meth, *args, &block)
16
+ Actor.future @mailbox, meth, *args, &block
17
+ end
18
+ end
19
+ end
@@ -7,27 +7,32 @@ module Celluloid
7
7
  def initialize(type)
8
8
  @type = type
9
9
  @status = :new
10
- @yield = Queue.new
11
- @resume = Queue.new
10
+
11
+ @resume_queue = Queue.new
12
+ @yield_mutex = Mutex.new
13
+ @yield_cond = ConditionVariable.new
12
14
 
13
15
  actor, mailbox = Thread.current[:actor], Thread.current[:mailbox]
14
16
  raise NotActorError, "can't create tasks outside of actors" unless actor
15
17
 
16
18
  @thread = InternalPool.get do
17
- @status = :running
18
- Thread.current[:actor] = actor
19
- Thread.current[:mailbox] = mailbox
20
- Thread.current[:task] = self
21
- actor.tasks << self
22
-
23
19
  begin
24
- @yield.push(yield(@resume.pop))
20
+ value = @resume_queue.pop
21
+ raise value if value.is_a?(Task::TerminatedError)
22
+
23
+ @status = :running
24
+ Thread.current[:actor] = actor
25
+ Thread.current[:mailbox] = mailbox
26
+ Thread.current[:task] = self
27
+ actor.tasks << self
28
+
29
+ yield
25
30
  rescue Task::TerminatedError
26
31
  # Task was explicitly terminated
27
32
  ensure
28
33
  @status = :dead
29
34
  actor.tasks.delete self
30
- @waiter.run if @waiter
35
+ @yield_cond.signal
31
36
  end
32
37
  end
33
38
  end
@@ -35,20 +40,24 @@ module Celluloid
35
40
  # Suspend the current task, changing the status to the given argument
36
41
  def suspend(status)
37
42
  @status = status
38
- @yield.push(nil)
39
- result = @resume.pop
43
+ @yield_cond.signal
44
+ value = @resume_queue.pop
40
45
 
41
- raise result if result.is_a?(Task::TerminatedError)
46
+ raise value if value.is_a?(Task::TerminatedError)
42
47
  @status = :running
43
48
 
44
- result
49
+ value
45
50
  end
46
51
 
47
52
  # Resume a suspended task, giving it a value to return if needed
48
53
  def resume(value = nil)
49
54
  raise DeadTaskError, "cannot resume a dead task" unless @thread.alive?
50
- @resume.push(value)
51
- @yield.pop
55
+
56
+ @yield_mutex.synchronize do
57
+ @resume_queue.push(value)
58
+ @yield_cond.wait(@yield_mutex)
59
+ end
60
+
52
61
  nil
53
62
  rescue ThreadError
54
63
  raise DeadTaskError, "cannot resume a dead task"
@@ -1,4 +1,4 @@
1
1
  module Celluloid
2
- VERSION = '0.12.0.pre'
2
+ VERSION = '0.12.0.pre2'
3
3
  def self.version; VERSION; end
4
4
  end
@@ -25,22 +25,28 @@ shared_context "a Celluloid Actor" do |included_module|
25
25
  actor.object_id.should_not == Kernel.object_id
26
26
  end
27
27
 
28
- it "handles synchronous calls" do
28
+ it "supports synchronous calls" do
29
29
  actor = actor_class.new "Troy McClure"
30
30
  actor.greet.should == "Hi, I'm Troy McClure"
31
31
  end
32
32
 
33
- it "handles synchronous calls via #method" do
33
+ it "supports synchronous calls via #method" do
34
34
  method = actor_class.new("Troy McClure").method(:greet)
35
35
  method.call.should == "Hi, I'm Troy McClure"
36
36
  end
37
37
 
38
- it "handles futures for synchronous calls" do
38
+ it "supports future(:method) syntax for synchronous future calls" do
39
39
  actor = actor_class.new "Troy McClure"
40
40
  future = actor.future :greet
41
41
  future.value.should == "Hi, I'm Troy McClure"
42
42
  end
43
43
 
44
+ it "supports future.method syntax for synchronous future calls" do
45
+ actor = actor_class.new "Troy McClure"
46
+ future = actor.future.greet
47
+ future.value.should == "Hi, I'm Troy McClure"
48
+ end
49
+
44
50
  it "handles circular synchronous calls" do
45
51
  klass = Class.new do
46
52
  include included_module
@@ -136,19 +142,25 @@ shared_context "a Celluloid Actor" do |included_module|
136
142
  end.to raise_exception(Celluloid::DeadActorError)
137
143
  end
138
144
 
139
- it "handles asynchronous calls" do
145
+ it "supports method! syntax for asynchronous calls" do
140
146
  actor = actor_class.new "Troy McClure"
141
147
  actor.change_name! "Charlie Sheen"
142
148
  actor.greet.should == "Hi, I'm Charlie Sheen"
143
149
  end
144
150
 
145
- it "handles asynchronous calls via #async" do
151
+ it "supports async(:method) syntax for asynchronous calls" do
146
152
  actor = actor_class.new "Troy McClure"
147
153
  actor.async :change_name, "Charlie Sheen"
148
154
  actor.greet.should == "Hi, I'm Charlie Sheen"
149
155
  end
150
156
 
151
- it "handles asynchronous calls to itself" do
157
+ it "supports async.method syntax for asynchronous calls" do
158
+ actor = actor_class.new "Troy McClure"
159
+ actor.async.change_name "Charlie Sheen"
160
+ actor.greet.should == "Hi, I'm Charlie Sheen"
161
+ end
162
+
163
+ it "supports asynchronous calls to itself" do
152
164
  actor = actor_class.new "Troy McClure"
153
165
  actor.change_name_async "Charlie Sheen"
154
166
  actor.greet.should == "Hi, I'm Charlie Sheen"
@@ -374,7 +386,6 @@ shared_context "a Celluloid Actor" do |included_module|
374
386
  obj.should be_signaled
375
387
  end
376
388
 
377
- # FIXME: This is deadlocking on Travis, and may still have issues
378
389
  it "sends values along with signals" do
379
390
  obj = @signaler.new
380
391
  obj.should_not be_signaled
@@ -472,8 +483,6 @@ shared_context "a Celluloid Actor" do |included_module|
472
483
  end
473
484
 
474
485
  context :timers do
475
- # Level of accuracy enforced by the tests (50ms)
476
- Q = 0.05
477
486
 
478
487
  before do
479
488
  @klass = Class.new do
@@ -636,6 +645,26 @@ shared_context "a Celluloid Actor" do |included_module|
636
645
  end
637
646
  end
638
647
 
648
+ context :mailbox_class do
649
+ class ExampleMailbox < Celluloid::Mailbox; end
650
+
651
+ subject do
652
+ Class.new do
653
+ include included_module
654
+ mailbox_class ExampleMailbox
655
+ end
656
+ end
657
+
658
+ it "overrides the mailbox class" do
659
+ subject.new.mailbox.should be_a ExampleMailbox
660
+ end
661
+
662
+ it "retains custom mailboxes when subclassed" do
663
+ subclass = Class.new(subject)
664
+ subclass.new.mailbox.should be_a ExampleMailbox
665
+ end
666
+ end
667
+
639
668
  context :task_class do
640
669
  class ExampleTask < Celluloid::TaskFiber; end
641
670
 
metadata CHANGED
@@ -1,62 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: celluloid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0.pre
5
4
  prerelease: 7
5
+ version: 0.12.0.pre2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Tony Arcieri
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-01 00:00:00.000000000 Z
12
+ date: 2012-09-03 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: timers
16
- requirement: &70213085365480 !ruby/object:Gem::Requirement
17
- none: false
16
+ version_requirements: &2056 !ruby/object:Gem::Requirement
18
17
  requirements:
19
18
  - - ! '>='
20
19
  - !ruby/object:Gem::Version
21
20
  version: 1.0.0
22
- type: :runtime
21
+ none: false
22
+ requirement: *2056
23
23
  prerelease: false
24
- version_requirements: *70213085365480
24
+ type: :runtime
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70213085364540 !ruby/object:Gem::Requirement
28
- none: false
27
+ version_requirements: &2074 !ruby/object:Gem::Requirement
29
28
  requirements:
30
29
  - - ! '>='
31
30
  - !ruby/object:Gem::Version
32
31
  version: '0'
33
- type: :development
32
+ none: false
33
+ requirement: *2074
34
34
  prerelease: false
35
- version_requirements: *70213085364540
35
+ type: :development
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70213085363780 !ruby/object:Gem::Requirement
39
- none: false
38
+ version_requirements: &2092 !ruby/object:Gem::Requirement
40
39
  requirements:
41
40
  - - ! '>='
42
41
  - !ruby/object:Gem::Version
43
42
  version: '0'
44
- type: :development
43
+ none: false
44
+ requirement: *2092
45
45
  prerelease: false
46
- version_requirements: *70213085363780
46
+ type: :development
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: benchmark_suite
49
- requirement: &70213085363200 !ruby/object:Gem::Requirement
50
- none: false
49
+ version_requirements: &2108 !ruby/object:Gem::Requirement
51
50
  requirements:
52
51
  - - ! '>='
53
52
  - !ruby/object:Gem::Version
54
53
  version: '0'
55
- type: :development
54
+ none: false
55
+ requirement: *2108
56
56
  prerelease: false
57
- version_requirements: *70213085363200
58
- description: Celluloid enables people to build concurrent programs out of concurrent
59
- objects just as easily as they build sequential programs out of sequential objects
57
+ type: :development
58
+ description: Celluloid enables people to build concurrent programs out of concurrent objects just as easily as they build sequential programs out of sequential objects
60
59
  email:
61
60
  - tony.arcieri@gmail.com
62
61
  executables: []
@@ -64,8 +63,8 @@ extensions: []
64
63
  extra_rdoc_files: []
65
64
  files:
66
65
  - README.md
66
+ - lib/celluloid.rb
67
67
  - lib/celluloid/actor.rb
68
- - lib/celluloid/actor_proxy.rb
69
68
  - lib/celluloid/boot.rb
70
69
  - lib/celluloid/calls.rb
71
70
  - lib/celluloid/core_ext.rb
@@ -89,12 +88,15 @@ files:
89
88
  - lib/celluloid/supervisor.rb
90
89
  - lib/celluloid/system_events.rb
91
90
  - lib/celluloid/task.rb
92
- - lib/celluloid/tasks/task_fiber.rb
93
- - lib/celluloid/tasks/task_thread.rb
94
91
  - lib/celluloid/thread_handle.rb
95
92
  - lib/celluloid/uuid.rb
96
93
  - lib/celluloid/version.rb
97
- - lib/celluloid.rb
94
+ - lib/celluloid/proxies/abstract_proxy.rb
95
+ - lib/celluloid/proxies/actor_proxy.rb
96
+ - lib/celluloid/proxies/async_proxy.rb
97
+ - lib/celluloid/proxies/future_proxy.rb
98
+ - lib/celluloid/tasks/task_fiber.rb
99
+ - lib/celluloid/tasks/task_thread.rb
98
100
  - spec/support/actor_examples.rb
99
101
  - spec/support/example_actor_class.rb
100
102
  - spec/support/mailbox_examples.rb
@@ -102,27 +104,28 @@ files:
102
104
  homepage: https://github.com/celluloid/celluloid
103
105
  licenses:
104
106
  - MIT
105
- post_install_message:
107
+ post_install_message:
106
108
  rdoc_options: []
107
109
  require_paths:
108
110
  - lib
109
111
  required_ruby_version: !ruby/object:Gem::Requirement
110
- none: false
111
112
  requirements:
112
113
  - - ! '>='
113
114
  - !ruby/object:Gem::Version
114
- version: '0'
115
- required_rubygems_version: !ruby/object:Gem::Requirement
115
+ version: 1.9.2
116
116
  none: false
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
118
  requirements:
118
119
  - - ! '>='
119
120
  - !ruby/object:Gem::Version
120
121
  version: 1.3.6
122
+ none: false
121
123
  requirements: []
122
- rubyforge_project:
123
- rubygems_version: 1.8.10
124
- signing_key:
124
+ rubyforge_project:
125
+ rubygems_version: 1.8.15
126
+ signing_key:
125
127
  specification_version: 3
126
128
  summary: Actor-based concurrent object framework for Ruby
127
129
  test_files: []
128
- has_rdoc:
130
+ has_rdoc:
131
+ ...