concurrent-ruby 0.4.1 → 0.5.0.pre.1
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 +31 -33
 - data/lib/concurrent.rb +11 -3
 - data/lib/concurrent/actor.rb +29 -29
 - data/lib/concurrent/agent.rb +98 -16
 - data/lib/concurrent/atomic.rb +125 -0
 - data/lib/concurrent/channel.rb +36 -1
 - data/lib/concurrent/condition.rb +67 -0
 - data/lib/concurrent/copy_on_notify_observer_set.rb +80 -0
 - data/lib/concurrent/copy_on_write_observer_set.rb +94 -0
 - data/lib/concurrent/count_down_latch.rb +60 -0
 - data/lib/concurrent/dataflow.rb +85 -0
 - data/lib/concurrent/dereferenceable.rb +69 -31
 - data/lib/concurrent/event.rb +27 -21
 - data/lib/concurrent/future.rb +103 -43
 - data/lib/concurrent/ivar.rb +78 -0
 - data/lib/concurrent/mvar.rb +154 -0
 - data/lib/concurrent/obligation.rb +94 -9
 - data/lib/concurrent/postable.rb +11 -9
 - data/lib/concurrent/promise.rb +101 -127
 - data/lib/concurrent/safe_task_executor.rb +28 -0
 - data/lib/concurrent/scheduled_task.rb +60 -54
 - data/lib/concurrent/stoppable.rb +2 -2
 - data/lib/concurrent/supervisor.rb +36 -29
 - data/lib/concurrent/thread_local_var.rb +117 -0
 - data/lib/concurrent/timer_task.rb +28 -30
 - data/lib/concurrent/utilities.rb +1 -1
 - data/lib/concurrent/version.rb +1 -1
 - data/spec/concurrent/agent_spec.rb +121 -230
 - data/spec/concurrent/atomic_spec.rb +201 -0
 - data/spec/concurrent/condition_spec.rb +171 -0
 - data/spec/concurrent/copy_on_notify_observer_set_spec.rb +10 -0
 - data/spec/concurrent/copy_on_write_observer_set_spec.rb +10 -0
 - data/spec/concurrent/count_down_latch_spec.rb +125 -0
 - data/spec/concurrent/dataflow_spec.rb +160 -0
 - data/spec/concurrent/dereferenceable_shared.rb +145 -0
 - data/spec/concurrent/event_spec.rb +44 -9
 - data/spec/concurrent/fixed_thread_pool_spec.rb +0 -1
 - data/spec/concurrent/future_spec.rb +184 -69
 - data/spec/concurrent/ivar_spec.rb +192 -0
 - data/spec/concurrent/mvar_spec.rb +380 -0
 - data/spec/concurrent/obligation_spec.rb +193 -0
 - data/spec/concurrent/observer_set_shared.rb +233 -0
 - data/spec/concurrent/postable_shared.rb +3 -7
 - data/spec/concurrent/promise_spec.rb +270 -192
 - data/spec/concurrent/safe_task_executor_spec.rb +58 -0
 - data/spec/concurrent/scheduled_task_spec.rb +142 -38
 - data/spec/concurrent/thread_local_var_spec.rb +113 -0
 - data/spec/concurrent/thread_pool_shared.rb +2 -3
 - data/spec/concurrent/timer_task_spec.rb +31 -1
 - data/spec/spec_helper.rb +2 -3
 - data/spec/support/functions.rb +4 -0
 - data/spec/support/less_than_or_equal_to_matcher.rb +5 -0
 - metadata +50 -30
 - data/lib/concurrent/contract.rb +0 -21
 - data/lib/concurrent/event_machine_defer_proxy.rb +0 -22
 - data/md/actor.md +0 -404
 - data/md/agent.md +0 -142
 - data/md/channel.md +0 -40
 - data/md/dereferenceable.md +0 -49
 - data/md/future.md +0 -125
 - data/md/obligation.md +0 -32
 - data/md/promise.md +0 -217
 - data/md/scheduled_task.md +0 -156
 - data/md/supervisor.md +0 -246
 - data/md/thread_pool.md +0 -225
 - data/md/timer_task.md +0 -191
 - data/spec/concurrent/contract_spec.rb +0 -34
 - data/spec/concurrent/event_machine_defer_proxy_spec.rb +0 -240
 
    
        data/md/timer_task.md
    DELETED
    
    | 
         @@ -1,191 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # To Gobbler's Knob. It's Groundhog Day!
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            A very common currency pattern is to run a thread that performs a task at regular
         
     | 
| 
       4 
     | 
    
         
            -
            intervals. The thread that peforms the task sleeps for the given interval then
         
     | 
| 
       5 
     | 
    
         
            -
            wakes up and performs the task. Lather, rinse, repeat... This pattern causes two
         
     | 
| 
       6 
     | 
    
         
            -
            problems. First, it is difficult to test the business logic of the task becuse the
         
     | 
| 
       7 
     | 
    
         
            -
            task itself is tightly coupled with the concurrency logic. Second, an exception in
         
     | 
| 
       8 
     | 
    
         
            -
            raised while performing the task can cause the entire thread to abend. In a
         
     | 
| 
       9 
     | 
    
         
            -
            long-running application where the task thread is intended to run for days/weeks/years
         
     | 
| 
       10 
     | 
    
         
            -
            a crashed task thread can pose a significant problem. `TimerTask` alleviates both problems.
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            When a `TimerTask` is launched it starts a thread for monitoring the execution interval.
         
     | 
| 
       13 
     | 
    
         
            -
            The `TimerTask` thread does not perform the task, however. Instead, the TimerTask
         
     | 
| 
       14 
     | 
    
         
            -
            launches the task on a separate thread. Should the task experience an unrecoverable
         
     | 
| 
       15 
     | 
    
         
            -
            crash only the task thread will crash. This makes the `TimerTask` very fault tolerant
         
     | 
| 
       16 
     | 
    
         
            -
            Additionally, the `TimerTask` thread can respond to the success or failure of the task,
         
     | 
| 
       17 
     | 
    
         
            -
            performing logging or ancillary operations. `TimerTask` can also be configured with a
         
     | 
| 
       18 
     | 
    
         
            -
            timeout value allowing it to kill a task that runs too long.
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
            One other advantage of `TimerTask` is it forces the bsiness logic to be completely decoupled
         
     | 
| 
       21 
     | 
    
         
            -
            from the concurrency logic. The business logic can be tested separately then passed to the
         
     | 
| 
       22 
     | 
    
         
            -
            `TimerTask` for scheduling and running.
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
            Unlike other abstraction in this library, `TimerTask` does not run on the global thread pool.
         
     | 
| 
       25 
     | 
    
         
            -
            In my experience the types of tasks that will benefit from `TimerTask` tend to also be long
         
     | 
| 
       26 
     | 
    
         
            -
            running. For this reason they get their own thread every time the task is executed.
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
            This class is based on the Java class
         
     | 
| 
       29 
     | 
    
         
            -
            [of the same name](http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html).
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
            ## Observation
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
            `TimerTask` supports notification through the Ruby standard library
         
     | 
| 
       34 
     | 
    
         
            -
            [Observable](http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html)
         
     | 
| 
       35 
     | 
    
         
            -
            module. On execution the `TimerTask` will notify the observers with thress arguments:
         
     | 
| 
       36 
     | 
    
         
            -
            time of execution, the result of the block (or nil on failure), and any raised
         
     | 
| 
       37 
     | 
    
         
            -
            exceptions (or nil on success). If the timeout interval is exceeded the observer
         
     | 
| 
       38 
     | 
    
         
            -
            will receive a `Concurrent::TimeoutError` object as the third argument.
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
            ## Examples
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
            A basic example:
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       45 
     | 
    
         
            -
            require 'concurrent'
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
            task = Concurrent::TimerTask.new{ puts 'Boom!' }
         
     | 
| 
       48 
     | 
    
         
            -
            task.run!
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
            task.execution_interval #=> 60 (default)
         
     | 
| 
       51 
     | 
    
         
            -
            task.timeout_interval   #=> 30 (default)
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
            # wait 60 seconds...
         
     | 
| 
       54 
     | 
    
         
            -
            #=> 'Boom!'
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
            task.stop #=> true
         
     | 
| 
       57 
     | 
    
         
            -
            ```
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
            Both the execution_interval and the timeout_interval can be configured:
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       62 
     | 
    
         
            -
            task = Concurrent::TimerTask.new(execution_interval: 5, timeout_interval: 5) do
         
     | 
| 
       63 
     | 
    
         
            -
                   puts 'Boom!'
         
     | 
| 
       64 
     | 
    
         
            -
                 end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
            task.execution_interval #=> 5
         
     | 
| 
       67 
     | 
    
         
            -
            task.timeout_interval   #=> 5
         
     | 
| 
       68 
     | 
    
         
            -
            ```
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
            By default an `TimerTask` will wait for `:execution_interval` seconds before running the block.
         
     | 
| 
       71 
     | 
    
         
            -
            To run the block immediately set the `:run_now` option to `true`:
         
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       74 
     | 
    
         
            -
            task = Concurrent::TimerTask.new(run_now: true){ puts 'Boom!' }
         
     | 
| 
       75 
     | 
    
         
            -
            task.run!
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
            #=> 'Boom!'
         
     | 
| 
       78 
     | 
    
         
            -
            ```
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
            The `TimerTask` class includes the `Dereferenceable` mixin module so the result of
         
     | 
| 
       81 
     | 
    
         
            -
            the last execution is always available via the `#value` method. Derefencing options
         
     | 
| 
       82 
     | 
    
         
            -
            can be passed to the `TimerTask` during construction or at any later time using the
         
     | 
| 
       83 
     | 
    
         
            -
            `#set_deref_options` method.
         
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       86 
     | 
    
         
            -
            task = Concurrent::TimerTask.new(
         
     | 
| 
       87 
     | 
    
         
            -
              dup_on_deref: true,
         
     | 
| 
       88 
     | 
    
         
            -
              execution_interval: 5
         
     | 
| 
       89 
     | 
    
         
            -
            ){ Time.now }
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
            task.run!
         
     | 
| 
       92 
     | 
    
         
            -
            Time.now   #=> 2013-11-07 18:06:50 -0500
         
     | 
| 
       93 
     | 
    
         
            -
            sleep(10)
         
     | 
| 
       94 
     | 
    
         
            -
            task.value #=> 2013-11-07 18:06:55 -0500
         
     | 
| 
       95 
     | 
    
         
            -
            ```
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
            A simple example with observation:
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       100 
     | 
    
         
            -
            class TaskObserver
         
     | 
| 
       101 
     | 
    
         
            -
              def update(time, result, ex)
         
     | 
| 
       102 
     | 
    
         
            -
                if result
         
     | 
| 
       103 
     | 
    
         
            -
                  print "(#{time}) Execution successfully returned #{result}\n"
         
     | 
| 
       104 
     | 
    
         
            -
                elsif ex.is_a?(Concurrent::TimeoutError)
         
     | 
| 
       105 
     | 
    
         
            -
                  print "(#{time}) Execution timed out\n"
         
     | 
| 
       106 
     | 
    
         
            -
                else
         
     | 
| 
       107 
     | 
    
         
            -
                  print "(#{time}) Execution failed with error #{ex}\n"
         
     | 
| 
       108 
     | 
    
         
            -
                end
         
     | 
| 
       109 
     | 
    
         
            -
              end
         
     | 
| 
       110 
     | 
    
         
            -
            end
         
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
            task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ 42 }
         
     | 
| 
       113 
     | 
    
         
            -
            task.add_observer(TaskObserver.new)
         
     | 
| 
       114 
     | 
    
         
            -
            task.run!
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
            #=> (2013-10-13 19:08:58 -0400) Execution successfully returned 42
         
     | 
| 
       117 
     | 
    
         
            -
            #=> (2013-10-13 19:08:59 -0400) Execution successfully returned 42
         
     | 
| 
       118 
     | 
    
         
            -
            #=> (2013-10-13 19:09:00 -0400) Execution successfully returned 42
         
     | 
| 
       119 
     | 
    
         
            -
            task.stop
         
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
            task = Concurrent::TimerTask.new(execution_interval: 1, timeout_interval: 1){ sleep }
         
     | 
| 
       122 
     | 
    
         
            -
            task.add_observer(TaskObserver.new)
         
     | 
| 
       123 
     | 
    
         
            -
            task.run!
         
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
            #=> (2013-10-13 19:07:25 -0400) Execution timed out
         
     | 
| 
       126 
     | 
    
         
            -
            #=> (2013-10-13 19:07:27 -0400) Execution timed out
         
     | 
| 
       127 
     | 
    
         
            -
            #=> (2013-10-13 19:07:29 -0400) Execution timed out
         
     | 
| 
       128 
     | 
    
         
            -
            task.stop
         
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
            task = Concurrent::TimerTask.new(execution_interval: 1){ raise StandardError }
         
     | 
| 
       131 
     | 
    
         
            -
            task.add_observer(TaskObserver.new)
         
     | 
| 
       132 
     | 
    
         
            -
            task.run!
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
     | 
    
         
            -
            #=> (2013-10-13 19:09:37 -0400) Execution failed with error StandardError
         
     | 
| 
       135 
     | 
    
         
            -
            #=> (2013-10-13 19:09:38 -0400) Execution failed with error StandardError
         
     | 
| 
       136 
     | 
    
         
            -
            #=> (2013-10-13 19:09:39 -0400) Execution failed with error StandardError
         
     | 
| 
       137 
     | 
    
         
            -
            task.stop
         
     | 
| 
       138 
     | 
    
         
            -
            ```
         
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
       140 
     | 
    
         
            -
            In some cases it may be necessary for a `TimerTask` to affect its own execution cycle.
         
     | 
| 
       141 
     | 
    
         
            -
            To facilitate this a reference to the task object is passed into the block as a block
         
     | 
| 
       142 
     | 
    
         
            -
            argument every time the task is executed.
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       145 
     | 
    
         
            -
            timer_task = Concurrent::TimerTask.new(execution_interval: 1) do |task|
         
     | 
| 
       146 
     | 
    
         
            -
              task.execution_interval.times{ print 'Boom! ' }
         
     | 
| 
       147 
     | 
    
         
            -
              print "\n"
         
     | 
| 
       148 
     | 
    
         
            -
              task.execution_interval += 1
         
     | 
| 
       149 
     | 
    
         
            -
              if task.execution_interval > 5
         
     | 
| 
       150 
     | 
    
         
            -
                puts 'Stopping...'
         
     | 
| 
       151 
     | 
    
         
            -
                task.stop
         
     | 
| 
       152 
     | 
    
         
            -
              end
         
     | 
| 
       153 
     | 
    
         
            -
            end
         
     | 
| 
       154 
     | 
    
         
            -
             
     | 
| 
       155 
     | 
    
         
            -
            timer_task.run # blocking call - this task will stop itself
         
     | 
| 
       156 
     | 
    
         
            -
            #=> Boom!
         
     | 
| 
       157 
     | 
    
         
            -
            #=> Boom! Boom!
         
     | 
| 
       158 
     | 
    
         
            -
            #=> Boom! Boom! Boom!
         
     | 
| 
       159 
     | 
    
         
            -
            #=> Boom! Boom! Boom! Boom!
         
     | 
| 
       160 
     | 
    
         
            -
            #=> Boom! Boom! Boom! Boom! Boom!
         
     | 
| 
       161 
     | 
    
         
            -
            #=> Stopping...
         
     | 
| 
       162 
     | 
    
         
            -
            ```
         
     | 
| 
       163 
     | 
    
         
            -
             
     | 
| 
       164 
     | 
    
         
            -
            ## Copyright
         
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
            *Concurrent Ruby* is Copyright © 2013 [Jerry D'Antonio](https://twitter.com/jerrydantonio).
         
     | 
| 
       167 
     | 
    
         
            -
            It is free software and may be redistributed under the terms specified in the LICENSE file.
         
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
            ## License
         
     | 
| 
       170 
     | 
    
         
            -
             
     | 
| 
       171 
     | 
    
         
            -
            Released under the MIT license.
         
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
            http://www.opensource.org/licenses/mit-license.php  
         
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
            > Permission is hereby granted, free of charge, to any person obtaining a copy  
         
     | 
| 
       176 
     | 
    
         
            -
            > of this software and associated documentation files (the "Software"), to deal  
         
     | 
| 
       177 
     | 
    
         
            -
            > in the Software without restriction, including without limitation the rights  
         
     | 
| 
       178 
     | 
    
         
            -
            > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
         
     | 
| 
       179 
     | 
    
         
            -
            > copies of the Software, and to permit persons to whom the Software is  
         
     | 
| 
       180 
     | 
    
         
            -
            > furnished to do so, subject to the following conditions:  
         
     | 
| 
       181 
     | 
    
         
            -
            > 
         
     | 
| 
       182 
     | 
    
         
            -
            > The above copyright notice and this permission notice shall be included in  
         
     | 
| 
       183 
     | 
    
         
            -
            > all copies or substantial portions of the Software.  
         
     | 
| 
       184 
     | 
    
         
            -
            > 
         
     | 
| 
       185 
     | 
    
         
            -
            > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
         
     | 
| 
       186 
     | 
    
         
            -
            > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
         
     | 
| 
       187 
     | 
    
         
            -
            > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
         
     | 
| 
       188 
     | 
    
         
            -
            > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
         
     | 
| 
       189 
     | 
    
         
            -
            > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
         
     | 
| 
       190 
     | 
    
         
            -
            > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN  
         
     | 
| 
       191 
     | 
    
         
            -
            > THE SOFTWARE.  
         
     | 
| 
         @@ -1,34 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'spec_helper'
         
     | 
| 
       2 
     | 
    
         
            -
            require_relative 'obligation_shared'
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
            module Concurrent
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
              describe Contract do
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
                let!(:fulfilled_value) { 10 }
         
     | 
| 
       9 
     | 
    
         
            -
                let(:rejected_reason) { StandardError.new('Boom!') }
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                let(:pending_subject) do
         
     | 
| 
       12 
     | 
    
         
            -
                  @contract = Contract.new
         
     | 
| 
       13 
     | 
    
         
            -
                  Thread.new do
         
     | 
| 
       14 
     | 
    
         
            -
                    sleep(3)
         
     | 
| 
       15 
     | 
    
         
            -
                    @contract.complete(fulfilled_value, nil)
         
     | 
| 
       16 
     | 
    
         
            -
                  end
         
     | 
| 
       17 
     | 
    
         
            -
                  @contract
         
     | 
| 
       18 
     | 
    
         
            -
                end
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                let(:fulfilled_subject) do
         
     | 
| 
       21 
     | 
    
         
            -
                  contract = Contract.new
         
     | 
| 
       22 
     | 
    
         
            -
                  contract.complete(fulfilled_value, nil)
         
     | 
| 
       23 
     | 
    
         
            -
                  contract
         
     | 
| 
       24 
     | 
    
         
            -
                end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                let(:rejected_subject) do
         
     | 
| 
       27 
     | 
    
         
            -
                  contract = Contract.new
         
     | 
| 
       28 
     | 
    
         
            -
                  contract.complete(nil, rejected_reason)
         
     | 
| 
       29 
     | 
    
         
            -
                  contract
         
     | 
| 
       30 
     | 
    
         
            -
                end
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                it_should_behave_like :obligation
         
     | 
| 
       33 
     | 
    
         
            -
              end
         
     | 
| 
       34 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,240 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'spec_helper'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'concurrent/agent'
         
     | 
| 
       4 
     | 
    
         
            -
            require 'concurrent/future'
         
     | 
| 
       5 
     | 
    
         
            -
            require 'concurrent/promise'
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            if mri?
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
              module Concurrent
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                describe EventMachineDeferProxy do
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                  subject { EventMachineDeferProxy.new }
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                  after(:all) do
         
     | 
| 
       16 
     | 
    
         
            -
                    $GLOBAL_THREAD_POOL = FixedThreadPool.new(1)
         
     | 
| 
       17 
     | 
    
         
            -
                  end
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
                  context '#post' do
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
                    it 'proxies a call without arguments' do
         
     | 
| 
       22 
     | 
    
         
            -
                      @expected = false
         
     | 
| 
       23 
     | 
    
         
            -
                      EventMachine.run do
         
     | 
| 
       24 
     | 
    
         
            -
                        subject.post{ @expected = true }
         
     | 
| 
       25 
     | 
    
         
            -
                        sleep(0.1)
         
     | 
| 
       26 
     | 
    
         
            -
                        EventMachine.stop
         
     | 
| 
       27 
     | 
    
         
            -
                      end
         
     | 
| 
       28 
     | 
    
         
            -
                      @expected.should eq true
         
     | 
| 
       29 
     | 
    
         
            -
                    end
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                    it 'proxies a call with arguments' do
         
     | 
| 
       32 
     | 
    
         
            -
                      @expected = []
         
     | 
| 
       33 
     | 
    
         
            -
                      EventMachine.run do
         
     | 
| 
       34 
     | 
    
         
            -
                        subject.post(1,2,3){|*args| @expected = args }
         
     | 
| 
       35 
     | 
    
         
            -
                        sleep(0.1)
         
     | 
| 
       36 
     | 
    
         
            -
                        EventMachine.stop
         
     | 
| 
       37 
     | 
    
         
            -
                      end
         
     | 
| 
       38 
     | 
    
         
            -
                      @expected.should eq [1,2,3]
         
     | 
| 
       39 
     | 
    
         
            -
                    end
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                    it 'aliases #<<' do
         
     | 
| 
       42 
     | 
    
         
            -
                      @expected = false
         
     | 
| 
       43 
     | 
    
         
            -
                      EventMachine.run do
         
     | 
| 
       44 
     | 
    
         
            -
                        subject << proc{ @expected = true }
         
     | 
| 
       45 
     | 
    
         
            -
                        sleep(0.1)
         
     | 
| 
       46 
     | 
    
         
            -
                        EventMachine.stop
         
     | 
| 
       47 
     | 
    
         
            -
                      end
         
     | 
| 
       48 
     | 
    
         
            -
                      @expected.should eq true
         
     | 
| 
       49 
     | 
    
         
            -
                    end
         
     | 
| 
       50 
     | 
    
         
            -
                  end
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                  context 'operation' do
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                    context Agent do
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
                      subject { Agent.new(0) }
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
                      before(:each) do
         
     | 
| 
       59 
     | 
    
         
            -
                        Agent.thread_pool = EventMachineDeferProxy.new
         
     | 
| 
       60 
     | 
    
         
            -
                      end
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
                      it 'supports fulfillment' do
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
                        EventMachine.run do
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
                          @expected = []
         
     | 
| 
       67 
     | 
    
         
            -
                          subject.post{ @expected << 1 }
         
     | 
| 
       68 
     | 
    
         
            -
                          subject.post{ @expected << 2 }
         
     | 
| 
       69 
     | 
    
         
            -
                          subject.post{ @expected << 3 }
         
     | 
| 
       70 
     | 
    
         
            -
                          sleep(0.1)
         
     | 
| 
       71 
     | 
    
         
            -
                          @expected.should include(1)
         
     | 
| 
       72 
     | 
    
         
            -
                          @expected.should include(2)
         
     | 
| 
       73 
     | 
    
         
            -
                          @expected.should include(3)
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                          EventMachine.stop
         
     | 
| 
       76 
     | 
    
         
            -
                        end
         
     | 
| 
       77 
     | 
    
         
            -
                      end
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
                      it 'supports validation' do
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
                        EventMachine.run do
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                          @expected = nil
         
     | 
| 
       84 
     | 
    
         
            -
                          subject.validate{ @expected = 10; true }
         
     | 
| 
       85 
     | 
    
         
            -
                          subject.post{ nil }
         
     | 
| 
       86 
     | 
    
         
            -
                          sleep(0.1)
         
     | 
| 
       87 
     | 
    
         
            -
                          @expected.should eq 10
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
                          EventMachine.stop
         
     | 
| 
       90 
     | 
    
         
            -
                        end
         
     | 
| 
       91 
     | 
    
         
            -
                      end
         
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
                      it 'supports rejection' do
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
                        EventMachine.run do
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
                          @expected = nil
         
     | 
| 
       98 
     | 
    
         
            -
                          subject.
         
     | 
| 
       99 
     | 
    
         
            -
                            on_error(StandardError){|ex| @expected = 1 }.
         
     | 
| 
       100 
     | 
    
         
            -
                            on_error(StandardError){|ex| @expected = 2 }.
         
     | 
| 
       101 
     | 
    
         
            -
                            on_error(StandardError){|ex| @expected = 3 }
         
     | 
| 
       102 
     | 
    
         
            -
                          subject.post{ raise StandardError }
         
     | 
| 
       103 
     | 
    
         
            -
                          sleep(0.1)
         
     | 
| 
       104 
     | 
    
         
            -
                          @expected.should eq 1
         
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
                          EventMachine.stop
         
     | 
| 
       107 
     | 
    
         
            -
                        end
         
     | 
| 
       108 
     | 
    
         
            -
                      end
         
     | 
| 
       109 
     | 
    
         
            -
                    end
         
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
                    context Future do
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
                      before(:each) do
         
     | 
| 
       114 
     | 
    
         
            -
                        Future.thread_pool = EventMachineDeferProxy.new
         
     | 
| 
       115 
     | 
    
         
            -
                      end
         
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
                      it 'supports fulfillment' do
         
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
                        EventMachine.run do
         
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
                          @a = @b = @c = nil
         
     | 
| 
       122 
     | 
    
         
            -
                          f = Future.new(1, 2, 3) do |a, b, c|
         
     | 
| 
       123 
     | 
    
         
            -
                            @a, @b, @c = a, b, c
         
     | 
| 
       124 
     | 
    
         
            -
                          end
         
     | 
| 
       125 
     | 
    
         
            -
                          sleep(0.1)
         
     | 
| 
       126 
     | 
    
         
            -
                          [@a, @b, @c].should eq [1, 2, 3]
         
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
                          sleep(0.1)
         
     | 
| 
       129 
     | 
    
         
            -
                          EventMachine.stop
         
     | 
| 
       130 
     | 
    
         
            -
                        end
         
     | 
| 
       131 
     | 
    
         
            -
                      end
         
     | 
| 
       132 
     | 
    
         
            -
                    end
         
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
     | 
    
         
            -
                    context Promise do
         
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
     | 
    
         
            -
                      before(:each) do
         
     | 
| 
       137 
     | 
    
         
            -
                        Promise.thread_pool = EventMachineDeferProxy.new
         
     | 
| 
       138 
     | 
    
         
            -
                      end
         
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
       140 
     | 
    
         
            -
                      context 'fulfillment' do
         
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
     | 
    
         
            -
                        it 'passes all arguments to the first promise in the chain' do
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
                          EventMachine.run do
         
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
                            @a = @b = @c = nil
         
     | 
| 
       147 
     | 
    
         
            -
                            p = Promise.new(1, 2, 3) do |a, b, c|
         
     | 
| 
       148 
     | 
    
         
            -
                              @a, @b, @c = a, b, c
         
     | 
| 
       149 
     | 
    
         
            -
                            end
         
     | 
| 
       150 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       151 
     | 
    
         
            -
                            [@a, @b, @c].should eq [1, 2, 3]
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       154 
     | 
    
         
            -
                            EventMachine.stop
         
     | 
| 
       155 
     | 
    
         
            -
                          end
         
     | 
| 
       156 
     | 
    
         
            -
                        end
         
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
                        it 'passes the result of each block to all its children' do
         
     | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
       160 
     | 
    
         
            -
                          EventMachine.run do
         
     | 
| 
       161 
     | 
    
         
            -
                            @expected = nil
         
     | 
| 
       162 
     | 
    
         
            -
                            Promise.new(10){|a| a * 2 }.then{|result| @expected = result}
         
     | 
| 
       163 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       164 
     | 
    
         
            -
                            @expected.should eq 20
         
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       167 
     | 
    
         
            -
                            EventMachine.stop
         
     | 
| 
       168 
     | 
    
         
            -
                          end
         
     | 
| 
       169 
     | 
    
         
            -
                        end
         
     | 
| 
       170 
     | 
    
         
            -
             
     | 
| 
       171 
     | 
    
         
            -
                        it 'sets the promise value to the result if its block' do
         
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
                          EventMachine.run do
         
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
                            p = Promise.new(10){|a| a * 2 }.then{|result| result * 2}
         
     | 
| 
       176 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       177 
     | 
    
         
            -
                            p.value.should eq 40
         
     | 
| 
       178 
     | 
    
         
            -
             
     | 
| 
       179 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       180 
     | 
    
         
            -
                            EventMachine.stop
         
     | 
| 
       181 
     | 
    
         
            -
                          end
         
     | 
| 
       182 
     | 
    
         
            -
                        end
         
     | 
| 
       183 
     | 
    
         
            -
                      end
         
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
                      context 'rejection' do
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
                        it 'sets the promise reason and error on exception' do
         
     | 
| 
       188 
     | 
    
         
            -
             
     | 
| 
       189 
     | 
    
         
            -
                          EventMachine.run do
         
     | 
| 
       190 
     | 
    
         
            -
             
     | 
| 
       191 
     | 
    
         
            -
                            p = Promise.new{ raise StandardError.new('Boom!') }
         
     | 
| 
       192 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       193 
     | 
    
         
            -
                            p.reason.should be_a(Exception)
         
     | 
| 
       194 
     | 
    
         
            -
                            p.reason.should.to_s =~ /Boom!/
         
     | 
| 
       195 
     | 
    
         
            -
                            p.should be_rejected
         
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
       197 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       198 
     | 
    
         
            -
                            EventMachine.stop
         
     | 
| 
       199 
     | 
    
         
            -
                          end
         
     | 
| 
       200 
     | 
    
         
            -
                        end
         
     | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
       202 
     | 
    
         
            -
                        it 'calls the first exception block with a matching class' do
         
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
       204 
     | 
    
         
            -
                          EventMachine.run do
         
     | 
| 
       205 
     | 
    
         
            -
             
     | 
| 
       206 
     | 
    
         
            -
                            @expected = nil
         
     | 
| 
       207 
     | 
    
         
            -
                            Promise.new{ raise StandardError }.
         
     | 
| 
       208 
     | 
    
         
            -
                              on_error(StandardError){|ex| @expected = 1 }.
         
     | 
| 
       209 
     | 
    
         
            -
                              on_error(StandardError){|ex| @expected = 2 }.
         
     | 
| 
       210 
     | 
    
         
            -
                              on_error(StandardError){|ex| @expected = 3 }
         
     | 
| 
       211 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       212 
     | 
    
         
            -
                            @expected.should eq 1
         
     | 
| 
       213 
     | 
    
         
            -
             
     | 
| 
       214 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       215 
     | 
    
         
            -
                            EventMachine.stop
         
     | 
| 
       216 
     | 
    
         
            -
                          end
         
     | 
| 
       217 
     | 
    
         
            -
                        end
         
     | 
| 
       218 
     | 
    
         
            -
             
     | 
| 
       219 
     | 
    
         
            -
                        it 'passes the exception object to the matched block' do
         
     | 
| 
       220 
     | 
    
         
            -
             
     | 
| 
       221 
     | 
    
         
            -
                          EventMachine.run do
         
     | 
| 
       222 
     | 
    
         
            -
             
     | 
| 
       223 
     | 
    
         
            -
                            @expected = nil
         
     | 
| 
       224 
     | 
    
         
            -
                            Promise.new{ raise StandardError }.
         
     | 
| 
       225 
     | 
    
         
            -
                              on_error(ArgumentError){|ex| @expected = ex }.
         
     | 
| 
       226 
     | 
    
         
            -
                              on_error(LoadError){|ex| @expected = ex }.
         
     | 
| 
       227 
     | 
    
         
            -
                              on_error(Exception){|ex| @expected = ex }
         
     | 
| 
       228 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       229 
     | 
    
         
            -
                            @expected.should be_a(StandardError)
         
     | 
| 
       230 
     | 
    
         
            -
             
     | 
| 
       231 
     | 
    
         
            -
                            sleep(0.1)
         
     | 
| 
       232 
     | 
    
         
            -
                            EventMachine.stop
         
     | 
| 
       233 
     | 
    
         
            -
                          end
         
     | 
| 
       234 
     | 
    
         
            -
                        end
         
     | 
| 
       235 
     | 
    
         
            -
                      end
         
     | 
| 
       236 
     | 
    
         
            -
                    end
         
     | 
| 
       237 
     | 
    
         
            -
                  end
         
     | 
| 
       238 
     | 
    
         
            -
                end
         
     | 
| 
       239 
     | 
    
         
            -
              end
         
     | 
| 
       240 
     | 
    
         
            -
            end
         
     |