concurrent-ruby 0.6.0.pre.1 → 0.6.0.pre.2
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.
- checksums.yaml +4 -4
- data/README.md +16 -0
- data/lib/concurrent.rb +9 -29
- data/lib/concurrent/{actor.rb → actor/actor.rb} +3 -3
- data/lib/concurrent/actor/actor_context.rb +77 -0
- data/lib/concurrent/actor/actor_ref.rb +67 -0
- data/lib/concurrent/{postable.rb → actor/postable.rb} +1 -1
- data/lib/concurrent/actor/simple_actor_ref.rb +94 -0
- data/lib/concurrent/actors.rb +5 -0
- data/lib/concurrent/agent.rb +81 -47
- data/lib/concurrent/async.rb +35 -35
- data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +170 -0
- data/lib/concurrent/{condition.rb → atomic/condition.rb} +0 -0
- data/lib/concurrent/{copy_on_notify_observer_set.rb → atomic/copy_on_notify_observer_set.rb} +48 -13
- data/lib/concurrent/{copy_on_write_observer_set.rb → atomic/copy_on_write_observer_set.rb} +41 -20
- data/lib/concurrent/atomic/count_down_latch.rb +116 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
- data/lib/concurrent/atomic/event.rb +103 -0
- data/lib/concurrent/{thread_local_var.rb → atomic/thread_local_var.rb} +0 -0
- data/lib/concurrent/atomics.rb +9 -0
- data/lib/concurrent/channel/buffered_channel.rb +6 -4
- data/lib/concurrent/channel/channel.rb +30 -2
- data/lib/concurrent/channel/unbuffered_channel.rb +2 -2
- data/lib/concurrent/channel/waitable_list.rb +3 -1
- data/lib/concurrent/channels.rb +5 -0
- data/lib/concurrent/{channel → collection}/blocking_ring_buffer.rb +16 -5
- data/lib/concurrent/collection/priority_queue.rb +305 -0
- data/lib/concurrent/{channel → collection}/ring_buffer.rb +6 -1
- data/lib/concurrent/collections.rb +3 -0
- data/lib/concurrent/configuration.rb +68 -19
- data/lib/concurrent/dataflow.rb +9 -9
- data/lib/concurrent/delay.rb +21 -13
- data/lib/concurrent/dereferenceable.rb +40 -33
- data/lib/concurrent/exchanger.rb +3 -0
- data/lib/concurrent/{cached_thread_pool.rb → executor/cached_thread_pool.rb} +8 -9
- data/lib/concurrent/executor/executor.rb +222 -0
- data/lib/concurrent/{fixed_thread_pool.rb → executor/fixed_thread_pool.rb} +6 -7
- data/lib/concurrent/{immediate_executor.rb → executor/immediate_executor.rb} +5 -5
- data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
- data/lib/concurrent/{java_fixed_thread_pool.rb → executor/java_fixed_thread_pool.rb} +7 -11
- data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
- data/lib/concurrent/{java_thread_pool_executor.rb → executor/java_thread_pool_executor.rb} +66 -77
- data/lib/concurrent/executor/one_by_one.rb +65 -0
- data/lib/concurrent/{per_thread_executor.rb → executor/per_thread_executor.rb} +4 -4
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
- data/lib/concurrent/{ruby_fixed_thread_pool.rb → executor/ruby_fixed_thread_pool.rb} +5 -4
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +72 -0
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +282 -0
- data/lib/concurrent/{ruby_thread_pool_worker.rb → executor/ruby_thread_pool_worker.rb} +6 -6
- data/lib/concurrent/{safe_task_executor.rb → executor/safe_task_executor.rb} +20 -13
- data/lib/concurrent/executor/single_thread_executor.rb +35 -0
- data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
- data/lib/concurrent/executor/timer_set.rb +138 -0
- data/lib/concurrent/executors.rb +9 -0
- data/lib/concurrent/future.rb +39 -40
- data/lib/concurrent/ivar.rb +22 -15
- data/lib/concurrent/mvar.rb +2 -1
- data/lib/concurrent/obligation.rb +9 -3
- data/lib/concurrent/observable.rb +33 -0
- data/lib/concurrent/options_parser.rb +46 -0
- data/lib/concurrent/promise.rb +23 -24
- data/lib/concurrent/scheduled_task.rb +21 -45
- data/lib/concurrent/timer_task.rb +204 -126
- data/lib/concurrent/tvar.rb +1 -1
- data/lib/concurrent/utilities.rb +3 -36
- data/lib/concurrent/{processor_count.rb → utility/processor_count.rb} +1 -1
- data/lib/concurrent/utility/timeout.rb +36 -0
- data/lib/concurrent/utility/timer.rb +21 -0
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.bundle +0 -0
- data/spec/concurrent/{actor_context_spec.rb → actor/actor_context_spec.rb} +0 -8
- data/spec/concurrent/{actor_ref_shared.rb → actor/actor_ref_shared.rb} +9 -59
- data/spec/concurrent/{actor_spec.rb → actor/actor_spec.rb} +43 -41
- data/spec/concurrent/{postable_shared.rb → actor/postable_shared.rb} +0 -0
- data/spec/concurrent/actor/simple_actor_ref_spec.rb +135 -0
- data/spec/concurrent/agent_spec.rb +160 -71
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +172 -0
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +186 -0
- data/spec/concurrent/{condition_spec.rb → atomic/condition_spec.rb} +2 -2
- data/spec/concurrent/{copy_on_notify_observer_set_spec.rb → atomic/copy_on_notify_observer_set_spec.rb} +0 -0
- data/spec/concurrent/{copy_on_write_observer_set_spec.rb → atomic/copy_on_write_observer_set_spec.rb} +0 -0
- data/spec/concurrent/atomic/count_down_latch_spec.rb +151 -0
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +248 -0
- data/spec/concurrent/{event_spec.rb → atomic/event_spec.rb} +18 -3
- data/spec/concurrent/{observer_set_shared.rb → atomic/observer_set_shared.rb} +15 -6
- data/spec/concurrent/{thread_local_var_spec.rb → atomic/thread_local_var_spec.rb} +0 -0
- data/spec/concurrent/channel/buffered_channel_spec.rb +1 -1
- data/spec/concurrent/channel/channel_spec.rb +6 -4
- data/spec/concurrent/channel/probe_spec.rb +37 -9
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +2 -2
- data/spec/concurrent/{channel → collection}/blocking_ring_buffer_spec.rb +0 -0
- data/spec/concurrent/collection/priority_queue_spec.rb +317 -0
- data/spec/concurrent/{channel → collection}/ring_buffer_spec.rb +0 -0
- data/spec/concurrent/configuration_spec.rb +4 -70
- data/spec/concurrent/dereferenceable_shared.rb +5 -4
- data/spec/concurrent/exchanger_spec.rb +10 -5
- data/spec/concurrent/{cached_thread_pool_shared.rb → executor/cached_thread_pool_shared.rb} +15 -37
- data/spec/concurrent/{fixed_thread_pool_shared.rb → executor/fixed_thread_pool_shared.rb} +0 -0
- data/spec/concurrent/{global_thread_pool_shared.rb → executor/global_thread_pool_shared.rb} +10 -8
- data/spec/concurrent/{immediate_executor_spec.rb → executor/immediate_executor_spec.rb} +0 -0
- data/spec/concurrent/{java_cached_thread_pool_spec.rb → executor/java_cached_thread_pool_spec.rb} +1 -21
- data/spec/concurrent/{java_fixed_thread_pool_spec.rb → executor/java_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +21 -0
- data/spec/concurrent/{java_thread_pool_executor_spec.rb → executor/java_thread_pool_executor_spec.rb} +0 -0
- data/spec/concurrent/{per_thread_executor_spec.rb → executor/per_thread_executor_spec.rb} +0 -4
- data/spec/concurrent/{ruby_cached_thread_pool_spec.rb → executor/ruby_cached_thread_pool_spec.rb} +1 -1
- data/spec/concurrent/{ruby_fixed_thread_pool_spec.rb → executor/ruby_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +18 -0
- data/spec/concurrent/{ruby_thread_pool_executor_spec.rb → executor/ruby_thread_pool_executor_spec.rb} +12 -24
- data/spec/concurrent/executor/safe_task_executor_spec.rb +103 -0
- data/spec/concurrent/{thread_pool_class_cast_spec.rb → executor/thread_pool_class_cast_spec.rb} +12 -0
- data/spec/concurrent/{thread_pool_executor_shared.rb → executor/thread_pool_executor_shared.rb} +0 -0
- data/spec/concurrent/{thread_pool_shared.rb → executor/thread_pool_shared.rb} +84 -119
- data/spec/concurrent/executor/timer_set_spec.rb +183 -0
- data/spec/concurrent/future_spec.rb +12 -0
- data/spec/concurrent/ivar_spec.rb +11 -1
- data/spec/concurrent/observable_shared.rb +173 -0
- data/spec/concurrent/observable_spec.rb +51 -0
- data/spec/concurrent/options_parser_spec.rb +71 -0
- data/spec/concurrent/runnable_shared.rb +6 -0
- data/spec/concurrent/scheduled_task_spec.rb +60 -40
- data/spec/concurrent/timer_task_spec.rb +130 -144
- data/spec/concurrent/{processor_count_spec.rb → utility/processor_count_spec.rb} +0 -0
- data/spec/concurrent/{utilities_spec.rb → utility/timeout_spec.rb} +0 -0
- data/spec/concurrent/utility/timer_spec.rb +52 -0
- metadata +147 -108
- data/lib/concurrent/actor_context.rb +0 -31
- data/lib/concurrent/actor_ref.rb +0 -39
- data/lib/concurrent/atomic.rb +0 -121
- data/lib/concurrent/channel/probe.rb +0 -19
- data/lib/concurrent/count_down_latch.rb +0 -60
- data/lib/concurrent/event.rb +0 -80
- data/lib/concurrent/java_cached_thread_pool.rb +0 -45
- data/lib/concurrent/ruby_cached_thread_pool.rb +0 -37
- data/lib/concurrent/ruby_thread_pool_executor.rb +0 -268
- data/lib/concurrent/simple_actor_ref.rb +0 -124
- data/lib/concurrent/thread_pool_executor.rb +0 -30
- data/spec/concurrent/atomic_spec.rb +0 -201
- data/spec/concurrent/count_down_latch_spec.rb +0 -125
- data/spec/concurrent/safe_task_executor_spec.rb +0 -58
- data/spec/concurrent/simple_actor_ref_spec.rb +0 -219
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 | 
             
            require_relative 'dereferenceable_shared'
         | 
| 3 3 | 
             
            require_relative 'obligation_shared'
         | 
| 4 | 
            +
            require_relative 'observable_shared'
         | 
| 4 5 |  | 
| 5 6 | 
             
            module Concurrent
         | 
| 6 7 |  | 
| @@ -54,6 +55,17 @@ module Concurrent | |
| 54 55 | 
             
                  end
         | 
| 55 56 |  | 
| 56 57 | 
             
                  it_should_behave_like :dereferenceable
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  # observable
         | 
| 60 | 
            +
                  
         | 
| 61 | 
            +
                  subject{ Future.new{ nil } }
         | 
| 62 | 
            +
                  
         | 
| 63 | 
            +
                  def trigger_observable(observable)
         | 
| 64 | 
            +
                    observable.execute
         | 
| 65 | 
            +
                    sleep(0.1)
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  it_should_behave_like :observable
         | 
| 57 69 | 
             
                end
         | 
| 58 70 |  | 
| 59 71 | 
             
                context 'subclassing' do
         | 
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 | 
             
            require_relative 'dereferenceable_shared'
         | 
| 3 3 | 
             
            require_relative 'obligation_shared'
         | 
| 4 | 
            +
            require_relative 'observable_shared'
         | 
| 4 5 |  | 
| 5 6 | 
             
            module Concurrent
         | 
| 6 7 |  | 
| @@ -56,10 +57,19 @@ module Concurrent | |
| 56 57 |  | 
| 57 58 | 
             
                  def execute_dereferenceable(subject)
         | 
| 58 59 | 
             
                    subject.set('value')
         | 
| 59 | 
            -
                    sleep(0.1)
         | 
| 60 60 | 
             
                  end
         | 
| 61 61 |  | 
| 62 62 | 
             
                  it_should_behave_like :dereferenceable
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  # observable
         | 
| 65 | 
            +
                  
         | 
| 66 | 
            +
                  subject{ IVar.new }
         | 
| 67 | 
            +
                  
         | 
| 68 | 
            +
                  def trigger_observable(observable)
         | 
| 69 | 
            +
                    observable.set('value')
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  it_should_behave_like :observable
         | 
| 63 73 | 
             
                end
         | 
| 64 74 |  | 
| 65 75 | 
             
                context '#initialize' do
         | 
| @@ -0,0 +1,173 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            share_examples_for :observable do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              let(:observer_set) do
         | 
| 6 | 
            +
                subject.instance_variable_get(:@observers)
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              let(:observer_class) do
         | 
| 10 | 
            +
                Class.new do
         | 
| 11 | 
            +
                  def initialize(&block)
         | 
| 12 | 
            +
                    @block = block
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                  def update(*args)
         | 
| 15 | 
            +
                    @block.call(*args) if @block
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              let(:observer){ observer_class.new }
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              let!(:observer_func){ :notify }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              let(:observer_with_func_class) do
         | 
| 25 | 
            +
                Class.new do
         | 
| 26 | 
            +
                  def initialize(&block)
         | 
| 27 | 
            +
                    @block = block
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                  def notify(*args)
         | 
| 30 | 
            +
                    @block.call(*args) if @block
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              let(:observer_with_func){ observer_with_func_class.new }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              context '#add_observer' do
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                it 'adds an observer if called before first notification' do
         | 
| 40 | 
            +
                  observer_set.should_receive(:add_observer).with(any_args)
         | 
| 41 | 
            +
                  subject.add_observer(observer)
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                it 'adds an observer with :func if called before first notification' do
         | 
| 45 | 
            +
                  observer_set.should_receive(:add_observer).with(observer_with_func, :notify)
         | 
| 46 | 
            +
                  subject.add_observer(observer_with_func, observer_func)
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                it 'creates an observer from a block if called before first notification' do
         | 
| 50 | 
            +
                  block = proc{ nil }
         | 
| 51 | 
            +
                  observer_set.should_receive(:add_observer).with(any_args)
         | 
| 52 | 
            +
                  subject.add_observer(&block)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                it 'raises an exception if not given an observer or a block' do
         | 
| 56 | 
            +
                  expect {
         | 
| 57 | 
            +
                    subject.add_observer
         | 
| 58 | 
            +
                  }.to raise_error(ArgumentError)
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                it 'raises an exception when given both an observer and a block' do
         | 
| 62 | 
            +
                  expect {
         | 
| 63 | 
            +
                    subject.add_observer(observer){ nil }
         | 
| 64 | 
            +
                  }.to raise_error(ArgumentError)
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
              
         | 
| 68 | 
            +
              context '#delete_observer' do
         | 
| 69 | 
            +
              
         | 
| 70 | 
            +
                it 'deletes the given observer if called before first notification' do
         | 
| 71 | 
            +
                  subject.count_observers.should eq 0
         | 
| 72 | 
            +
                  subject.add_observer(observer)
         | 
| 73 | 
            +
                  subject.count_observers.should eq 1
         | 
| 74 | 
            +
                  subject.delete_observer(observer)
         | 
| 75 | 
            +
                  subject.count_observers.should eq 0
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                it 'returns the removed observer if found in the observer set' do
         | 
| 79 | 
            +
                  subject.add_observer(observer)
         | 
| 80 | 
            +
                  subject.delete_observer(observer).should eq observer
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                it 'returns the given observer even when not found in the observer set' do
         | 
| 84 | 
            +
                  subject.delete_observer(observer).should eq observer
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
              
         | 
| 88 | 
            +
              context '#delete_observers' do
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                it 'deletes all observers when called before first notification' do
         | 
| 91 | 
            +
                  5.times{ subject.add_observer(observer_class.new) }
         | 
| 92 | 
            +
                  subject.count_observers.should eq 5
         | 
| 93 | 
            +
                  subject.delete_observers
         | 
| 94 | 
            +
                  subject.count_observers.should eq 0
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                it 'returns self' do
         | 
| 98 | 
            +
                  subject.delete_observers.should eq subject
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
              end
         | 
| 101 | 
            +
              
         | 
| 102 | 
            +
              context '#count_observers' do
         | 
| 103 | 
            +
              
         | 
| 104 | 
            +
                it 'returns zero for a new observable object' do
         | 
| 105 | 
            +
                  subject.count_observers.should eq 0
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                it 'returns a count of registered observers if called before first notification' do
         | 
| 109 | 
            +
                  5.times{ subject.add_observer(observer_class.new) }
         | 
| 110 | 
            +
                  subject.count_observers.should eq 5
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                it 'returns zero after #delete_observers has been called' do
         | 
| 114 | 
            +
                  5.times{ subject.add_observer(observer_class.new) }
         | 
| 115 | 
            +
                  subject.delete_observers
         | 
| 116 | 
            +
                  subject.count_observers.should eq 0
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
              end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
              context 'first notification' do
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                it 'calls the #update method on all observers without a specified :func' do
         | 
| 123 | 
            +
                  latch = Concurrent::CountDownLatch.new(5)
         | 
| 124 | 
            +
                  5.times do
         | 
| 125 | 
            +
                    subject.add_observer(observer_class.new{ latch.count_down })
         | 
| 126 | 
            +
                  end
         | 
| 127 | 
            +
                  trigger_observable(subject)
         | 
| 128 | 
            +
                  latch.count.should eq 0
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                it 'calls the appropriate function on all observers which specified a :func' do
         | 
| 132 | 
            +
                  latch = Concurrent::CountDownLatch.new(5)
         | 
| 133 | 
            +
                  5.times do
         | 
| 134 | 
            +
                    obs = observer_with_func_class.new{ latch.count_down }
         | 
| 135 | 
            +
                    subject.add_observer(obs, observer_func)
         | 
| 136 | 
            +
                  end
         | 
| 137 | 
            +
                  trigger_observable(subject)
         | 
| 138 | 
            +
                  latch.count.should eq 0
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                it 'calls the proc for all observers added as a block' do
         | 
| 142 | 
            +
                  latch = Concurrent::CountDownLatch.new(5)
         | 
| 143 | 
            +
                  5.times do
         | 
| 144 | 
            +
                    subject.add_observer{ latch.count_down }
         | 
| 145 | 
            +
                  end
         | 
| 146 | 
            +
                  trigger_observable(subject)
         | 
| 147 | 
            +
                  latch.count.should eq 0
         | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                it 'does not notify any observers removed with #delete_observer' do
         | 
| 151 | 
            +
                  latch = Concurrent::CountDownLatch.new(5)
         | 
| 152 | 
            +
                  
         | 
| 153 | 
            +
                  obs = observer_class.new{ latch.count_down }
         | 
| 154 | 
            +
                  subject.add_observer(obs)
         | 
| 155 | 
            +
                  subject.delete_observer(obs)
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                  trigger_observable(subject)
         | 
| 158 | 
            +
                  latch.count.should eq 5
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                it 'does not notify any observers after #delete_observers called' do
         | 
| 162 | 
            +
                  latch = Concurrent::CountDownLatch.new(5)
         | 
| 163 | 
            +
                  5.times do
         | 
| 164 | 
            +
                    subject.add_observer(observer_class.new{ latch.count_down })
         | 
| 165 | 
            +
                  end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                  subject.delete_observers
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                  trigger_observable(subject)
         | 
| 170 | 
            +
                  latch.count.should eq 5
         | 
| 171 | 
            +
                end
         | 
| 172 | 
            +
              end
         | 
| 173 | 
            +
            end
         | 
| @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Concurrent
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              describe Observable do
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                let (:described_class) do
         | 
| 8 | 
            +
                  Class.new do
         | 
| 9 | 
            +
                    include Concurrent::Observable
         | 
| 10 | 
            +
                    public :observers, :observers=
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                let(:observer_set) { double(:observer_set) }
         | 
| 15 | 
            +
                subject { described_class.new }
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                before(:each) do
         | 
| 18 | 
            +
                  subject.observers = observer_set
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                it 'does not initialize set by by default' do
         | 
| 22 | 
            +
                  described_class.new.observers.should be_nil
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                it 'uses the given observer set' do
         | 
| 26 | 
            +
                  expected = CopyOnWriteObserverSet.new
         | 
| 27 | 
            +
                  subject.observers = expected
         | 
| 28 | 
            +
                  subject.observers.should eql expected
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                it 'delegates #add_observer' do
         | 
| 32 | 
            +
                  observer_set.should_receive(:add_observer).with(:observer)
         | 
| 33 | 
            +
                  subject.add_observer(:observer)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                it 'delegates #delete_observer' do
         | 
| 37 | 
            +
                  observer_set.should_receive(:delete_observer).with(:observer)
         | 
| 38 | 
            +
                  subject.delete_observer(:observer)
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                it 'delegates #delete_observers' do
         | 
| 42 | 
            +
                  observer_set.should_receive(:delete_observers).with(no_args)
         | 
| 43 | 
            +
                  subject.delete_observers
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                it 'delegates #count_observers' do
         | 
| 47 | 
            +
                  observer_set.should_receive(:count_observers).with(no_args)
         | 
| 48 | 
            +
                  subject.count_observers
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
            end
         | 
| @@ -0,0 +1,71 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Concurrent
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              describe OptionsParser do
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                let(:executor){ ImmediateExecutor.new }
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                let(:task_pool){ ImmediateExecutor.new }
         | 
| 10 | 
            +
                let(:operation_pool){ ImmediateExecutor.new }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                context '#get_executor_from' do
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  it 'returns the given :executor' do
         | 
| 15 | 
            +
                    OptionsParser::get_executor_from(executor: executor).should eq executor
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  it 'returns the global operation pool when :operation is true' do
         | 
| 19 | 
            +
                    Concurrent.configuration.should_receive(:global_operation_pool).
         | 
| 20 | 
            +
                      and_return(:operation_pool)
         | 
| 21 | 
            +
                    OptionsParser::get_executor_from(operation: true)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  it 'returns the global task pool when :operation is false' do
         | 
| 25 | 
            +
                    Concurrent.configuration.should_receive(:global_task_pool).
         | 
| 26 | 
            +
                      and_return(:task_pool)
         | 
| 27 | 
            +
                    OptionsParser::get_executor_from(operation: false)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  it 'returns the global operation pool when :task is false' do
         | 
| 31 | 
            +
                    Concurrent.configuration.should_receive(:global_operation_pool).
         | 
| 32 | 
            +
                      and_return(:operation_pool)
         | 
| 33 | 
            +
                    OptionsParser::get_executor_from(task: false)
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  it 'returns the global task pool when :task is true' do
         | 
| 37 | 
            +
                    Concurrent.configuration.should_receive(:global_task_pool).
         | 
| 38 | 
            +
                      and_return(:task_pool)
         | 
| 39 | 
            +
                    OptionsParser::get_executor_from(task: true)
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  it 'returns the global task pool when :executor is nil' do
         | 
| 43 | 
            +
                    Concurrent.configuration.should_receive(:global_task_pool).
         | 
| 44 | 
            +
                      and_return(:task_pool)
         | 
| 45 | 
            +
                    OptionsParser::get_executor_from(executor: nil)
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  it 'returns the global task pool when no option is given' do
         | 
| 49 | 
            +
                    Concurrent.configuration.should_receive(:global_task_pool).
         | 
| 50 | 
            +
                      and_return(:task_pool)
         | 
| 51 | 
            +
                    OptionsParser::get_executor_from
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  specify ':executor overrides :operation' do
         | 
| 55 | 
            +
                    OptionsParser::get_executor_from(executor: executor, operation: true).
         | 
| 56 | 
            +
                      should eq executor
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  specify ':executor overrides :task' do
         | 
| 60 | 
            +
                    OptionsParser::get_executor_from(executor: executor, task: true).
         | 
| 61 | 
            +
                      should eq executor
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  specify ':operation overrides :task' do
         | 
| 65 | 
            +
                    Concurrent.configuration.should_receive(:global_operation_pool).
         | 
| 66 | 
            +
                      and_return(:operation_pool)
         | 
| 67 | 
            +
                    OptionsParser::get_executor_from(operation: true, task: true)
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
            end
         | 
| @@ -55,7 +55,13 @@ share_examples_for :runnable do | |
| 55 55 | 
             
                  subject.should be_running
         | 
| 56 56 | 
             
                end
         | 
| 57 57 |  | 
| 58 | 
            +
                it 'returns false when first created' do
         | 
| 59 | 
            +
                  subject.should_not be_running
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 58 62 | 
             
                it 'returns false when not running' do
         | 
| 63 | 
            +
                  subject.stop
         | 
| 64 | 
            +
                  sleep(0.1)
         | 
| 59 65 | 
             
                  subject.should_not be_running
         | 
| 60 66 | 
             
                end
         | 
| 61 67 | 
             
              end
         | 
| @@ -2,6 +2,7 @@ require 'spec_helper' | |
| 2 2 | 
             
            require 'timecop'
         | 
| 3 3 | 
             
            require_relative 'dereferenceable_shared'
         | 
| 4 4 | 
             
            require_relative 'obligation_shared'
         | 
| 5 | 
            +
            require_relative 'observable_shared'
         | 
| 5 6 |  | 
| 6 7 | 
             
            module Concurrent
         | 
| 7 8 |  | 
| @@ -19,11 +20,19 @@ module Concurrent | |
| 19 20 | 
             
                  end
         | 
| 20 21 |  | 
| 21 22 | 
             
                  let(:fulfilled_subject) do
         | 
| 22 | 
            -
                     | 
| 23 | 
            +
                    latch = Concurrent::CountDownLatch.new(1)
         | 
| 24 | 
            +
                    task = ScheduledTask.new(0.1){ latch.count_down; fulfilled_value }.execute
         | 
| 25 | 
            +
                    latch.wait(1)
         | 
| 26 | 
            +
                    sleep(0.1)
         | 
| 27 | 
            +
                    task
         | 
| 23 28 | 
             
                  end
         | 
| 24 29 |  | 
| 25 30 | 
             
                  let(:rejected_subject) do
         | 
| 26 | 
            -
                     | 
| 31 | 
            +
                    latch = Concurrent::CountDownLatch.new(1)
         | 
| 32 | 
            +
                    task = ScheduledTask.new(0.1){ latch.count_down; raise rejected_reason }.execute
         | 
| 33 | 
            +
                    latch.wait(1)
         | 
| 34 | 
            +
                    sleep(0.1)
         | 
| 35 | 
            +
                    task
         | 
| 27 36 | 
             
                  end
         | 
| 28 37 |  | 
| 29 38 | 
             
                  it_should_behave_like :obligation
         | 
| @@ -44,6 +53,17 @@ module Concurrent | |
| 44 53 | 
             
                  end
         | 
| 45 54 |  | 
| 46 55 | 
             
                  it_should_behave_like :dereferenceable
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  # observable
         | 
| 58 | 
            +
                  
         | 
| 59 | 
            +
                  subject{ ScheduledTask.new(0.1){ nil } }
         | 
| 60 | 
            +
                  
         | 
| 61 | 
            +
                  def trigger_observable(observable)
         | 
| 62 | 
            +
                    observable.execute
         | 
| 63 | 
            +
                    sleep(0.2)
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  it_should_behave_like :observable
         | 
| 47 67 | 
             
                end
         | 
| 48 68 |  | 
| 49 69 | 
             
                context '#initialize' do
         | 
| @@ -65,19 +85,19 @@ module Concurrent | |
| 65 85 | 
             
                  it 'raises an exception when seconds is less than zero' do
         | 
| 66 86 | 
             
                    expect {
         | 
| 67 87 | 
             
                      ScheduledTask.new(-1){ nil }
         | 
| 68 | 
            -
                    }.to raise_error( | 
| 88 | 
            +
                    }.to raise_error(ArgumentError)
         | 
| 69 89 | 
             
                  end
         | 
| 70 90 |  | 
| 71 91 | 
             
                  it 'raises an exception when schedule time is in the past' do
         | 
| 72 92 | 
             
                    expect {
         | 
| 73 93 | 
             
                      ScheduledTask.new(Time.now - 60){ nil }
         | 
| 74 | 
            -
                    }.to raise_error( | 
| 94 | 
            +
                    }.to raise_error(ArgumentError)
         | 
| 75 95 | 
             
                  end
         | 
| 76 96 |  | 
| 77 97 | 
             
                  it 'raises an exception when no block given' do
         | 
| 78 98 | 
             
                    expect {
         | 
| 79 99 | 
             
                      ScheduledTask.new(1)
         | 
| 80 | 
            -
                    }.to raise_error( | 
| 100 | 
            +
                    }.to raise_error(ArgumentError)
         | 
| 81 101 | 
             
                  end
         | 
| 82 102 |  | 
| 83 103 | 
             
                  it 'sets the initial state to :unscheduled' do
         | 
| @@ -121,16 +141,10 @@ module Concurrent | |
| 121 141 | 
             
                      Timecop.travel(60)
         | 
| 122 142 | 
             
                      expect {
         | 
| 123 143 | 
             
                        task.execute
         | 
| 124 | 
            -
                      }.to raise_error( | 
| 144 | 
            +
                      }.to raise_error(ArgumentError)
         | 
| 125 145 | 
             
                    end
         | 
| 126 146 | 
             
                  end
         | 
| 127 147 |  | 
| 128 | 
            -
                  it 'spawns a new thread when a block was given on construction' do
         | 
| 129 | 
            -
                    Thread.should_receive(:new).with(any_args)
         | 
| 130 | 
            -
                    task = ScheduledTask.new(1){ nil }
         | 
| 131 | 
            -
                    task.execute
         | 
| 132 | 
            -
                  end
         | 
| 133 | 
            -
             | 
| 134 148 | 
             
                  it 'sets the sate to :pending' do
         | 
| 135 149 | 
             
                    task = ScheduledTask.new(1){ nil }
         | 
| 136 150 | 
             
                    task.execute
         | 
| @@ -153,7 +167,7 @@ module Concurrent | |
| 153 167 | 
             
                  it 'passes the block to the new ScheduledTask' do
         | 
| 154 168 | 
             
                    @expected = false
         | 
| 155 169 | 
             
                    task = ScheduledTask.execute(0.1){ @expected = true }
         | 
| 156 | 
            -
                     | 
| 170 | 
            +
                    task.value(1)
         | 
| 157 171 | 
             
                    @expected.should be_true
         | 
| 158 172 | 
             
                  end
         | 
| 159 173 |  | 
| @@ -169,37 +183,39 @@ module Concurrent | |
| 169 183 |  | 
| 170 184 | 
             
                  it 'returns false if the task has already been performed' do
         | 
| 171 185 | 
             
                    task = ScheduledTask.new(0.1){ 42 }.execute
         | 
| 172 | 
            -
                     | 
| 186 | 
            +
                    task.value(1)
         | 
| 173 187 | 
             
                    task.cancel.should be_false
         | 
| 174 188 | 
             
                  end
         | 
| 175 189 |  | 
| 176 190 | 
             
                  it 'returns false if the task is already in progress' do
         | 
| 177 | 
            -
                     | 
| 178 | 
            -
                     | 
| 191 | 
            +
                    latch = Concurrent::CountDownLatch.new(1)
         | 
| 192 | 
            +
                    task = ScheduledTask.new(0.1) {
         | 
| 193 | 
            +
                      latch.count_down
         | 
| 194 | 
            +
                      sleep(1)
         | 
| 195 | 
            +
                    }.execute
         | 
| 196 | 
            +
                    latch.wait(1)
         | 
| 179 197 | 
             
                    task.cancel.should be_false
         | 
| 180 198 | 
             
                  end
         | 
| 181 199 |  | 
| 182 200 | 
             
                  it 'cancels the task if it has not yet scheduled' do
         | 
| 183 | 
            -
                     | 
| 184 | 
            -
                    task = ScheduledTask.new(0.1){  | 
| 201 | 
            +
                    latch = Concurrent::CountDownLatch.new(1)
         | 
| 202 | 
            +
                    task = ScheduledTask.new(0.1){ latch.count_down }
         | 
| 185 203 | 
             
                    task.cancel
         | 
| 186 204 | 
             
                    task.execute
         | 
| 187 | 
            -
                     | 
| 188 | 
            -
                    @expected.should be_true
         | 
| 205 | 
            +
                    latch.wait(0.3).should be_false
         | 
| 189 206 | 
             
                  end
         | 
| 190 207 |  | 
| 191 208 |  | 
| 192 209 | 
             
                  it 'cancels the task if it has not yet started' do
         | 
| 193 | 
            -
                     | 
| 194 | 
            -
                    task = ScheduledTask.new(0.3){  | 
| 210 | 
            +
                    latch = Concurrent::CountDownLatch.new(1)
         | 
| 211 | 
            +
                    task = ScheduledTask.new(0.3){ latch.count_down }.execute
         | 
| 195 212 | 
             
                    sleep(0.1)
         | 
| 196 213 | 
             
                    task.cancel
         | 
| 197 | 
            -
                     | 
| 198 | 
            -
                    @expected.should be_true
         | 
| 214 | 
            +
                    latch.wait(0.5).should be_false
         | 
| 199 215 | 
             
                  end
         | 
| 200 216 |  | 
| 201 217 | 
             
                  it 'returns true on success' do
         | 
| 202 | 
            -
                    task = ScheduledTask.new( | 
| 218 | 
            +
                    task = ScheduledTask.new(10){ nil }.execute
         | 
| 203 219 | 
             
                    sleep(0.1)
         | 
| 204 220 | 
             
                    task.cancel.should be_true
         | 
| 205 221 | 
             
                  end
         | 
| @@ -215,8 +231,12 @@ module Concurrent | |
| 215 231 | 
             
                context 'execution' do
         | 
| 216 232 |  | 
| 217 233 | 
             
                  it 'sets the state to :in_progress when the task is running' do
         | 
| 218 | 
            -
                     | 
| 219 | 
            -
                     | 
| 234 | 
            +
                    latch = Concurrent::CountDownLatch.new(1)
         | 
| 235 | 
            +
                    task = ScheduledTask.new(0.1) {
         | 
| 236 | 
            +
                      latch.count_down
         | 
| 237 | 
            +
                      sleep(1)
         | 
| 238 | 
            +
                    }.execute
         | 
| 239 | 
            +
                    latch.wait(1)
         | 
| 220 240 | 
             
                    task.should be_in_progress
         | 
| 221 241 | 
             
                  end
         | 
| 222 242 | 
             
                end
         | 
| @@ -228,10 +248,15 @@ module Concurrent | |
| 228 248 | 
             
                      attr_reader :value
         | 
| 229 249 | 
             
                      attr_reader :reason
         | 
| 230 250 | 
             
                      attr_reader :count
         | 
| 231 | 
            -
                       | 
| 251 | 
            +
                      attr_reader :latch
         | 
| 252 | 
            +
                      def initialize
         | 
| 253 | 
            +
                        @latch = Concurrent::CountDownLatch.new(1)
         | 
| 254 | 
            +
                      end
         | 
| 255 | 
            +
                      def update(time, value, reason)
         | 
| 232 256 | 
             
                        @count = @count.to_i + 1
         | 
| 233 257 | 
             
                        @value = value
         | 
| 234 258 | 
             
                        @reason = reason
         | 
| 259 | 
            +
                        @latch.count_down
         | 
| 235 260 | 
             
                      end
         | 
| 236 261 | 
             
                    end
         | 
| 237 262 | 
             
                  end
         | 
| @@ -262,22 +287,20 @@ module Concurrent | |
| 262 287 |  | 
| 263 288 | 
             
                  it 'returns false for an observer added once :fulfilled' do
         | 
| 264 289 | 
             
                    task = ScheduledTask.new(0.1){ 42 }.execute
         | 
| 265 | 
            -
                     | 
| 290 | 
            +
                    task.value(1)
         | 
| 266 291 | 
             
                    task.add_observer(observer).should be_false
         | 
| 267 292 | 
             
                  end
         | 
| 268 293 |  | 
| 269 294 | 
             
                  it 'returns false for an observer added once :rejected' do
         | 
| 270 295 | 
             
                    task = ScheduledTask.new(0.1){ raise StandardError }.execute
         | 
| 271 | 
            -
                     | 
| 296 | 
            +
                    task.value(0.2)
         | 
| 272 297 | 
             
                    task.add_observer(observer).should be_false
         | 
| 273 298 | 
             
                  end
         | 
| 274 299 |  | 
| 275 300 | 
             
                  it 'notifies all observers on fulfillment' do
         | 
| 276 301 | 
             
                    task = ScheduledTask.new(0.1){ 42 }.execute
         | 
| 277 302 | 
             
                    task.add_observer(observer)
         | 
| 278 | 
            -
                     | 
| 279 | 
            -
                    task.value.should == 42
         | 
| 280 | 
            -
                    task.reason.should be_nil
         | 
| 303 | 
            +
                    observer.latch.wait(1)
         | 
| 281 304 | 
             
                    observer.value.should == 42
         | 
| 282 305 | 
             
                    observer.reason.should be_nil
         | 
| 283 306 | 
             
                  end
         | 
| @@ -285,9 +308,7 @@ module Concurrent | |
| 285 308 | 
             
                  it 'notifies all observers on rejection' do
         | 
| 286 309 | 
             
                    task = ScheduledTask.new(0.1){ raise StandardError }.execute
         | 
| 287 310 | 
             
                    task.add_observer(observer)
         | 
| 288 | 
            -
                     | 
| 289 | 
            -
                    task.value.should be_nil
         | 
| 290 | 
            -
                    task.reason.should be_a(StandardError)
         | 
| 311 | 
            +
                    observer.latch.wait(1)
         | 
| 291 312 | 
             
                    observer.value.should be_nil
         | 
| 292 313 | 
             
                    observer.reason.should be_a(StandardError)
         | 
| 293 314 | 
             
                  end
         | 
| @@ -295,7 +316,7 @@ module Concurrent | |
| 295 316 | 
             
                  it 'does not notify an observer added after fulfillment' do
         | 
| 296 317 | 
             
                    observer.should_not_receive(:update).with(any_args)
         | 
| 297 318 | 
             
                    task = ScheduledTask.new(0.1){ 42 }.execute
         | 
| 298 | 
            -
                     | 
| 319 | 
            +
                    task.value(1)
         | 
| 299 320 | 
             
                    task.add_observer(observer)
         | 
| 300 321 | 
             
                    sleep(0.1)
         | 
| 301 322 | 
             
                  end
         | 
| @@ -303,7 +324,7 @@ module Concurrent | |
| 303 324 | 
             
                  it 'does not notify an observer added after rejection' do
         | 
| 304 325 | 
             
                    observer.should_not_receive(:update).with(any_args)
         | 
| 305 326 | 
             
                    task = ScheduledTask.new(0.1){ raise StandardError }.execute
         | 
| 306 | 
            -
                     | 
| 327 | 
            +
                    task.value(1)
         | 
| 307 328 | 
             
                    task.add_observer(observer)
         | 
| 308 329 | 
             
                    sleep(0.1)
         | 
| 309 330 | 
             
                  end
         | 
| @@ -313,9 +334,8 @@ module Concurrent | |
| 313 334 | 
             
                    task = ScheduledTask.new(0.1){ 42 }.execute
         | 
| 314 335 | 
             
                    task.cancel
         | 
| 315 336 | 
             
                    task.add_observer(observer)
         | 
| 316 | 
            -
                     | 
| 337 | 
            +
                    task.value(1)
         | 
| 317 338 | 
             
                  end
         | 
| 318 | 
            -
             | 
| 319 339 | 
             
                end
         | 
| 320 340 | 
             
              end
         | 
| 321 341 | 
             
            end
         |