retry_upto 1.0 → 1.1

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 +42 -19
  2. data/lib/retry_upto.rb +2 -52
  3. data/test/retry_upto_test.rb +35 -19
  4. metadata +44 -78
data/README.md CHANGED
@@ -1,44 +1,67 @@
1
1
  # retry_upto: retry with steroids
2
2
 
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.
5
+
6
+ Therefore **Your Important Code** ends surrounded by counters, conditions and calls to `sleep`.
7
+
8
+ This gem deals elegantly with this common scenario:
9
+
10
+ 5.times.retry do
11
+ # Your Important Code
12
+ end
13
+
14
+ Keep reading to see all the options available.
15
+
3
16
  ## Usage
4
17
 
5
- Basic usage
18
+ ### Basic usage
6
19
 
7
- - retries up to 5 times catching any exception, doesn't wait between attempts:
20
+ Retries up to 5 times catching any exception, doesn't wait between attempts:
8
21
 
9
- retry_upto(5) do ... end
22
+ retry_upto(5)
10
23
 
11
- Waiting time between attempts
24
+ ### Waiting time between attempts
12
25
 
13
- - retries up to 5 times, waits 2 seconds between attempts:
26
+ Retries up to 5 times, waits 2 seconds between attempts:
14
27
 
15
- retry_upto(5, :interval => 2) do ... end
28
+ retry_upto(5, :interval => 2)
16
29
 
17
- Varying waiting time between attempts
30
+ ### Varying waiting time between attempts
18
31
 
19
- - retries up to 5 times, waits 1 second after the first attempt and increases
20
- the time between the following attempts (2, 4, 8, ...):
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, ...):
21
34
 
22
- retry_upto(5, :interval => 1, :growth => 2) do ... end
35
+ retry_upto(5, :interval => 1, :growth => 2)
23
36
 
24
- - retries up to 5 times, waits 1 second after the first attempt and decreases
25
- the time between the following attempts (0.5, 0.25, 0.125, ...):
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, ...):
26
39
 
27
- retry_upto(5, :interval => 1, :growth => 0.5) do ... end
40
+ retry_upto(5, :interval => 1, :growth => 0.5)
28
41
 
29
- - retries up to 5 times, waits 1 second after the first attempt and increases
30
- randomly the time between the following attempts:
42
+ Retries up to 5 times, waits 1 second after the first attempt and increases
43
+ randomly the time between the following attempts:
31
44
 
32
- retry_upto(5, :interval => 1, :growth => lambda{ |x| x + rand(3) } ) do ... end
45
+ retry_upto(5, :interval => 1, :growth => lambda{ |x| x + rand(3) } )
33
46
 
34
- Retrying only when certain Exceptions get raised
47
+ ### Retrying only when certain Exceptions get raised
35
48
 
36
- - retries up to 5 times only after a ZeroDivisionError, raising any other Exception:
49
+ Retries up to 5 times only after a ZeroDivisionError, raising any other Exception:
37
50
 
38
- retry_upto(5, :rescue => ZeroDivisionError) do ... end
51
+ retry_upto(5, :rescue => ZeroDivisionError)
39
52
 
40
53
  All the options described above can be combined together.
41
54
 
55
+ ### More sugar!
56
+
57
+ In ruby 1.9, the `Enumerator` class gets enhanced to use `retry_upto` this way:
58
+
59
+ 5.times.retry
60
+
61
+ And yes, this accepts the same options:
62
+
63
+ 5.times.retry(:interval => 10)
64
+
42
65
  ## License
43
66
 
44
67
  See the LICENSE file included in the distribution.
data/lib/retry_upto.rb CHANGED
@@ -1,49 +1,8 @@
1
- # retry with steroids
2
- #
3
- # Basic usage:
4
- #
5
- # - retries up to 5 times catching any exception, doesn't wait between attempts
6
- #
7
- # retry_upto(5) do ... end
8
- #
9
- #
10
- # Waiting time between attempts:
11
- #
12
- # - retries up to 5 times, waits 2 seconds between attempts
13
- #
14
- # retry_upto(5, :interval => 2) do ... end
15
- #
16
- #
17
- # Varying waiting time between attempts:
18
- #
19
- # - retries up to 5 times, waits 1 second after the first attempt and increases
20
- # the time between the following attempts (2, 4, 8, ...)
21
- #
22
- # retry_upto(5, :interval => 1, :growth => 2) do ... end
23
- #
24
- # - retries up to 5 times, waits 1 second after the first attempt and decreases
25
- # the time between the following attempts (0.5, 0.25, 0.125, ...)
26
- #
27
- # retry_upto(5, :interval => 1, :growth => 0.5) do ... end
28
- #
29
- # - retries up to 5 times, waits 1 second after the first attempt and increases
30
- # randomly the time between the following attempts
31
- #
32
- # retry_upto(5, :interval => 1, :growth => lambda{ |x| x + rand(3) } ) do ... end
33
- #
34
- #
35
- # Retrying only when certain Exceptions get raised:
36
- #
37
- # - retries up to 5 times only after a ZeroDivisionError, raising any other Exception
38
- #
39
- # retry_upto(5, :rescue => ZeroDivisionError) do ... end
40
- #
41
- #
42
- # All the described options can be combined together.
1
+ # See README.md for usage explanations
43
2
 
44
3
  def retry_upto(max_retries = 1, options = {})
45
4
  yield
46
- rescue (options[:rescue] || Exception)
5
+ rescue *(options[:rescue] || Exception)
47
6
  raise if (max_retries -= 1) == 0
48
7
  sleep(options[:interval] || 0)
49
8
  if options[:growth].respond_to?('*')
@@ -54,15 +13,6 @@ rescue (options[:rescue] || Exception)
54
13
  retry
55
14
  end
56
15
 
57
-
58
-
59
- # Extends enumerator to allow usage like:
60
- #
61
- # 5.times.retry do
62
- # ...
63
- # end
64
- #
65
-
66
16
  class Enumerator
67
17
  def retry(options = {}, &blk)
68
18
  retry_upto(self.count, options, &blk)
@@ -3,15 +3,25 @@ require './test/test_helper'
3
3
  class Retry_uptoTest < MiniTest::Unit::TestCase
4
4
 
5
5
  class FooError < Exception; end
6
+ class BarError < Exception; end
6
7
 
7
- # raises ZeroDivisionError in the two first hits
8
8
  class Target
9
- attr_accessor :hits
10
- def initialize; @hits = 0; end
9
+ attr_accessor :foos, :bars
10
+ def initialize
11
+ @foos = 0
12
+ @bars = 0
13
+ end
14
+
15
+ # raises FooError only in the two first calls
16
+ def foo!
17
+ @foos += 1
18
+ raise FooError if @foos < 3
19
+ end
11
20
 
12
- def hit!
13
- @hits += 1
14
- raise FooError if @hits < 3
21
+ # raises BarError only in the two first calls
22
+ def bar!
23
+ @bars += 1
24
+ raise BarError if @bars < 3
15
25
  end
16
26
  end
17
27
 
@@ -23,26 +33,26 @@ class Retry_uptoTest < MiniTest::Unit::TestCase
23
33
 
24
34
  def test_retries_one_time_by_default_without_capturing_the_exception
25
35
  assert_raises(FooError) do
26
- retry_upto{ @target.hit! }
36
+ retry_upto{ @target.foo! }
27
37
  end
28
- assert_equal 1, @target.hits
38
+ assert_equal 1, @target.foos
29
39
  end
30
40
 
31
41
  def test_retries_the_desired_number_of_attempts
32
- retry_upto(3){ @target.hit! }
33
- assert_equal 3, @target.hits
42
+ retry_upto(3){ @target.foo! }
43
+ assert_equal 3, @target.foos
34
44
  end
35
45
 
36
46
  # interval between attempts
37
47
 
38
48
  def test_there_is_no_interval_between_attempts_by_default
39
49
  self.expects(:sleep).times(2).with(0).returns(nil)
40
- retry_upto(3){ @target.hit! }
50
+ retry_upto(3){ @target.foo! }
41
51
  end
42
52
 
43
53
  def test_interval_between_attempts_can_be_customized
44
54
  self.expects(:sleep).times(2).with(5).returns(nil)
45
- retry_upto(3, :interval => 5){ @target.hit! }
55
+ retry_upto(3, :interval => 5){ @target.foo! }
46
56
  end
47
57
 
48
58
  # interval growth between attempts
@@ -50,42 +60,48 @@ class Retry_uptoTest < MiniTest::Unit::TestCase
50
60
  def test_inverval_can_be_multiplied_by_an_integer_growth
51
61
  self.expects(:sleep).times(1).with(5)
52
62
  self.expects(:sleep).times(1).with(15)
53
- retry_upto(3, :interval => 5, :growth => 3){ @target.hit! }
63
+ retry_upto(3, :interval => 5, :growth => 3){ @target.foo! }
54
64
  end
55
65
 
56
66
  def test_grow_for_inverval_between_attempts_can_be_defined_with_a_lambda
57
67
  self.expects(:sleep).times(1).with(5)
58
68
  self.expects(:sleep).times(1).with(7)
59
- retry_upto(3, :interval => 5, :growth => lambda{ |t| t + 2 }){ @target.hit! }
69
+ retry_upto(3, :interval => 5, :growth => lambda{ |t| t + 2 }){ @target.foo! }
60
70
  end
61
71
 
62
72
  # exceptions
63
73
 
64
74
  def test_by_default_any_exception_gets_captured_if_there_are_attempts_left
65
- retry_upto(3){ @target.hit! }
75
+ retry_upto(3){ @target.foo! }
66
76
  assert true # if we reach this no exception was raised out of retry_upto
67
77
  end
68
78
 
69
79
  def test_the_last_attempt_does_not_capture_the_exception
70
80
  assert_raises(FooError) do
71
- retry_upto(2){ @target.hit! }
81
+ retry_upto(2){ @target.foo! }
72
82
  end
73
83
  end
74
84
 
75
85
  def test_a_specified_exception_will_be_captured_between_attempts
76
- retry_upto(3, :rescue => FooError){ @target.hit! }
86
+ retry_upto(3, :rescue => FooError){ @target.foo! }
87
+ assert true # if we reach this no exception was raised out of retry_upto
88
+ end
89
+
90
+ 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! }
77
93
  assert true # if we reach this no exception was raised out of retry_upto
78
94
  end
79
95
 
80
96
  def test_the_last_attempt_does_not_capture_the_specified_exception
81
97
  assert_raises(FooError) do
82
- retry_upto(2, :rescue => FooError){ @target.hit! }
98
+ retry_upto(2, :rescue => FooError){ @target.foo! }
83
99
  end
84
100
  end
85
101
 
86
102
  def test_a_exception_different_from_the_specified_one_will_not_be_captured_between_attempts
87
103
  assert_raises(FooError) do
88
- retry_upto(3, :rescue => ZeroDivisionError){ @target.hit! }
104
+ retry_upto(3, :rescue => ZeroDivisionError){ @target.foo! }
89
105
  end
90
106
  end
91
107
 
metadata CHANGED
@@ -1,84 +1,61 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: retry_upto
3
- version: !ruby/object:Gem::Version
4
- hash: 15
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.1'
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 0
9
- version: "1.0"
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Raul Murciano
13
9
  - Glenn Gillen
14
10
  - Pedro Belo
15
11
  - Jaime Iniesta
16
- - "Lle\xC3\xAFr Borras"
17
- - "Aitor Garc\xC3\xADa Rey"
12
+ - Lleïr Borras
13
+ - Aitor García Rey
18
14
  autorequire:
19
15
  bindir: bin
20
16
  cert_chain: []
21
-
22
- date: 2011-10-07 00:00:00 -07:00
23
- default_executable:
24
- dependencies:
25
- - !ruby/object:Gem::Dependency
17
+ date: 2011-10-08 00:00:00.000000000Z
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
26
20
  name: minitest
27
- prerelease: false
28
- requirement: &id001 !ruby/object:Gem::Requirement
21
+ requirement: &2153033700 !ruby/object:Gem::Requirement
29
22
  none: false
30
- requirements:
31
- - - ">"
32
- - !ruby/object:Gem::Version
33
- hash: 3
34
- segments:
35
- - 2
36
- - 0
37
- version: "2.0"
23
+ requirements:
24
+ - - ! '>'
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
38
27
  type: :development
39
- version_requirements: *id001
40
- - !ruby/object:Gem::Dependency
41
- name: mocha
42
28
  prerelease: false
43
- requirement: &id002 !ruby/object:Gem::Requirement
29
+ version_requirements: *2153033700
30
+ - !ruby/object:Gem::Dependency
31
+ name: mocha
32
+ requirement: &2153033220 !ruby/object:Gem::Requirement
44
33
  none: false
45
- requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- hash: 55
49
- segments:
50
- - 0
51
- - 10
52
- - 0
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
53
37
  version: 0.10.0
54
38
  type: :development
55
- version_requirements: *id002
56
- - !ruby/object:Gem::Dependency
57
- name: rake
58
39
  prerelease: false
59
- requirement: &id003 !ruby/object:Gem::Requirement
40
+ version_requirements: *2153033220
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: &2153032760 !ruby/object:Gem::Requirement
60
44
  none: false
61
- requirements:
62
- - - ">="
63
- - !ruby/object:Gem::Version
64
- hash: 63
65
- segments:
66
- - 0
67
- - 9
68
- - 2
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
69
48
  version: 0.9.2
70
49
  type: :development
71
- version_requirements: *id003
50
+ prerelease: false
51
+ version_requirements: *2153032760
72
52
  description: adds some useful options to retry code blocks
73
- email:
53
+ email:
74
54
  - raul@murciano.net
75
55
  executables: []
76
-
77
56
  extensions: []
78
-
79
57
  extra_rdoc_files: []
80
-
81
- files:
58
+ files:
82
59
  - lib/retry_upto.rb
83
60
  - test/retry_upto_test.rb
84
61
  - test/test_helper.rb
@@ -87,39 +64,28 @@ files:
87
64
  - LICENSE
88
65
  - RakeFile
89
66
  - README.md
90
- has_rdoc: true
91
67
  homepage: http://github.com/raul/retry_upto
92
68
  licenses: []
93
-
94
69
  post_install_message:
95
70
  rdoc_options: []
96
-
97
- require_paths:
71
+ require_paths:
98
72
  - lib
99
- required_ruby_version: !ruby/object:Gem::Requirement
73
+ required_ruby_version: !ruby/object:Gem::Requirement
100
74
  none: false
101
- requirements:
102
- - - ">="
103
- - !ruby/object:Gem::Version
104
- hash: 3
105
- segments:
106
- - 0
107
- version: "0"
108
- required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
80
  none: false
110
- requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- hash: 3
114
- segments:
115
- - 0
116
- version: "0"
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
117
85
  requirements: []
118
-
119
86
  rubyforge_project: retry_upto
120
- rubygems_version: 1.5.2
87
+ rubygems_version: 1.8.10
121
88
  signing_key:
122
89
  specification_version: 3
123
90
  summary: retry with steroids
124
91
  test_files: []
125
-