attempt 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 087065c51e729d16ae28f79cb654fe9297320902
4
- data.tar.gz: b3ec80db39e164a6ec2f551e0815dbc29e0b4c61
3
+ metadata.gz: 1ec70ec03f74ac462d0981aae31fd9e896b9aa68
4
+ data.tar.gz: 00a6fda1a874fe350ba06867f595e84c311cdf92
5
5
  SHA512:
6
- metadata.gz: 3e65bf3517b1d6d529fc7e1e292b046f4b7a95a6e984f05c42addf293066a50082f9b88c78a6bf0ff5c0f2aeba3de5f0331f54981fd307ecfbbc1eb56276a880
7
- data.tar.gz: e3e4a05d424117e0a3315f82d39f90f48927e348a6e87b400f5d1e54bd57ee87a9ef83c332f6b6a0a087cfe691781677512be76bb1c014f6de5879b576f34cd7
6
+ metadata.gz: 48a3c30acad26d4411cf450897defea366d343294e0b43f16f5685900461b323256da6f2c0a390c993da09dac844c1934bb213fbc5f17269154e12449aeed2cd
7
+ data.tar.gz: fddca1ffba92d22baf4c2d7ff6a4f6b410e33aee00f0045c6780a535fb3af93f62bd333241b27483140d41f25f8c5342d1feebd6ea39c873bcacf8adc94431a8
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGES CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.4.0 - 5-Sep-2017
2
+ * Switched constructor to use keyword arguments.
3
+ * Replaced Timeout with SafeTimeout and added the safe_timeout dependency.
4
+ * The :log option now accepts either an IO or Logger object.
5
+ * Updated cert.
6
+
1
7
  == 0.3.2 - 4-Apr-2017
2
8
  * Fix metadata key names.
3
9
 
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'attempt'
5
- spec.version = '0.3.2'
5
+ spec.version = '0.4.0'
6
6
  spec.author = 'Daniel J. Berger'
7
7
  spec.license = 'Artistic 2.0'
8
8
  spec.email = 'djberg96@gmail.com'
@@ -22,6 +22,8 @@ Gem::Specification.new do |spec|
22
22
  }
23
23
 
24
24
  spec.add_dependency('structured_warnings', '~> 0.3.0')
25
+ spec.add_dependency('safe_timeout', '~> 0.0.5')
26
+
25
27
  spec.add_development_dependency('test-unit')
26
28
 
27
29
  spec.description = <<-EOF
@@ -1,21 +1,21 @@
1
1
  -----BEGIN CERTIFICATE-----
2
2
  MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MREwDwYDVQQDDAhkamJl
3
3
  cmc5NjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t
4
- MB4XDTE2MDkxOTAzNDY0NVoXDTE3MDkxOTAzNDY0NVowPzERMA8GA1UEAwwIZGpi
4
+ MB4XDTE3MDkwMzE1MjMxM1oXDTE4MDkwMzE1MjMxM1owPzERMA8GA1UEAwwIZGpi
5
5
  ZXJnOTYxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
6
- bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM0eOHOQRpLOeqkyeK7O
7
- DGHYLkO0Wq7gStVVVyHXahgyCopLN6JVBwGy5aCpKFcy5sFz2DdnISj+hQ7FctDa
8
- yz6Lq9TvAF8Jkis8dDFLQKeHilB/AM4ssQAsGQyoQnoE4v5tCOSW4e3YHFDp/dMZ
9
- s7Hkoim6PeEdkh4hB5LCa90OrHSPe8nlMFsVhRIGj86xNTRazEiWPZCOKmN9rZgW
10
- ziheP/6hC2c7vNRevv5iE/K+NqaL/WOdMquOSZoF2mdBcoMIPDDBNzh/oHinPQ3N
11
- 1oOvoET0+Tj+O5tXX/L1TAsUrwZXlyrYGaZ5aYyoo/7r9pmvmbfgBqaU6JywT0EE
12
- 5x0CAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFO+k
13
- C/3R+t2aIyIpwU5wPrAfYVL6MB0GA1UdEQQWMBSBEmRqYmVyZzk2QGdtYWlsLmNv
6
+ bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ8y4kEssxNpAdPhNNw2
7
+ p4zkERFndPAnmOKDdErczFYYUA9uYpA7/iTjkLlNyRwvsNHpnMXdSF7vy++YIU+F
8
+ Ux3AGTmspupbdSzqBNUhSEJ9TmpjMer1dMYMR9fRw3r3qQreiO2u/O/tV4VpzrDj
9
+ 28JC0b1PcKtfobxbnk+hporZqTH6ClOxDsRx+trlkr7q7FLZwTZn0ywjAV8WMVTO
10
+ SMmkzXQ37s2Nnrq6r+dDZI0voBxyQkAUzmdBOQTrvOFAo3tuWcnJNR/RRdFhJ9nK
11
+ mYMPmEd1z0s+cU0SUEeTvhGv/9LCmbSyZqKezDLYNR4Gb0FOA9D50+4OOi2+3G1o
12
+ 1U0CAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFJCx
13
+ ukSSioTiLtwQCdML0IyEZAJ/MB0GA1UdEQQWMBSBEmRqYmVyZzk2QGdtYWlsLmNv
14
14
  bTAdBgNVHRIEFjAUgRJkamJlcmc5NkBnbWFpbC5jb20wDQYJKoZIhvcNAQEFBQAD
15
- ggEBAIJWpqQOUMoYhpm0wJ4kfiYv9rZVbpZ3L2cFYt4O6+wgbpdWP8DBBgZfCSQW
16
- 1J9miChMKdxZ8eOoeId79IMXN3IAcnalTFvD0Rp9ltaFZTXBfXMFqxQN3fHsIVwz
17
- as/JSbwXo/PE8rULhjU+Utwcmji38cKEDWLAW4vsCBmwvBTwmAmcuHHKjnNvd8aR
18
- YMrq9v505w8IjSysIO3KKysxCFuzoIPIYMdYswquvmtuTA+lpB9btWHr8n2FFsDp
19
- A943I/wqE6xbYQpHxkndWo5uLDUbZh+XxG+fhZKpeqLIqHaFuU6wdO5odt32kB/B
20
- nCjVswaVYlu1U2iLPCqE+MrjmTA=
15
+ ggEBAJh/dmRaTpJAUeJ2x9CEyy9gSP6SZjMeAwWgPNdowPDyw0JzlpBIrYiTnCYK
16
+ 2OqxvIi8L38+rHw3KYL0fEyNqP3RbMl6+SljRwiU0JwEqj9e1pqIx99RTLKeI9PM
17
+ F8LxxmDHreGOaY4R8JBOMxys1wBkF/Iilx4qoT4LBn+DzraAlmYjr6O6itIxGten
18
+ NFJFS/tFBTTeNW6SJLdDnGd2b7vBBEd/ZpIhuZNxriU6FKWC5FJeBdAiuw6lqHun
19
+ QLLepVJthIvwmfc8AU5TJGMawtVAUHIWiuQPoBBVVKOkeEhioO0cV8UabKsKMbE8
20
+ VpiARrgH+4lYiRFJ+gKpIbSEJvk=
21
21
  -----END CERTIFICATE-----
@@ -1,4 +1,4 @@
1
- require 'timeout'
1
+ require 'safe_timeout'
2
2
  require 'structured_warnings'
3
3
 
4
4
  # The Attempt class encapsulates methods related to multiple attempts at
@@ -6,7 +6,7 @@ require 'structured_warnings'
6
6
  class Attempt
7
7
 
8
8
  # The version of the attempt library.
9
- VERSION = '0.3.2'.freeze
9
+ VERSION = '0.4.0'.freeze
10
10
 
11
11
  # Warning raised if an attempt fails before the maximum number of tries
12
12
  # has been reached.
@@ -38,21 +38,34 @@ class Attempt
38
38
  attr_accessor :level
39
39
 
40
40
  # :call-seq:
41
- # Attempt.new{ |a| ... }
41
+ # Attempt.new(**kwargs)
42
42
  #
43
- # Creates and returns a new +Attempt+ object. Use a block to set the
44
- # accessors.
43
+ # Creates and returns a new +Attempt+ object. The supported keyword options
44
+ # are as follows:
45
45
  #
46
- def initialize
47
- @tries = 3 # Reasonable default
48
- @interval = 60 # Reasonable default
49
- @log = nil # Should be an IO handle, if provided
50
- @increment = nil # Should be an int, if provided
51
- @timeout = nil # Wrap the code in a timeout block if provided
52
- @level = Exception # Level of exception to be caught
53
- @warnings = true # Errors are sent to STDERR as warnings if true
54
-
55
- yield self if block_given?
46
+ # * tries - The number of attempts to make before giving up. The default is 3.
47
+ # * interval - The delay in seconds between each attempt. The default is 60.
48
+ # * log - An IO handle or Logger instance where warnings/errors are logged to. The default is nil.
49
+ # * increment - The amount to increment the interval between tries. The default is 0.
50
+ # * level - The level of exception to be caught. The default is everything, i.e. Exception.
51
+ # * warnings - Boolean value that indicates whether or not errors are treated as warnings
52
+ # until the maximum number of attempts has been made. The default is true.
53
+ # * timeout - Boolean value to indicate whether or not to automatically wrap your
54
+ # proc in a SafeTimeout block. The default is false.
55
+ #
56
+ # Example:
57
+ #
58
+ # a = Attempt.new(tries: 5, increment: 10, timeout: true)
59
+ # a.attempt{ http.get("http://something.foo.com") }
60
+ #
61
+ def initialize(**options)
62
+ @tries = options[:tries] || 3 # Reasonable default
63
+ @interval = options[:interval] || 60 # Reasonable default
64
+ @log = options[:log] # Should be an IO handle, if provided
65
+ @increment = options[:increment] || 0 # Should be an integer, if provided
66
+ @timeout = options[:timeout] || false # Wrap the code in a timeout block if provided
67
+ @level = options[:level] || Exception # Level of exception to be caught
68
+ @warnings = options[:warnings] || true # Errors are sent to STDERR as warnings if true
56
69
  end
57
70
 
58
71
  # Attempt to perform the operation in the provided block up to +tries+
@@ -65,7 +78,7 @@ class Attempt
65
78
  count = 1
66
79
  begin
67
80
  if @timeout
68
- Timeout.timeout(@timeout){ yield }
81
+ SafeTimeout.timeout(@timeout){ yield }
69
82
  else
70
83
  yield
71
84
  end
@@ -75,7 +88,11 @@ class Attempt
75
88
  msg = "Error on attempt # #{count}: #{error}; retrying"
76
89
  count += 1
77
90
  warn Warning, msg if @warnings
78
- @log.puts msg if @log
91
+
92
+ if @log # Accept an IO or Logger object
93
+ @log.respond_to?(:puts) ? @log.puts(msg) : @log.warn(msg)
94
+ end
95
+
79
96
  @interval += @increment if @increment
80
97
  sleep @interval
81
98
  retry
@@ -87,34 +104,28 @@ end
87
104
 
88
105
  module Kernel
89
106
  # :call-seq:
90
- # attempt(tries = 3, interval = 60, timeout = nil){ # some op }
107
+ # attempt(tries: 3, interval: 60, timeout: 10){ # some op }
91
108
  #
92
109
  # Attempt to perform the operation in the provided block up to +tries+
93
- # times, sleeping +interval+ between each try. By default the number
110
+ # times, sleeping +interval+ between each try. By default the number
94
111
  # of tries defaults to 3, the interval defaults to 60 seconds, and there
95
112
  # is no timeout specified.
96
113
  #
97
114
  # If +timeout+ is provided then the operation is wrapped in a Timeout
98
- # block as well. This is handy for those rare occasions when an IO
115
+ # block as well. This is handy for those rare occasions when an IO
99
116
  # connection could hang indefinitely, for example.
100
117
  #
101
118
  # If the operation still fails the (last) error is then re-raised.
102
119
  #
103
- # This is really just a wrapper for Attempt.new where the simple case is
104
- # good enough i.e. you don't care about warnings, increments or logging,
105
- # and you want a little added convenience.
120
+ # This is really just a convenient wrapper for Attempt.new + Attempt#attempt.
106
121
  #
107
122
  # Example:
108
123
  #
109
124
  # # Make 3 attempts to connect to the database, 60 seconds apart.
110
125
  # attempt{ DBI.connect(dsn, user, passwd) }
111
126
  #
112
- def attempt(tries = 3, interval = 60, timeout = nil, &block)
113
- raise 'no block given' unless block_given?
114
- Attempt.new{ |a|
115
- a.tries = tries
116
- a.interval = interval
117
- a.timeout = timeout if timeout
118
- }.attempt(&block)
127
+ def attempt(**kwargs, &block)
128
+ object = Attempt.new(kwargs)
129
+ object.attempt(&block)
119
130
  end
120
131
  end
data/test.rb ADDED
@@ -0,0 +1,10 @@
1
+ $:.unshift 'lib'
2
+ require 'attempt'
3
+ require 'logger'
4
+
5
+ log = Logger.new(STDOUT)
6
+
7
+ p Attempt::VERSION
8
+
9
+
10
+ attempt(tries: 2, log: log, timeout: 1, interval: 2){ sleep 3 }
@@ -23,7 +23,7 @@ class TC_Attempt < Test::Unit::TestCase
23
23
  end
24
24
 
25
25
  test "version constant is set to expected value" do
26
- assert_equal('0.3.2', Attempt::VERSION)
26
+ assert_equal('0.4.0', Attempt::VERSION)
27
27
  end
28
28
 
29
29
  test "attempt works as expected without arguments" do
@@ -31,24 +31,28 @@ class TC_Attempt < Test::Unit::TestCase
31
31
  end
32
32
 
33
33
  test "attempt retries the number of times specified" do
34
- assert_nothing_raised{ attempt(@tries){ $value += 1; raise if $value < 2 } }
34
+ assert_nothing_raised{ attempt(tries: @tries){ $value += 1; raise if $value < 2 } }
35
35
  assert_equal(2, $value)
36
36
  end
37
37
 
38
38
  test "attempt retries the number of times specified with interval" do
39
- assert_nothing_raised{ attempt(@tries, @interval){ $value += 1; raise if $value < 2 } }
39
+ assert_nothing_raised{
40
+ attempt(tries: @tries, interval: @interval){ $value += 1; raise if $value < 2 }
41
+ }
40
42
  end
41
43
 
42
44
  test "attempt retries the number of times specified with interval and timeout" do
43
- assert_nothing_raised{ attempt(@tries, @interval, @timeout){ $value += 1; raise if $value < 2 } }
45
+ assert_nothing_raised{
46
+ attempt(tries: @tries, interval: @interval, timeout: @timeout){ $value += 1; raise if $value < 2 }
47
+ }
44
48
  end
45
49
 
46
50
  test "attempt raises a timeout error if timeout value is exceeded" do
47
- assert_raises(Timeout::Error){ attempt(1, 1, @timeout){ sleep 5 } }
51
+ assert_raises(Timeout::Error){ attempt(tries: 1, interval: 1, timeout: @timeout){ sleep 5 } }
48
52
  end
49
53
 
50
54
  test "attempt raises exception as expected" do
51
- assert_raises(RuntimeError){ attempt(2, 2){ raise } }
55
+ assert_raises(RuntimeError){ attempt(tries: 2, interval: 2){ raise } }
52
56
  end
53
57
 
54
58
  def teardown
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attempt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
@@ -12,25 +12,25 @@ cert_chain:
12
12
  -----BEGIN CERTIFICATE-----
13
13
  MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MREwDwYDVQQDDAhkamJl
14
14
  cmc5NjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t
15
- MB4XDTE2MDkxOTAzNDY0NVoXDTE3MDkxOTAzNDY0NVowPzERMA8GA1UEAwwIZGpi
15
+ MB4XDTE3MDkwMzE1MjMxM1oXDTE4MDkwMzE1MjMxM1owPzERMA8GA1UEAwwIZGpi
16
16
  ZXJnOTYxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
17
- bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM0eOHOQRpLOeqkyeK7O
18
- DGHYLkO0Wq7gStVVVyHXahgyCopLN6JVBwGy5aCpKFcy5sFz2DdnISj+hQ7FctDa
19
- yz6Lq9TvAF8Jkis8dDFLQKeHilB/AM4ssQAsGQyoQnoE4v5tCOSW4e3YHFDp/dMZ
20
- s7Hkoim6PeEdkh4hB5LCa90OrHSPe8nlMFsVhRIGj86xNTRazEiWPZCOKmN9rZgW
21
- ziheP/6hC2c7vNRevv5iE/K+NqaL/WOdMquOSZoF2mdBcoMIPDDBNzh/oHinPQ3N
22
- 1oOvoET0+Tj+O5tXX/L1TAsUrwZXlyrYGaZ5aYyoo/7r9pmvmbfgBqaU6JywT0EE
23
- 5x0CAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFO+k
24
- C/3R+t2aIyIpwU5wPrAfYVL6MB0GA1UdEQQWMBSBEmRqYmVyZzk2QGdtYWlsLmNv
17
+ bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ8y4kEssxNpAdPhNNw2
18
+ p4zkERFndPAnmOKDdErczFYYUA9uYpA7/iTjkLlNyRwvsNHpnMXdSF7vy++YIU+F
19
+ Ux3AGTmspupbdSzqBNUhSEJ9TmpjMer1dMYMR9fRw3r3qQreiO2u/O/tV4VpzrDj
20
+ 28JC0b1PcKtfobxbnk+hporZqTH6ClOxDsRx+trlkr7q7FLZwTZn0ywjAV8WMVTO
21
+ SMmkzXQ37s2Nnrq6r+dDZI0voBxyQkAUzmdBOQTrvOFAo3tuWcnJNR/RRdFhJ9nK
22
+ mYMPmEd1z0s+cU0SUEeTvhGv/9LCmbSyZqKezDLYNR4Gb0FOA9D50+4OOi2+3G1o
23
+ 1U0CAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFJCx
24
+ ukSSioTiLtwQCdML0IyEZAJ/MB0GA1UdEQQWMBSBEmRqYmVyZzk2QGdtYWlsLmNv
25
25
  bTAdBgNVHRIEFjAUgRJkamJlcmc5NkBnbWFpbC5jb20wDQYJKoZIhvcNAQEFBQAD
26
- ggEBAIJWpqQOUMoYhpm0wJ4kfiYv9rZVbpZ3L2cFYt4O6+wgbpdWP8DBBgZfCSQW
27
- 1J9miChMKdxZ8eOoeId79IMXN3IAcnalTFvD0Rp9ltaFZTXBfXMFqxQN3fHsIVwz
28
- as/JSbwXo/PE8rULhjU+Utwcmji38cKEDWLAW4vsCBmwvBTwmAmcuHHKjnNvd8aR
29
- YMrq9v505w8IjSysIO3KKysxCFuzoIPIYMdYswquvmtuTA+lpB9btWHr8n2FFsDp
30
- A943I/wqE6xbYQpHxkndWo5uLDUbZh+XxG+fhZKpeqLIqHaFuU6wdO5odt32kB/B
31
- nCjVswaVYlu1U2iLPCqE+MrjmTA=
26
+ ggEBAJh/dmRaTpJAUeJ2x9CEyy9gSP6SZjMeAwWgPNdowPDyw0JzlpBIrYiTnCYK
27
+ 2OqxvIi8L38+rHw3KYL0fEyNqP3RbMl6+SljRwiU0JwEqj9e1pqIx99RTLKeI9PM
28
+ F8LxxmDHreGOaY4R8JBOMxys1wBkF/Iilx4qoT4LBn+DzraAlmYjr6O6itIxGten
29
+ NFJFS/tFBTTeNW6SJLdDnGd2b7vBBEd/ZpIhuZNxriU6FKWC5FJeBdAiuw6lqHun
30
+ QLLepVJthIvwmfc8AU5TJGMawtVAUHIWiuQPoBBVVKOkeEhioO0cV8UabKsKMbE8
31
+ VpiARrgH+4lYiRFJ+gKpIbSEJvk=
32
32
  -----END CERTIFICATE-----
33
- date: 2017-04-04 00:00:00.000000000 Z
33
+ date: 2017-09-05 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: structured_warnings
@@ -46,6 +46,20 @@ dependencies:
46
46
  - - "~>"
47
47
  - !ruby/object:Gem::Version
48
48
  version: 0.3.0
49
+ - !ruby/object:Gem::Dependency
50
+ name: safe_timeout
51
+ requirement: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 0.0.5
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 0.0.5
49
63
  - !ruby/object:Gem::Dependency
50
64
  name: test-unit
51
65
  requirement: !ruby/object:Gem::Requirement
@@ -85,6 +99,7 @@ files:
85
99
  - README
86
100
  - test
87
101
  - test/test_attempt.rb
102
+ - test.rb
88
103
  homepage: https://github.com/djberg96/attempt
89
104
  licenses:
90
105
  - Artistic 2.0
@@ -109,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
124
  version: '0'
110
125
  requirements: []
111
126
  rubyforge_project:
112
- rubygems_version: 2.6.11
127
+ rubygems_version: 2.6.12
113
128
  signing_key:
114
129
  specification_version: 4
115
130
  summary: A thin wrapper for begin + rescue + sleep + retry
metadata.gz.sig CHANGED
Binary file