anticipate 0.0.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.
- data/README.rdoc +26 -0
 - data/anticipate.gemspec +19 -0
 - data/lib/anticipate.rb +74 -0
 - data/lib/anticipate/anticipator.rb +23 -0
 - data/lib/anticipate/timeout_error.rb +24 -0
 - data/spec/anticipate/anticipate_spec.rb +88 -0
 - data/spec/anticipate/anticipator_spec.rb +66 -0
 - data/spec/anticipate/integration_spec.rb +72 -0
 - data/spec/spec_helper.rb +6 -0
 - metadata +75 -0
 
    
        data/README.rdoc
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            = Anticipate
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            == About
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Anticipate is a fluent interface for retrying blocks of code:
         
     | 
| 
      
 6 
     | 
    
         
            +
              
         
     | 
| 
      
 7 
     | 
    
         
            +
              trying_every(3).seconds.failing_after(9).tries do
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
                # Repeatedly calls block until it stops raising errors
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
              
         
     | 
| 
      
 13 
     | 
    
         
            +
            The Anticipate module allows the following expressions:
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              trying_every(n).seconds {}
         
     | 
| 
      
 16 
     | 
    
         
            +
              failing_after(n).tries {}
         
     | 
| 
      
 17 
     | 
    
         
            +
              trying_every(x).seconds.failing_after(y).tries {}
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
            Blocks should contain an assertion, i.e. raise a
         
     | 
| 
      
 20 
     | 
    
         
            +
            descriptive error if some condition is unsatisfied. On
         
     | 
| 
      
 21 
     | 
    
         
            +
            the last iteration, the error will be wrapped in a
         
     | 
| 
      
 22 
     | 
    
         
            +
            TimeoutError and re-raised.
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            I'm aware of a couple of gems supporting the
         
     | 
| 
      
 25 
     | 
    
         
            +
            begin-rescue-sleep-retry dance, namely 'retry' and 'attempt'.
         
     | 
| 
      
 26 
     | 
    
         
            +
            The aim of this library is to offer more expressive syntax.
         
     | 
    
        data/anticipate.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- encoding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "anticipate"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.name        = 'anticipate'
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.version     = Anticipate::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.authors     = ['Josh Chisholm']
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.description = 'Fluent interface for try-rescue-sleep-retry-abort'
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.summary     = "anticipate-#{s.version}"
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.email       = 'joshuachisholm@gmail.com'
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.homepage    = 'http://github.com/joshski/anticipate'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              s.rubygems_version  = "1.3.7"
         
     | 
| 
      
 15 
     | 
    
         
            +
              s.files             = `git ls-files`.split("\n")
         
     | 
| 
      
 16 
     | 
    
         
            +
              s.test_files        = `git ls-files -- {spec}/*`.split("\n")
         
     | 
| 
      
 17 
     | 
    
         
            +
              s.extra_rdoc_files  = ["README.rdoc"]
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.require_path      = "lib"
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/anticipate.rb
    ADDED
    
    | 
         @@ -0,0 +1,74 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            lib = File.dirname(__FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
            $:.unshift(lib) unless $:.include?(lib) || $:.include?(File.expand_path(lib))
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'anticipate/anticipator'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Anticipate
         
     | 
| 
      
 7 
     | 
    
         
            +
              VERSION = '0.0.1'
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
              def anticipator
         
     | 
| 
      
 10 
     | 
    
         
            +
                Anticipator.new(Kernel)
         
     | 
| 
      
 11 
     | 
    
         
            +
              end  
         
     | 
| 
      
 12 
     | 
    
         
            +
              
         
     | 
| 
      
 13 
     | 
    
         
            +
              def default_tries
         
     | 
| 
      
 14 
     | 
    
         
            +
                @default_tries ||= 1
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
              
         
     | 
| 
      
 17 
     | 
    
         
            +
              def default_interval
         
     | 
| 
      
 18 
     | 
    
         
            +
                @default_interval ||= 0.1
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
              def trying_every(amount)
         
     | 
| 
      
 22 
     | 
    
         
            +
                anticipation.trying_every(amount)
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              def failing_after(amount)
         
     | 
| 
      
 26 
     | 
    
         
            +
                anticipation.failing_after(amount)
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
              private
         
     | 
| 
      
 30 
     | 
    
         
            +
              
         
     | 
| 
      
 31 
     | 
    
         
            +
              def anticipation
         
     | 
| 
      
 32 
     | 
    
         
            +
                Anticipation.new(anticipator, default_interval, default_tries)
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
              
         
     | 
| 
      
 35 
     | 
    
         
            +
              class Term
         
     | 
| 
      
 36 
     | 
    
         
            +
                def initialize(anticipator, interval, timeout)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @anticipator, @interval, @timeout = anticipator, interval, timeout
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
                
         
     | 
| 
      
 40 
     | 
    
         
            +
                private
         
     | 
| 
      
 41 
     | 
    
         
            +
                
         
     | 
| 
      
 42 
     | 
    
         
            +
                def exec
         
     | 
| 
      
 43 
     | 
    
         
            +
                  @anticipator.anticipate(@interval, @timeout) do
         
     | 
| 
      
 44 
     | 
    
         
            +
                    yield
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
                
         
     | 
| 
      
 48 
     | 
    
         
            +
                def chain
         
     | 
| 
      
 49 
     | 
    
         
            +
                  Anticipation.new(@anticipator, @interval, @timeout)
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
                
         
     | 
| 
      
 53 
     | 
    
         
            +
              class TimeUnit < Term
         
     | 
| 
      
 54 
     | 
    
         
            +
                def seconds
         
     | 
| 
      
 55 
     | 
    
         
            +
                  block_given? ? exec { yield } : chain
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
              
         
     | 
| 
      
 59 
     | 
    
         
            +
              class CountUnit < Term
         
     | 
| 
      
 60 
     | 
    
         
            +
                def tries
         
     | 
| 
      
 61 
     | 
    
         
            +
                  block_given? ? exec { yield } : chain
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              class Anticipation < Term
         
     | 
| 
      
 66 
     | 
    
         
            +
                def trying_every(amount)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  TimeUnit.new(@anticipator, amount, @timeout)
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
                
         
     | 
| 
      
 70 
     | 
    
         
            +
                def failing_after(amount)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  CountUnit.new(@anticipator, @interval, amount)
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'anticipate/timeout_error'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Anticipate
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Anticipator
         
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(sleeper)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @sleeper = sleeper
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
                def anticipate(interval, tries)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  count = -1
         
     | 
| 
      
 11 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 12 
     | 
    
         
            +
                    yield
         
     | 
| 
      
 13 
     | 
    
         
            +
                    return
         
     | 
| 
      
 14 
     | 
    
         
            +
                  rescue => e
         
     | 
| 
      
 15 
     | 
    
         
            +
                    if (count += 1) == tries
         
     | 
| 
      
 16 
     | 
    
         
            +
                      raise TimeoutError.new(interval, tries, e)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @sleeper.sleep interval
         
     | 
| 
      
 19 
     | 
    
         
            +
                    retry
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Anticipate
         
     | 
| 
      
 2 
     | 
    
         
            +
              class TimeoutError < RuntimeError
         
     | 
| 
      
 3 
     | 
    
         
            +
                def initialize(interval, tries, last_error)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @interval, @tries, @last_error =
         
     | 
| 
      
 5 
     | 
    
         
            +
                    interval, tries, last_error
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
                
         
     | 
| 
      
 8 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 9 
     | 
    
         
            +
                  "Timed out after #{@tries} tries" +
         
     | 
| 
      
 10 
     | 
    
         
            +
                  " (tried every #{seconds(@interval)})" +
         
     | 
| 
      
 11 
     | 
    
         
            +
                  "\n#{@last_error}"
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
                
         
     | 
| 
      
 14 
     | 
    
         
            +
                def backtrace
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @last_error.backtrace
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                private
         
     | 
| 
      
 19 
     | 
    
         
            +
                
         
     | 
| 
      
 20 
     | 
    
         
            +
                def seconds(amount)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  amount == 1 ? "1 second" : "#{amount} seconds"
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,88 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Anticipate
         
     | 
| 
      
 4 
     | 
    
         
            +
              describe Anticipate do
         
     | 
| 
      
 5 
     | 
    
         
            +
                include Anticipate
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                before do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @anticipator = mock("anticipator")
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @anticipator.stub!(:anticipate).and_yield
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
                
         
     | 
| 
      
 12 
     | 
    
         
            +
                def anticipator
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @anticipator
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                describe "trying_every(n).seconds" do
         
     | 
| 
      
 17 
     | 
    
         
            +
                  it "yields" do
         
     | 
| 
      
 18 
     | 
    
         
            +
                    called = false
         
     | 
| 
      
 19 
     | 
    
         
            +
                    trying_every(1).seconds { called = true }
         
     | 
| 
      
 20 
     | 
    
         
            +
                    called.should be_true
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  
         
     | 
| 
      
 23 
     | 
    
         
            +
                  it "overrides the interval" do
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @anticipator.should_receive(:anticipate).with(55, anything)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    trying_every(55).seconds {}
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  
         
     | 
| 
      
 28 
     | 
    
         
            +
                  it "uses the default timeout" do
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @anticipator.should_receive(:anticipate).with(anything, default_tries)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    trying_every(66).seconds {}
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
                describe "failing_after(n).tries" do
         
     | 
| 
      
 35 
     | 
    
         
            +
                  it "yields" do
         
     | 
| 
      
 36 
     | 
    
         
            +
                    called = false
         
     | 
| 
      
 37 
     | 
    
         
            +
                    failing_after(1).tries { called = true }
         
     | 
| 
      
 38 
     | 
    
         
            +
                    called.should be_true
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  
         
     | 
| 
      
 41 
     | 
    
         
            +
                  it "overrides the timeout" do
         
     | 
| 
      
 42 
     | 
    
         
            +
                    @anticipator.should_receive(:anticipate).with(anything, 77)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    failing_after(77).tries {}
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                  
         
     | 
| 
      
 46 
     | 
    
         
            +
                  it "uses the default interval" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @anticipator.should_receive(:anticipate).with(default_interval, anything)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    failing_after(88).tries {}
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
                
         
     | 
| 
      
 52 
     | 
    
         
            +
                describe "failing_after(x).tries.trying_every(y).seconds" do
         
     | 
| 
      
 53 
     | 
    
         
            +
                  it "yields" do
         
     | 
| 
      
 54 
     | 
    
         
            +
                    called = false
         
     | 
| 
      
 55 
     | 
    
         
            +
                    failing_after(2).tries.trying_every(1).seconds { called = true }
         
     | 
| 
      
 56 
     | 
    
         
            +
                    called.should be_true
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                  
         
     | 
| 
      
 59 
     | 
    
         
            +
                  it "overrides the timeout" do
         
     | 
| 
      
 60 
     | 
    
         
            +
                    @anticipator.should_receive(:anticipate).with(anything, 222)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    failing_after(222).tries.trying_every(111).seconds {}
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  
         
     | 
| 
      
 64 
     | 
    
         
            +
                  it "overrides the interval" do
         
     | 
| 
      
 65 
     | 
    
         
            +
                    @anticipator.should_receive(:anticipate).with(333, anything)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    failing_after(444).tries.trying_every(333).seconds {}
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
                
         
     | 
| 
      
 70 
     | 
    
         
            +
                describe "trying_every(x).seconds.failing_after(y).tries" do
         
     | 
| 
      
 71 
     | 
    
         
            +
                  it "yields" do
         
     | 
| 
      
 72 
     | 
    
         
            +
                    called = false
         
     | 
| 
      
 73 
     | 
    
         
            +
                    trying_every(1).seconds.failing_after(2).tries { called = true }
         
     | 
| 
      
 74 
     | 
    
         
            +
                    called.should be_true
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
                  
         
     | 
| 
      
 77 
     | 
    
         
            +
                  it "overrides the timeout" do
         
     | 
| 
      
 78 
     | 
    
         
            +
                    @anticipator.should_receive(:anticipate).with(anything, 666)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    trying_every(555).seconds.failing_after(666).tries {}
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  
         
     | 
| 
      
 82 
     | 
    
         
            +
                  it "overrides the interval" do
         
     | 
| 
      
 83 
     | 
    
         
            +
                    @anticipator.should_receive(:anticipate).with(777, anything)
         
     | 
| 
      
 84 
     | 
    
         
            +
                    trying_every(777).seconds.failing_after(888).tries {}
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Anticipate
         
     | 
| 
      
 4 
     | 
    
         
            +
              describe Anticipator do
         
     | 
| 
      
 5 
     | 
    
         
            +
                before do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @sleeper = mock("sleeper")
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @sleeper.stub!(:sleep)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @anticipator = Anticipator.new(@sleeper)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                describe "#anticipate" do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  
         
     | 
| 
      
 13 
     | 
    
         
            +
                  describe "when the block eventually stops raising" do
         
     | 
| 
      
 14 
     | 
    
         
            +
                    it "sleeps the given interval between tries" do
         
     | 
| 
      
 15 
     | 
    
         
            +
                      @sleeper.should_receive(:sleep).with(1).exactly(8).times
         
     | 
| 
      
 16 
     | 
    
         
            +
                      tries = 0
         
     | 
| 
      
 17 
     | 
    
         
            +
                      @anticipator.anticipate(1,9) do
         
     | 
| 
      
 18 
     | 
    
         
            +
                        raise "fail" unless (tries += 1) == 9
         
     | 
| 
      
 19 
     | 
    
         
            +
                      end
         
     | 
| 
      
 20 
     | 
    
         
            +
                      tries.should == 9
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
                    
         
     | 
| 
      
 23 
     | 
    
         
            +
                    it "does not raise" do
         
     | 
| 
      
 24 
     | 
    
         
            +
                      tries = 0
         
     | 
| 
      
 25 
     | 
    
         
            +
                      lambda {
         
     | 
| 
      
 26 
     | 
    
         
            +
                        @anticipator.anticipate(1,2) do
         
     | 
| 
      
 27 
     | 
    
         
            +
                          raise "fail" unless (tries += 1) == 2
         
     | 
| 
      
 28 
     | 
    
         
            +
                        end
         
     | 
| 
      
 29 
     | 
    
         
            +
                      }.should_not raise_error
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                    
         
     | 
| 
      
 33 
     | 
    
         
            +
                  describe "when the block always raises" do
         
     | 
| 
      
 34 
     | 
    
         
            +
                    describe "when waiting for one second" do        
         
     | 
| 
      
 35 
     | 
    
         
            +
                      it "raises a TimeoutError, with the last error message" do
         
     | 
| 
      
 36 
     | 
    
         
            +
                        tries = 0
         
     | 
| 
      
 37 
     | 
    
         
            +
                        lambda {
         
     | 
| 
      
 38 
     | 
    
         
            +
                          @anticipator.anticipate(1,2) { raise (tries += 1).to_s }
         
     | 
| 
      
 39 
     | 
    
         
            +
                        }.should raise_error(TimeoutError,
         
     | 
| 
      
 40 
     | 
    
         
            +
                                  "Timed out after 2 tries (tried every 1 second)\n3")
         
     | 
| 
      
 41 
     | 
    
         
            +
                      end
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
                    
         
     | 
| 
      
 44 
     | 
    
         
            +
                    describe "when waiting for any other number of seconds" do
         
     | 
| 
      
 45 
     | 
    
         
            +
                      it "raises a TimeoutError, with the last error message" do
         
     | 
| 
      
 46 
     | 
    
         
            +
                        tries = 0
         
     | 
| 
      
 47 
     | 
    
         
            +
                        lambda {
         
     | 
| 
      
 48 
     | 
    
         
            +
                          @anticipator.anticipate(2,3) { raise (tries += 1).to_s }
         
     | 
| 
      
 49 
     | 
    
         
            +
                        }.should raise_error(TimeoutError,
         
     | 
| 
      
 50 
     | 
    
         
            +
                                  "Timed out after 3 tries (tried every 2 seconds)\n4")
         
     | 
| 
      
 51 
     | 
    
         
            +
                      end
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  
         
     | 
| 
      
 55 
     | 
    
         
            +
                  describe "when the block never raises" do
         
     | 
| 
      
 56 
     | 
    
         
            +
                    it "does not raise" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                      lambda {
         
     | 
| 
      
 58 
     | 
    
         
            +
                        @anticipator.anticipate(1,2) do
         
     | 
| 
      
 59 
     | 
    
         
            +
                        end
         
     | 
| 
      
 60 
     | 
    
         
            +
                      }.should_not raise_error
         
     | 
| 
      
 61 
     | 
    
         
            +
                    end
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,72 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Anticipate
         
     | 
| 
      
 4 
     | 
    
         
            +
              describe Anticipate, "with default options" do
         
     | 
| 
      
 5 
     | 
    
         
            +
                include Anticipate
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                it "raises when a block continually raises" do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  raises = []
         
     | 
| 
      
 9 
     | 
    
         
            +
                  lambda {
         
     | 
| 
      
 10 
     | 
    
         
            +
                    trying_every(0.01).seconds.failing_after(5).tries {
         
     | 
| 
      
 11 
     | 
    
         
            +
                      raise (raises << Time.now).to_s
         
     | 
| 
      
 12 
     | 
    
         
            +
                    }
         
     | 
| 
      
 13 
     | 
    
         
            +
                  }.should raise_error(TimeoutError)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  raises.size.should == 6
         
     | 
| 
      
 15 
     | 
    
         
            +
                  total_time = raises.last - raises.first
         
     | 
| 
      
 16 
     | 
    
         
            +
                  total_time.should > 0.05
         
     | 
| 
      
 17 
     | 
    
         
            +
                  total_time.should < 0.06
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                it "continues when a block stops raising" do
         
     | 
| 
      
 21 
     | 
    
         
            +
                  raises = 0
         
     | 
| 
      
 22 
     | 
    
         
            +
                  lambda {
         
     | 
| 
      
 23 
     | 
    
         
            +
                    trying_every(0.01).seconds.failing_after(3).tries {
         
     | 
| 
      
 24 
     | 
    
         
            +
                      raise (raises += 1).to_s unless raises == 2
         
     | 
| 
      
 25 
     | 
    
         
            +
                    }
         
     | 
| 
      
 26 
     | 
    
         
            +
                  }.should_not raise_error
         
     | 
| 
      
 27 
     | 
    
         
            +
                  raises.should == 2
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
              
         
     | 
| 
      
 31 
     | 
    
         
            +
              describe Anticipate, "with overridden tries" do
         
     | 
| 
      
 32 
     | 
    
         
            +
                include Anticipate
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
                def default_tries
         
     | 
| 
      
 35 
     | 
    
         
            +
                  5
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                it "uses the overridden tries" do
         
     | 
| 
      
 39 
     | 
    
         
            +
                  raises = []
         
     | 
| 
      
 40 
     | 
    
         
            +
                  lambda {
         
     | 
| 
      
 41 
     | 
    
         
            +
                    trying_every(0.01).seconds {
         
     | 
| 
      
 42 
     | 
    
         
            +
                      raise (raises << Time.now).to_s
         
     | 
| 
      
 43 
     | 
    
         
            +
                    }
         
     | 
| 
      
 44 
     | 
    
         
            +
                  }.should raise_error(TimeoutError)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  raises.size.should == 6
         
     | 
| 
      
 46 
     | 
    
         
            +
                  total_time = raises.last - raises.first
         
     | 
| 
      
 47 
     | 
    
         
            +
                  total_time.should > 0.05
         
     | 
| 
      
 48 
     | 
    
         
            +
                  total_time.should < 0.06
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
              
         
     | 
| 
      
 52 
     | 
    
         
            +
              describe Anticipate, "with overridden interval" do
         
     | 
| 
      
 53 
     | 
    
         
            +
                include Anticipate
         
     | 
| 
      
 54 
     | 
    
         
            +
                
         
     | 
| 
      
 55 
     | 
    
         
            +
                def default_interval
         
     | 
| 
      
 56 
     | 
    
         
            +
                  0.01
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                it "uses the overridden interval" do
         
     | 
| 
      
 60 
     | 
    
         
            +
                  raises = []
         
     | 
| 
      
 61 
     | 
    
         
            +
                  lambda {
         
     | 
| 
      
 62 
     | 
    
         
            +
                    failing_after(5).tries {
         
     | 
| 
      
 63 
     | 
    
         
            +
                      raise (raises << Time.now).to_s
         
     | 
| 
      
 64 
     | 
    
         
            +
                    }
         
     | 
| 
      
 65 
     | 
    
         
            +
                  }.should raise_error(TimeoutError)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  raises.size.should == 6
         
     | 
| 
      
 67 
     | 
    
         
            +
                  total_time = raises.last - raises.first
         
     | 
| 
      
 68 
     | 
    
         
            +
                  total_time.should > 0.05
         
     | 
| 
      
 69 
     | 
    
         
            +
                  total_time.should < 0.06
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
      
 72 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,75 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: anticipate
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 4 
     | 
    
         
            +
              hash: 29
         
     | 
| 
      
 5 
     | 
    
         
            +
              prerelease: 
         
     | 
| 
      
 6 
     | 
    
         
            +
              segments: 
         
     | 
| 
      
 7 
     | 
    
         
            +
              - 0
         
     | 
| 
      
 8 
     | 
    
         
            +
              - 0
         
     | 
| 
      
 9 
     | 
    
         
            +
              - 1
         
     | 
| 
      
 10 
     | 
    
         
            +
              version: 0.0.1
         
     | 
| 
      
 11 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 12 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 13 
     | 
    
         
            +
            - Josh Chisholm
         
     | 
| 
      
 14 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 15 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 16 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            date: 2011-01-31 00:00:00 +00:00
         
     | 
| 
      
 19 
     | 
    
         
            +
            default_executable: 
         
     | 
| 
      
 20 
     | 
    
         
            +
            dependencies: []
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            description: Fluent interface for try-rescue-sleep-retry-abort
         
     | 
| 
      
 23 
     | 
    
         
            +
            email: joshuachisholm@gmail.com
         
     | 
| 
      
 24 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            extra_rdoc_files: 
         
     | 
| 
      
 29 
     | 
    
         
            +
            - README.rdoc
         
     | 
| 
      
 30 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 31 
     | 
    
         
            +
            - README.rdoc
         
     | 
| 
      
 32 
     | 
    
         
            +
            - anticipate.gemspec
         
     | 
| 
      
 33 
     | 
    
         
            +
            - lib/anticipate.rb
         
     | 
| 
      
 34 
     | 
    
         
            +
            - lib/anticipate/anticipator.rb
         
     | 
| 
      
 35 
     | 
    
         
            +
            - lib/anticipate/timeout_error.rb
         
     | 
| 
      
 36 
     | 
    
         
            +
            - spec/anticipate/anticipate_spec.rb
         
     | 
| 
      
 37 
     | 
    
         
            +
            - spec/anticipate/anticipator_spec.rb
         
     | 
| 
      
 38 
     | 
    
         
            +
            - spec/anticipate/integration_spec.rb
         
     | 
| 
      
 39 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     | 
| 
      
 40 
     | 
    
         
            +
            has_rdoc: true
         
     | 
| 
      
 41 
     | 
    
         
            +
            homepage: http://github.com/joshski/anticipate
         
     | 
| 
      
 42 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 45 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 48 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 49 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 50 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 51 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 52 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 53 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 54 
     | 
    
         
            +
                  hash: 3
         
     | 
| 
      
 55 
     | 
    
         
            +
                  segments: 
         
     | 
| 
      
 56 
     | 
    
         
            +
                  - 0
         
     | 
| 
      
 57 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 58 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 59 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 60 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 61 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 62 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 63 
     | 
    
         
            +
                  hash: 3
         
     | 
| 
      
 64 
     | 
    
         
            +
                  segments: 
         
     | 
| 
      
 65 
     | 
    
         
            +
                  - 0
         
     | 
| 
      
 66 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 67 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 70 
     | 
    
         
            +
            rubygems_version: 1.4.1
         
     | 
| 
      
 71 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 72 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 73 
     | 
    
         
            +
            summary: anticipate-0.0.1
         
     | 
| 
      
 74 
     | 
    
         
            +
            test_files: []
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     |