concurrent-ruby 0.6.0.pre.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -8
  3. data/lib/concurrent.rb +2 -0
  4. data/lib/concurrent/actor/actor.rb +3 -3
  5. data/lib/concurrent/actor/postable.rb +1 -1
  6. data/lib/concurrent/actors.rb +0 -3
  7. data/lib/concurrent/actress.rb +75 -0
  8. data/lib/concurrent/actress/ad_hoc.rb +14 -0
  9. data/lib/concurrent/actress/context.rb +96 -0
  10. data/lib/concurrent/actress/core.rb +204 -0
  11. data/lib/concurrent/actress/core_delegations.rb +37 -0
  12. data/lib/concurrent/actress/doc.md +53 -0
  13. data/lib/concurrent/actress/envelope.rb +25 -0
  14. data/lib/concurrent/actress/errors.rb +14 -0
  15. data/lib/concurrent/actress/reference.rb +64 -0
  16. data/lib/concurrent/actress/type_check.rb +48 -0
  17. data/lib/concurrent/agent.rb +20 -11
  18. data/lib/concurrent/async.rb +54 -25
  19. data/lib/concurrent/atomic/atomic.rb +48 -0
  20. data/lib/concurrent/atomic/atomic_boolean.rb +13 -13
  21. data/lib/concurrent/atomic/atomic_fixnum.rb +9 -17
  22. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +7 -4
  23. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +16 -14
  24. data/lib/concurrent/atomic/event.rb +11 -16
  25. data/lib/concurrent/atomics.rb +1 -0
  26. data/lib/concurrent/channel/channel.rb +4 -2
  27. data/lib/concurrent/collection/blocking_ring_buffer.rb +1 -1
  28. data/lib/concurrent/configuration.rb +59 -47
  29. data/lib/concurrent/delay.rb +28 -12
  30. data/lib/concurrent/dereferenceable.rb +6 -6
  31. data/lib/concurrent/errors.rb +30 -0
  32. data/lib/concurrent/executor/executor.rb +11 -4
  33. data/lib/concurrent/executor/immediate_executor.rb +1 -0
  34. data/lib/concurrent/executor/java_thread_pool_executor.rb +4 -0
  35. data/lib/concurrent/executor/one_by_one.rb +24 -12
  36. data/lib/concurrent/executor/per_thread_executor.rb +1 -0
  37. data/lib/concurrent/executor/ruby_single_thread_executor.rb +2 -1
  38. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +7 -2
  39. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +3 -0
  40. data/lib/concurrent/executor/timer_set.rb +1 -1
  41. data/lib/concurrent/future.rb +0 -2
  42. data/lib/concurrent/ivar.rb +31 -6
  43. data/lib/concurrent/logging.rb +17 -0
  44. data/lib/concurrent/mvar.rb +45 -0
  45. data/lib/concurrent/obligation.rb +61 -20
  46. data/lib/concurrent/observable.rb +7 -0
  47. data/lib/concurrent/promise.rb +1 -0
  48. data/lib/concurrent/runnable.rb +2 -2
  49. data/lib/concurrent/supervisor.rb +1 -2
  50. data/lib/concurrent/timer_task.rb +17 -13
  51. data/lib/concurrent/tvar.rb +113 -73
  52. data/lib/concurrent/utility/processor_count.rb +141 -116
  53. data/lib/concurrent/utility/timeout.rb +4 -5
  54. data/lib/concurrent/version.rb +1 -1
  55. data/spec/concurrent/actor/postable_shared.rb +1 -1
  56. data/spec/concurrent/actress_spec.rb +191 -0
  57. data/spec/concurrent/async_spec.rb +35 -3
  58. data/spec/concurrent/atomic/atomic_boolean_spec.rb +1 -1
  59. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +1 -1
  60. data/spec/concurrent/atomic/atomic_spec.rb +133 -0
  61. data/spec/concurrent/atomic/count_down_latch_spec.rb +1 -1
  62. data/spec/concurrent/collection/priority_queue_spec.rb +1 -1
  63. data/spec/concurrent/configuration_spec.rb +5 -2
  64. data/spec/concurrent/delay_spec.rb +14 -0
  65. data/spec/concurrent/exchanger_spec.rb +4 -9
  66. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +1 -1
  67. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +1 -1
  68. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +1 -1
  69. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +1 -1
  70. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +4 -4
  71. data/spec/concurrent/ivar_spec.rb +2 -2
  72. data/spec/concurrent/obligation_spec.rb +113 -24
  73. data/spec/concurrent/observable_shared.rb +4 -0
  74. data/spec/concurrent/observable_spec.rb +8 -3
  75. data/spec/concurrent/runnable_spec.rb +2 -2
  76. data/spec/concurrent/scheduled_task_spec.rb +1 -0
  77. data/spec/concurrent/supervisor_spec.rb +26 -11
  78. data/spec/concurrent/timer_task_spec.rb +36 -35
  79. data/spec/concurrent/tvar_spec.rb +1 -1
  80. data/spec/concurrent/utility/timer_spec.rb +8 -8
  81. data/spec/spec_helper.rb +8 -18
  82. data/spec/support/example_group_extensions.rb +48 -0
  83. metadata +23 -16
  84. data/lib/concurrent/actor/actor_context.rb +0 -77
  85. data/lib/concurrent/actor/actor_ref.rb +0 -67
  86. data/lib/concurrent/actor/simple_actor_ref.rb +0 -94
  87. data/lib/concurrent_ruby_ext.bundle +0 -0
  88. data/spec/concurrent/actor/actor_context_spec.rb +0 -29
  89. data/spec/concurrent/actor/actor_ref_shared.rb +0 -263
  90. data/spec/concurrent/actor/simple_actor_ref_spec.rb +0 -135
  91. data/spec/support/functions.rb +0 -25
@@ -0,0 +1,48 @@
1
+ require 'rbconfig'
2
+
3
+ module Concurrent
4
+ module TestHelpers
5
+ def delta(v1, v2)
6
+ if block_given?
7
+ v1 = yield(v1)
8
+ v2 = yield(v2)
9
+ end
10
+ return (v1 - v2).abs
11
+ end
12
+
13
+ def mri?
14
+ RbConfig::CONFIG['ruby_install_name']=~ /^ruby$/i
15
+ end
16
+
17
+ def jruby?
18
+ RbConfig::CONFIG['ruby_install_name']=~ /^jruby$/i
19
+ end
20
+
21
+ def rbx?
22
+ RbConfig::CONFIG['ruby_install_name']=~ /^rbx$/i
23
+ end
24
+
25
+ def reset_gem_configuration
26
+ Concurrent.instance_variable_set(:@configuration, Concurrent::Configuration.new)
27
+ end
28
+
29
+ extend self
30
+ end
31
+ end
32
+
33
+ class RSpec::Core::ExampleGroup
34
+ def self.with_full_reset
35
+ before(:each) do
36
+ reset_gem_configuration
37
+ end
38
+
39
+ after(:each) do
40
+ Thread.list.each do |thread|
41
+ thread.kill unless thread == Thread.current
42
+ end
43
+ end
44
+ end
45
+
46
+ include Concurrent::TestHelpers
47
+ extend Concurrent::TestHelpers
48
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0.pre.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerry D'Antonio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-12 00:00:00.000000000 Z
11
+ date: 2014-05-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2
14
14
  Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
@@ -24,13 +24,21 @@ files:
24
24
  - README.md
25
25
  - lib/concurrent.rb
26
26
  - lib/concurrent/actor/actor.rb
27
- - lib/concurrent/actor/actor_context.rb
28
- - lib/concurrent/actor/actor_ref.rb
29
27
  - lib/concurrent/actor/postable.rb
30
- - lib/concurrent/actor/simple_actor_ref.rb
31
28
  - lib/concurrent/actors.rb
29
+ - lib/concurrent/actress.rb
30
+ - lib/concurrent/actress/ad_hoc.rb
31
+ - lib/concurrent/actress/context.rb
32
+ - lib/concurrent/actress/core.rb
33
+ - lib/concurrent/actress/core_delegations.rb
34
+ - lib/concurrent/actress/doc.md
35
+ - lib/concurrent/actress/envelope.rb
36
+ - lib/concurrent/actress/errors.rb
37
+ - lib/concurrent/actress/reference.rb
38
+ - lib/concurrent/actress/type_check.rb
32
39
  - lib/concurrent/agent.rb
33
40
  - lib/concurrent/async.rb
41
+ - lib/concurrent/atomic/atomic.rb
34
42
  - lib/concurrent/atomic/atomic_boolean.rb
35
43
  - lib/concurrent/atomic/atomic_fixnum.rb
36
44
  - lib/concurrent/atomic/condition.rb
@@ -54,6 +62,7 @@ files:
54
62
  - lib/concurrent/dataflow.rb
55
63
  - lib/concurrent/delay.rb
56
64
  - lib/concurrent/dereferenceable.rb
65
+ - lib/concurrent/errors.rb
57
66
  - lib/concurrent/exchanger.rb
58
67
  - lib/concurrent/executor/cached_thread_pool.rb
59
68
  - lib/concurrent/executor/executor.rb
@@ -77,6 +86,7 @@ files:
77
86
  - lib/concurrent/executors.rb
78
87
  - lib/concurrent/future.rb
79
88
  - lib/concurrent/ivar.rb
89
+ - lib/concurrent/logging.rb
80
90
  - lib/concurrent/mvar.rb
81
91
  - lib/concurrent/obligation.rb
82
92
  - lib/concurrent/observable.rb
@@ -94,16 +104,14 @@ files:
94
104
  - lib/concurrent/utility/timer.rb
95
105
  - lib/concurrent/version.rb
96
106
  - lib/concurrent_ruby.rb
97
- - lib/concurrent_ruby_ext.bundle
98
- - spec/concurrent/actor/actor_context_spec.rb
99
- - spec/concurrent/actor/actor_ref_shared.rb
100
107
  - spec/concurrent/actor/actor_spec.rb
101
108
  - spec/concurrent/actor/postable_shared.rb
102
- - spec/concurrent/actor/simple_actor_ref_spec.rb
109
+ - spec/concurrent/actress_spec.rb
103
110
  - spec/concurrent/agent_spec.rb
104
111
  - spec/concurrent/async_spec.rb
105
112
  - spec/concurrent/atomic/atomic_boolean_spec.rb
106
113
  - spec/concurrent/atomic/atomic_fixnum_spec.rb
114
+ - spec/concurrent/atomic/atomic_spec.rb
107
115
  - spec/concurrent/atomic/condition_spec.rb
108
116
  - spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb
109
117
  - spec/concurrent/atomic/copy_on_write_observer_set_spec.rb
@@ -162,7 +170,7 @@ files:
162
170
  - spec/concurrent/utility/timeout_spec.rb
163
171
  - spec/concurrent/utility/timer_spec.rb
164
172
  - spec/spec_helper.rb
165
- - spec/support/functions.rb
173
+ - spec/support/example_group_extensions.rb
166
174
  - spec/support/less_than_or_equal_to_matcher.rb
167
175
  homepage: http://www.concurrent-ruby.com
168
176
  licenses:
@@ -179,9 +187,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
179
187
  version: 1.9.3
180
188
  required_rubygems_version: !ruby/object:Gem::Requirement
181
189
  requirements:
182
- - - ">"
190
+ - - ">="
183
191
  - !ruby/object:Gem::Version
184
- version: 1.3.1
192
+ version: '0'
185
193
  requirements: []
186
194
  rubyforge_project:
187
195
  rubygems_version: 2.2.2
@@ -190,15 +198,14 @@ specification_version: 4
190
198
  summary: Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
191
199
  F#, C#, Java, and classic concurrency patterns.
192
200
  test_files:
193
- - spec/concurrent/actor/actor_context_spec.rb
194
- - spec/concurrent/actor/actor_ref_shared.rb
195
201
  - spec/concurrent/actor/actor_spec.rb
196
202
  - spec/concurrent/actor/postable_shared.rb
197
- - spec/concurrent/actor/simple_actor_ref_spec.rb
203
+ - spec/concurrent/actress_spec.rb
198
204
  - spec/concurrent/agent_spec.rb
199
205
  - spec/concurrent/async_spec.rb
200
206
  - spec/concurrent/atomic/atomic_boolean_spec.rb
201
207
  - spec/concurrent/atomic/atomic_fixnum_spec.rb
208
+ - spec/concurrent/atomic/atomic_spec.rb
202
209
  - spec/concurrent/atomic/condition_spec.rb
203
210
  - spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb
204
211
  - spec/concurrent/atomic/copy_on_write_observer_set_spec.rb
@@ -257,6 +264,6 @@ test_files:
257
264
  - spec/concurrent/utility/timeout_spec.rb
258
265
  - spec/concurrent/utility/timer_spec.rb
259
266
  - spec/spec_helper.rb
260
- - spec/support/functions.rb
267
+ - spec/support/example_group_extensions.rb
261
268
  - spec/support/less_than_or_equal_to_matcher.rb
262
269
  has_rdoc:
@@ -1,77 +0,0 @@
1
- require 'concurrent/actor/simple_actor_ref'
2
-
3
- module Concurrent
4
-
5
- # Actor-based concurrency is all the rage in some circles. Originally described in
6
- # 1973, the actor model is a paradigm for creating asynchronous, concurrent objects
7
- # that is becoming increasingly popular. Much has changed since actors were first
8
- # written about four decades ago, which has led to a serious fragmentation within
9
- # the actor community. There is *no* universally accepted, strict definition of
10
- # "actor" and actor implementations differ widely between languages and libraries.
11
- #
12
- # A good definition of "actor" is:
13
- #
14
- # An independent, concurrent, single-purpose, computational entity that communicates exclusively via message passing.
15
- #
16
- # The actor framework in this library is heavily influenced by the Akka toolkit,
17
- # with additional inspiration from Erlang and Scala. Unlike many of the abstractions
18
- # in this library, `ActorContext` takes an *object-oriented* approach to asynchronous
19
- # concurrency, rather than a *functional programming* approach.
20
- #
21
- # Creating an actor class is achieved by including the `ActorContext` module
22
- # within a standard Ruby class. One `ActorContext` is mixed in, however, everything
23
- # changes. Objects of the class can no longer be instanced with the `#new` method.
24
- # Instead, the various factor methods, such as `#spawn`, must be used. These factory
25
- # methods do not return direct references to the actor object. Instead they return
26
- # objects of one of the `ActorRef` subclasses. The `ActorRef` objects encapsulate
27
- # actor objects. This encapsulation is necessary to prevent synchronous method calls
28
- # froom being made against the actors. It also allows the messaging and lifecycle
29
- # behavior to be implemented within the `ActorRef` subclasses, allowing for better
30
- # separation of responsibility.
31
- #
32
- # @see Concurrent::ActorRef
33
- #
34
- # @see http://akka.io/
35
- # @see http://www.erlang.org/doc/getting_started/conc_prog.html
36
- # @see http://www.scala-lang.org/api/current/index.html#scala.actors.Actor
37
- #
38
- # @see http://doc.akka.io/docs/akka/snapshot/general/supervision.html#What_Restarting_Means What Restarting Means
39
- # @see http://doc.akka.io/docs/akka/snapshot/general/supervision.html#What_Lifecycle_Monitoring_Means What Lifecycle Monitoring Means
40
- module ActorContext
41
-
42
- # Callback method called by the `ActorRef` which encapsulates the actor instance.
43
- def on_start
44
- end
45
-
46
- # Callback method called by the `ActorRef` which encapsulates the actor instance.
47
- def on_shutdown
48
- end
49
-
50
- # Callback method called by the `ActorRef` which encapsulates the actor instance.
51
- #
52
- # @param [Time] time the date/time at which the error occurred
53
- # @param [Array] message the message that caused the error
54
- # @param [Exception] exception the exception object that was raised
55
- def on_error(time, message, exception)
56
- end
57
-
58
- def self.included(base)
59
-
60
- class << base
61
-
62
- # Create a single, unregistered actor. The actor will run on its own, dedicated
63
- # thread. The thread will be started the first time a message is post to the actor.
64
- # Should the thread ever die it will be restarted the next time a message is post.
65
- #
66
- # @param [Hash] opts the options defining actor behavior
67
- # @option opts [Array] :args (`nil`) arguments to be passed to the actor constructor
68
- #
69
- # @return [SimpleActorRef] the `ActorRef` encapsulating the actor
70
- def spawn(opts = {})
71
- args = opts.fetch(:args, [])
72
- Concurrent::SimpleActorRef.new(self.new(*args), opts)
73
- end
74
- end
75
- end
76
- end
77
- end
@@ -1,67 +0,0 @@
1
- module Concurrent
2
-
3
- # Base class for classes that encapsulate `ActorContext` objects.
4
- #
5
- # @see Concurrent::ActorContext
6
- module ActorRef
7
-
8
- # @!method post(*msg, &block)
9
- #
10
- # Send a message and return a future which will eventually be updated
11
- # with the result of the operation. An optional callback block can be
12
- # given which will be called once the operation is complete. Although
13
- # it is possible to use a callback block and also interrogate the
14
- # returned future it is a good practice to do one or the other.
15
- #
16
- # @param [Array] msg One or more elements of the message
17
- #
18
- # @yield a callback operation to be performed when the operation is complete.
19
- # @yieldparam [Time] time the date/time at which the error occurred
20
- # @yieldparam [Object] result the result of message processing or `nil` on error
21
- # @yieldparam [Exception] exception the exception object that was raised or `nil` on success
22
- #
23
- # @return [IVar] a future that will eventually contain the result of message processing
24
-
25
- # @!method post!(timeout, *msg)
26
- # Send a message synchronously and block awaiting the response.
27
- #
28
- # @param [Integer] timeout the maximum number of seconds to block waiting
29
- # for a response
30
- # @param [Array] msg One or more elements of the message
31
- #
32
- # @return [Object] the result of successful message processing
33
- #
34
- # @raise [Concurrent::TimeoutError] if a timeout occurs
35
- # @raise [Exception] an exception which occurred during message processing
36
-
37
- # @!method running?()
38
- # Is the actor running and processing messages?
39
- # @return [Boolean] `true` if running else `false`
40
-
41
- # @!method shutdown?()
42
- # Is the actor shutdown and no longer processing messages?
43
- # @return [Boolean] `true` if shutdown else `false`
44
-
45
- # @!method shutdown()
46
- # Shutdown the actor, gracefully exit all threads, and stop processing messages.
47
- # @return [Boolean] `true` if shutdown is successful else `false`
48
-
49
- # @!method join(limit = nil)
50
- # Suspend the current thread until the actor has been shutdown
51
- # @param [Integer] limit the maximum number of seconds to block waiting for the
52
- # actor to shutdown. Block indefinitely when `nil` or not given
53
- # @return [Boolean] `true` if the actor shutdown before the limit expired else `false`
54
- # @see http://www.ruby-doc.org/core-2.1.1/Thread.html#method-i-join
55
-
56
- # Send a message and return. It's a fire-and-forget interaction.
57
- #
58
- # @param [Object] message a single value representing the message to be sent
59
- # to the actor or an array of multiple message components
60
- #
61
- # @return [ActorRef] self
62
- def <<(message)
63
- post(*message)
64
- self
65
- end
66
- end
67
- end
@@ -1,94 +0,0 @@
1
- require 'concurrent/actor/actor_ref'
2
- require 'concurrent/atomic/event'
3
- require 'concurrent/executor/single_thread_executor'
4
- require 'concurrent/ivar'
5
-
6
- module Concurrent
7
-
8
- class SimpleActorRef
9
- include ActorRef
10
-
11
- def initialize(actor, opts = {})
12
- @actor = actor
13
- @mutex = Mutex.new
14
- @one_by_one = OneByOne.new
15
- @executor = OptionsParser::get_executor_from(opts)
16
- @stop_event = Event.new
17
- @reset_on_error = opts.fetch(:reset_on_error, true)
18
- @exception_class = opts.fetch(:rescue_exception, false) ? Exception : StandardError
19
- @args = opts.fetch(:args, []) if @reset_on_error
20
-
21
- @actor.define_singleton_method(:shutdown, &method(:set_stop_event))
22
- @actor.on_start
23
- end
24
-
25
- def running?
26
- not @stop_event.set?
27
- end
28
-
29
- def shutdown?
30
- @stop_event.set?
31
- end
32
-
33
- def post(*msg, &block)
34
- raise ArgumentError.new('message cannot be empty') if msg.empty?
35
- ivar = IVar.new
36
- @one_by_one.post(@executor, Message.new(msg, ivar, block), &method(:process_message))
37
- ivar
38
- end
39
-
40
- def post!(timeout, *msg)
41
- raise Concurrent::TimeoutError unless timeout.nil? || timeout >= 0
42
- ivar = self.post(*msg)
43
- ivar.value(timeout)
44
- if ivar.incomplete?
45
- raise Concurrent::TimeoutError
46
- elsif ivar.reason
47
- raise ivar.reason
48
- end
49
- ivar.value
50
- end
51
-
52
- def shutdown
53
- @mutex.synchronize do
54
- return if shutdown?
55
- @actor.on_shutdown
56
- @stop_event.set
57
- end
58
- end
59
-
60
- def join(limit = nil)
61
- @stop_event.wait(limit)
62
- end
63
-
64
- private
65
-
66
- Message = Struct.new(:payload, :ivar, :callback)
67
-
68
- def set_stop_event
69
- @stop_event.set
70
- end
71
-
72
- def process_message(message)
73
- result = ex = nil
74
-
75
- begin
76
- result = @actor.receive(*message.payload)
77
- rescue @exception_class => ex
78
- @actor.on_error(Time.now, message.payload, ex)
79
- if @reset_on_error
80
- @mutex.synchronize{ @actor = @actor.class.new(*@args) }
81
- end
82
- ensure
83
- now = Time.now
84
- message.ivar.complete(ex.nil?, result, ex)
85
-
86
- begin
87
- message.callback.call(now, result, ex) if message.callback
88
- rescue @exception_class => ex
89
- # suppress
90
- end
91
- end
92
- end
93
- end
94
- end
Binary file
@@ -1,29 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe ActorContext do
6
-
7
- let(:described_class) do
8
- Class.new do
9
- include ActorContext
10
- end
11
- end
12
-
13
- context 'callbacks' do
14
-
15
- subject { described_class.send(:new) }
16
-
17
- specify { subject.should respond_to :on_start }
18
-
19
- specify { subject.should respond_to :on_shutdown }
20
- end
21
-
22
- context '#spawn' do
23
-
24
- it 'returns an ActorRef' do
25
- described_class.spawn.should be_a ActorRef
26
- end
27
- end
28
- end
29
- end
@@ -1,263 +0,0 @@
1
- require 'spec_helper'
2
-
3
- def create_actor_test_class
4
- Class.new do
5
- include Concurrent::ActorContext
6
-
7
- attr_reader :argv
8
-
9
- def initialize(*args)
10
- @argv = args
11
- end
12
-
13
- def receive(*msg)
14
- case msg.first
15
- when :poison
16
- raise StandardError
17
- when :bullet
18
- raise Exception
19
- when :stop
20
- shutdown
21
- when :terminate
22
- Thread.current.kill
23
- when :sleep
24
- sleep(msg.last)
25
- when :check
26
- msg[1].set(msg.last)
27
- else
28
- msg.first
29
- end
30
- end
31
- end
32
- end
33
-
34
- share_examples_for :actor_ref do
35
-
36
- after(:each) do
37
- subject.shutdown
38
- end
39
-
40
- it 'includes ActorRef' do
41
- subject.should be_a Concurrent::ActorRef
42
- end
43
-
44
- context 'running and shutdown' do
45
-
46
- specify { subject.should respond_to :shutdown }
47
-
48
- specify { subject.should be_running }
49
-
50
- specify { subject.should_not be_shutdown }
51
-
52
- specify do
53
- subject.shutdown
54
- sleep(0.1)
55
- subject.should be_shutdown
56
- end
57
-
58
- it 'defines a shutdown method on the actor(s)' do
59
- subject << :foo
60
- subject << :stop
61
- sleep(0.1)
62
- subject.should be_shutdown
63
- end
64
- end
65
-
66
- context '#post' do
67
-
68
- it 'raises an exception when the message is empty' do
69
- expect {
70
- subject.post
71
- }.to raise_error(ArgumentError)
72
- end
73
-
74
- it 'returns an IVar' do
75
- subject.post(:foo).should be_a Concurrent::IVar
76
- end
77
-
78
- it 'fulfills the IVar when message is processed' do
79
- ivar = subject.post(:foo)
80
- sleep(0.1)
81
- ivar.should be_fulfilled
82
- ivar.value.should eq :foo
83
- end
84
-
85
- it 'rejects the IVar when message processing fails' do
86
- ivar = subject.post(:poison)
87
- sleep(0.1)
88
- ivar.should be_rejected
89
- ivar.reason.should be_a StandardError
90
- end
91
- end
92
-
93
- context '#<<' do
94
-
95
- it 'posts the message' do
96
- ivar = Concurrent::IVar.new
97
- subject << [:check, ivar, :foo]
98
- ivar.value(0.1).should eq :foo
99
- end
100
-
101
- it 'returns self' do
102
- expected = subject
103
- result = subject << [1,2,3,4]
104
- result.should eq expected
105
- end
106
- end
107
-
108
- context '#post with callback' do
109
-
110
- specify 'on success calls the callback with time and value' do
111
- expected_value = expected_reason = nil
112
- subject.post(:foo) do |time, value, reason|
113
- expected_value = value
114
- expected_reason = reason
115
- end
116
- sleep(0.1)
117
-
118
- expected_value.should eq :foo
119
- expected_reason.should be_nil
120
- end
121
-
122
- specify 'on failure calls the callback with time and reason' do
123
- expected_value = expected_reason = nil
124
- subject.post(:poison) do |time, value, reason|
125
- expected_value = value
126
- expected_reason = reason
127
- end
128
- sleep(0.1)
129
-
130
- expected_value.should be_nil
131
- expected_reason.should be_a StandardError
132
- end
133
-
134
- it 'supresses exceptions thrown by the callback' do
135
- expected = nil
136
- subject.post(:foo){|time, value, reason| raise StandardError }
137
- sleep(0.1)
138
-
139
- subject.post(:bar){|time, value, reason| expected = value }
140
- sleep(0.1)
141
-
142
- expected.should eq :bar
143
- end
144
- end
145
-
146
- context '#post!' do
147
-
148
- it 'raises an exception when the message is empty' do
149
- expect {
150
- subject.post!(1)
151
- }.to raise_error(ArgumentError)
152
- end
153
-
154
- it 'blocks for up to the given number of seconds' do
155
- start = Time.now.to_f
156
- begin
157
- subject.post!(1, :sleep, 2)
158
- rescue
159
- end
160
- delta = Time.now.to_f - start
161
- delta.should >= 1
162
- delta.should <= 2
163
- end
164
-
165
- it 'blocks forever when the timeout is nil' do
166
- start = Time.now.to_f
167
- subject.post!(nil, :sleep, 1)
168
- delta = Time.now.to_f - start
169
- delta.should > 1
170
- end
171
-
172
- it 'raises a TimeoutError when timeout is zero' do
173
- expect {
174
- subject.post!(0, :foo)
175
- }.to raise_error(Concurrent::TimeoutError)
176
- end
177
-
178
- it 'raises a TimeoutError when the timeout is reached' do
179
- expect {
180
- subject.post!(1, :sleep, 10)
181
- }.to raise_error(Concurrent::TimeoutError)
182
- end
183
-
184
- it 'returns the result of success processing' do
185
- subject.post!(1, :foo).should eq :foo
186
- end
187
-
188
- it 'bubbles exceptions thrown during processing' do
189
- expect {
190
- subject.post!(1, :poison)
191
- }.to raise_error(StandardError)
192
- end
193
- end
194
-
195
- context '#join' do
196
-
197
- it 'blocks until shutdown when no limit is given' do
198
- start = Time.now
199
- subject << :foo # start the actor's thread
200
- Thread.new{ sleep(1); subject.shutdown }
201
- subject.join
202
- stop = Time.now
203
-
204
- subject.should be_shutdown
205
- stop.should >= start + 1
206
- stop.should <= start + 2
207
- end
208
-
209
- it 'blocks for no more than the given number of seconds' do
210
- start = Time.now
211
- subject << :foo # start the actor's thread
212
- Thread.new{ sleep(5); subject.shutdown }
213
- subject.join(1)
214
- stop = Time.now
215
-
216
- stop.should >= start + 1
217
- stop.should <= start + 2
218
- end
219
-
220
- it 'returns true when shutdown has completed before timeout' do
221
- subject << :foo # start the actor's thread
222
- Thread.new{ sleep(1); subject.shutdown }
223
- subject.join.should be_true
224
- end
225
-
226
- it 'returns false on timeout' do
227
- subject << :foo # start the actor's thread
228
- Thread.new{ sleep(5); subject.shutdown }
229
- subject.join(1).should be_false
230
- end
231
-
232
- it 'returns immediately when already shutdown' do
233
- start = Time.now
234
- subject << :foo # start the actor's thread
235
- sleep(0.1)
236
- subject.shutdown
237
- sleep(0.1)
238
-
239
- start = Time.now
240
- subject.join
241
- Time.now.should >= start
242
- Time.now.should <= start + 0.1
243
- end
244
- end
245
-
246
- context '#on_error' do
247
-
248
- specify 'is not called on success' do
249
- actor = subject.instance_variable_get(:@actor)
250
- actor.should_not_receive(:on_error).with(any_args)
251
- subject.post(:foo)
252
- sleep(0.1)
253
- end
254
-
255
- specify 'is called when a message raises an exception' do
256
- actor = subject.instance_variable_get(:@actor)
257
- actor.should_receive(:on_error).
258
- with(anything, [:poison], an_instance_of(StandardError))
259
- subject.post(:poison)
260
- sleep(0.1)
261
- end
262
- end
263
- end