celluloid 0.12.0.pre → 0.12.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ ...