retry_upto 1.1 → 1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.md +20 -20
  2. data/lib/retry_upto.rb +9 -10
  3. data/test/retry_upto_test.rb +23 -30
  4. metadata +8 -8
data/README.md CHANGED
@@ -1,12 +1,18 @@
1
1
  # retry_upto: retry with steroids
2
2
 
3
3
  If you need to use `retry` in ruby, you probably want to retry some code only a **maximum number of times**,
4
- and sometimes **wait a bit** between the attempts to avoid external resources hiccups or usage limits.
4
+ and sometimes **wait an interval of time** between the attempts to avoid external resources hiccups or usage limits.
5
5
 
6
6
  Therefore **Your Important Code** ends surrounded by counters, conditions and calls to `sleep`.
7
7
 
8
8
  This gem deals elegantly with this common scenario:
9
9
 
10
+ retry_upto(5) do
11
+ # Your Important Code
12
+ end
13
+
14
+ Under Ruby 1.9 it also allows:
15
+
10
16
  5.times.retry do
11
17
  # Your Important Code
12
18
  end
@@ -21,28 +27,18 @@ Retries up to 5 times catching any exception, doesn't wait between attempts:
21
27
 
22
28
  retry_upto(5)
23
29
 
24
- ### Waiting time between attempts
30
+ ### Time intervals between attempts
25
31
 
26
- Retries up to 5 times, waits 2 seconds between attempts:
32
+ For fixed intervals, an `:interval` parameter can be passed indicating the time in seconds.
33
+ The following example will sleep two seconds between attempts:
27
34
 
28
35
  retry_upto(5, :interval => 2)
29
36
 
30
- ### Varying waiting time between attempts
31
-
32
- Retries up to 5 times, waits 1 second after the first attempt and increases
33
- the time between the following attempts (2, 4, 8, ...):
34
-
35
- retry_upto(5, :interval => 1, :growth => 2)
37
+ For customized intervals, the `:interval` parameter can be a lambda, which will be applied
38
+ to the number of each attempt. For instance, the following code will sleep 3 seconds after
39
+ the first attempt, 6 after the second, 9 after the third...
36
40
 
37
- Retries up to 5 times, waits 1 second after the first attempt and decreases
38
- the time between the following attempts (0.5, 0.25, 0.125, ...):
39
-
40
- retry_upto(5, :interval => 1, :growth => 0.5)
41
-
42
- Retries up to 5 times, waits 1 second after the first attempt and increases
43
- randomly the time between the following attempts:
44
-
45
- retry_upto(5, :interval => 1, :growth => lambda{ |x| x + rand(3) } )
41
+ retry_upto(5, :interval => lambda{ |attempt| attempt * 3 })
46
42
 
47
43
  ### Retrying only when certain Exceptions get raised
48
44
 
@@ -50,6 +46,10 @@ Retries up to 5 times only after a ZeroDivisionError, raising any other Exceptio
50
46
 
51
47
  retry_upto(5, :rescue => ZeroDivisionError)
52
48
 
49
+ Retries up to 5 times only after a ZeroDivisionError or a NameError, raising any other Exception:
50
+
51
+ retry_upto(5, :rescue => [ZeroDivisionError, NameError])
52
+
53
53
  All the options described above can be combined together.
54
54
 
55
55
  ### More sugar!
@@ -58,7 +58,7 @@ In ruby 1.9, the `Enumerator` class gets enhanced to use `retry_upto` this way:
58
58
 
59
59
  5.times.retry
60
60
 
61
- And yes, this accepts the same options:
61
+ This syntax accepts the same options:
62
62
 
63
63
  5.times.retry(:interval => 10)
64
64
 
@@ -68,7 +68,7 @@ See the LICENSE file included in the distribution.
68
68
 
69
69
  ## Authors
70
70
 
71
- This gem was born from gists by Raul Murciano, Glenn Gillen, Pedro Belo, Jaime Iniesta, Lleïr Borras and ideas taken from Aitor García Rey.
71
+ This gem was born from gists by Raul Murciano, Glenn Gillen, Pedro Belo, Jaime Iniesta, Lleïr Borras and ideas taken from Aitor García Rey and Jim Remsik.
72
72
 
73
73
  Yes, so many brain cells and so few lines of code. Great, isn't it?
74
74
 
data/lib/retry_upto.rb CHANGED
@@ -1,20 +1,19 @@
1
1
  # See README.md for usage explanations
2
2
 
3
- def retry_upto(max_retries = 1, options = {})
3
+ def retry_upto(max_retries = 1, opts = {})
4
4
  yield
5
- rescue *(options[:rescue] || Exception)
6
- raise if (max_retries -= 1) == 0
7
- sleep(options[:interval] || 0)
8
- if options[:growth].respond_to?('*')
9
- options[:interval] = options[:interval] * options[:growth]
10
- elsif options[:growth].respond_to?(:call)
11
- options[:interval] = options[:growth].call(options[:interval])
5
+ rescue *(opts[:rescue] || Exception)
6
+ attempt = attempt ? attempt+1 : 1
7
+ raise if (attempt == max_retries)
8
+ if interval = opts[:interval]
9
+ secs = interval.respond_to?(:call) ? interval.call(attempt) : interval
10
+ sleep(secs)
12
11
  end
13
12
  retry
14
13
  end
15
14
 
16
15
  class Enumerator
17
- def retry(options = {}, &blk)
18
- retry_upto(self.count, options, &blk)
16
+ def retry(opts = {}, &blk)
17
+ retry_upto(self.count, opts, &blk)
19
18
  end
20
19
  end
@@ -1,6 +1,6 @@
1
1
  require './test/test_helper'
2
2
 
3
- class Retry_uptoTest < MiniTest::Unit::TestCase
3
+ class RetryUptoTest < MiniTest::Unit::TestCase
4
4
 
5
5
  class FooError < Exception; end
6
6
  class BarError < Exception; end
@@ -12,16 +12,16 @@ class Retry_uptoTest < MiniTest::Unit::TestCase
12
12
  @bars = 0
13
13
  end
14
14
 
15
- # raises FooError only in the two first calls
15
+ # raises FooError only in the 3 first calls
16
16
  def foo!
17
17
  @foos += 1
18
- raise FooError if @foos < 3
18
+ raise FooError if @foos < 4
19
19
  end
20
20
 
21
- # raises BarError only in the two first calls
21
+ # raises BarError only in the 3 first calls
22
22
  def bar!
23
23
  @bars += 1
24
- raise BarError if @bars < 3
24
+ raise BarError if @bars < 4
25
25
  end
26
26
  end
27
27
 
@@ -39,69 +39,62 @@ class Retry_uptoTest < MiniTest::Unit::TestCase
39
39
  end
40
40
 
41
41
  def test_retries_the_desired_number_of_attempts
42
- retry_upto(3){ @target.foo! }
43
- assert_equal 3, @target.foos
42
+ retry_upto(4){ @target.foo! }
43
+ assert_equal 4, @target.foos
44
44
  end
45
45
 
46
46
  # interval between attempts
47
47
 
48
48
  def test_there_is_no_interval_between_attempts_by_default
49
- self.expects(:sleep).times(2).with(0).returns(nil)
50
- retry_upto(3){ @target.foo! }
49
+ self.expects(:sleep).never
50
+ retry_upto(4){ @target.foo! }
51
51
  end
52
52
 
53
53
  def test_interval_between_attempts_can_be_customized
54
- self.expects(:sleep).times(2).with(5).returns(nil)
55
- retry_upto(3, :interval => 5){ @target.foo! }
54
+ self.expects(:sleep).times(3).with(5).returns(nil)
55
+ retry_upto(4, :interval => 5){ @target.foo! }
56
56
  end
57
57
 
58
- # interval growth between attempts
59
-
60
- def test_inverval_can_be_multiplied_by_an_integer_growth
61
- self.expects(:sleep).times(1).with(5)
62
- self.expects(:sleep).times(1).with(15)
63
- retry_upto(3, :interval => 5, :growth => 3){ @target.foo! }
64
- end
65
-
66
- def test_grow_for_inverval_between_attempts_can_be_defined_with_a_lambda
67
- self.expects(:sleep).times(1).with(5)
68
- self.expects(:sleep).times(1).with(7)
69
- retry_upto(3, :interval => 5, :growth => lambda{ |t| t + 2 }){ @target.foo! }
58
+ def test_different_intervals_can_be_defined_with_a_lambda
59
+ self.expects(:sleep).times(1).with(3)
60
+ self.expects(:sleep).times(1).with(6)
61
+ self.expects(:sleep).times(1).with(9)
62
+ retry_upto(4, :interval => lambda{ |attempt| attempt * 3 }){ @target.foo! }
70
63
  end
71
64
 
72
65
  # exceptions
73
66
 
74
67
  def test_by_default_any_exception_gets_captured_if_there_are_attempts_left
75
- retry_upto(3){ @target.foo! }
68
+ retry_upto(4){ @target.foo! }
76
69
  assert true # if we reach this no exception was raised out of retry_upto
77
70
  end
78
71
 
79
72
  def test_the_last_attempt_does_not_capture_the_exception
80
73
  assert_raises(FooError) do
81
- retry_upto(2){ @target.foo! }
74
+ retry_upto(3){ @target.foo! }
82
75
  end
83
76
  end
84
77
 
85
78
  def test_a_specified_exception_will_be_captured_between_attempts
86
- retry_upto(3, :rescue => FooError){ @target.foo! }
79
+ retry_upto(4, :rescue => FooError){ @target.foo! }
87
80
  assert true # if we reach this no exception was raised out of retry_upto
88
81
  end
89
82
 
90
83
  def test_several_specified_exceptions_will_be_captured_between_attempts
91
- retry_upto(3, :rescue => [FooError, BarError]){ @target.foo! }
92
- retry_upto(3, :rescue => [FooError, BarError]){ @target.bar! }
84
+ retry_upto(4, :rescue => [FooError, BarError]){ @target.foo! }
85
+ retry_upto(4, :rescue => [FooError, BarError]){ @target.bar! }
93
86
  assert true # if we reach this no exception was raised out of retry_upto
94
87
  end
95
88
 
96
89
  def test_the_last_attempt_does_not_capture_the_specified_exception
97
90
  assert_raises(FooError) do
98
- retry_upto(2, :rescue => FooError){ @target.foo! }
91
+ retry_upto(3, :rescue => FooError){ @target.foo! }
99
92
  end
100
93
  end
101
94
 
102
95
  def test_a_exception_different_from_the_specified_one_will_not_be_captured_between_attempts
103
96
  assert_raises(FooError) do
104
- retry_upto(3, :rescue => ZeroDivisionError){ @target.foo! }
97
+ retry_upto(4, :rescue => ZeroDivisionError){ @target.foo! }
105
98
  end
106
99
  end
107
100
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: retry_upto
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.1'
4
+ version: '1.2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -14,11 +14,11 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2011-10-08 00:00:00.000000000Z
17
+ date: 2011-10-10 00:00:00.000000000Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: minitest
21
- requirement: &2153033700 !ruby/object:Gem::Requirement
21
+ requirement: &2153491260 !ruby/object:Gem::Requirement
22
22
  none: false
23
23
  requirements:
24
24
  - - ! '>'
@@ -26,10 +26,10 @@ dependencies:
26
26
  version: '2.0'
27
27
  type: :development
28
28
  prerelease: false
29
- version_requirements: *2153033700
29
+ version_requirements: *2153491260
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: mocha
32
- requirement: &2153033220 !ruby/object:Gem::Requirement
32
+ requirement: &2153490760 !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
35
  - - ! '>='
@@ -37,10 +37,10 @@ dependencies:
37
37
  version: 0.10.0
38
38
  type: :development
39
39
  prerelease: false
40
- version_requirements: *2153033220
40
+ version_requirements: *2153490760
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
- requirement: &2153032760 !ruby/object:Gem::Requirement
43
+ requirement: &2153490260 !ruby/object:Gem::Requirement
44
44
  none: false
45
45
  requirements:
46
46
  - - ! '>='
@@ -48,7 +48,7 @@ dependencies:
48
48
  version: 0.9.2
49
49
  type: :development
50
50
  prerelease: false
51
- version_requirements: *2153032760
51
+ version_requirements: *2153490260
52
52
  description: adds some useful options to retry code blocks
53
53
  email:
54
54
  - raul@murciano.net