waiting 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZDY2YTVlYTIyZDBmZDhjZTkyNWE1YWU0ZWFiYmFmM2I5Mzg4YjY5ZQ==
5
- data.tar.gz: !binary |-
6
- ZWZjZWEyZDQ5M2Q3ZTJkODZmNmZjZGM1OGU4MmIyNGFjOWE0MzA0Zg==
2
+ SHA1:
3
+ metadata.gz: b08f089788fa4aa60a91cfc69b2a680a35f20f22
4
+ data.tar.gz: 72039eb831a615731eb8f45047b629df86d45ae4
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- Nzg2N2YzYTJjNmI3NzU5OWFiMmY3OGE2MmEwMDFiMzg0MTcwNGM1NzIxNTM2
10
- ODRjYjA4Y2NjMjcwNjE0MjNkNWFmZjU2MzBkZjVhYWI5M2ZhZGEzZWNmYWIw
11
- ZDI5NGJkZDg3MjRkMzgxNTIyODNjMWI0MDlkZjgwNjVmMTg1ZmM=
12
- data.tar.gz: !binary |-
13
- NzZiMWNkODNkZDdjMTQxNDY5MDY4ZTdiZTM5ZDA1ZmUxMzU1ZjMyZTYzNzgz
14
- NGI3MjRiYzY2MzI3MTYyYzUxNjM4NmFhYWMxNTc0ZGM2YWU4NTg3MDI0NDcy
15
- MzgyMjhiMjYwY2I4NGNiMTljZmE1NWZlZTFiZGNmYzI1YjA3ZDM=
6
+ metadata.gz: ea6d32881afd57b5f9924d012a93535d7a6e9598f51a6d79affef040b6868e6adcfbc640f57d67b9b6fc836b20ab4198d9c233e963c180bc567fc974a12ae504
7
+ data.tar.gz: dcb1edb32ce17edc4798e413c68b1a15d7f20f11d7171e183b78e9d668c5395e8e91b2cd0813756b921780978fccf11cd7149bce07a9529434a2e03cec6ad1a7
@@ -0,0 +1,3 @@
1
+ Metrics/BlockLength:
2
+ Exclude:
3
+ - 'spec/**/*_spec.rb'
@@ -0,0 +1,5 @@
1
+ guard :rspec, cmd: 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { 'spec' }
5
+ end
data/README.md CHANGED
@@ -25,36 +25,87 @@ Or install it yourself as:
25
25
  ```ruby
26
26
  require 'waiting'
27
27
 
28
- # optional
29
- Waiting.default_max_attempts = max_attempts # defaults to 60
30
- Waiting.default_interval = interval # seconds, defaults to 5
31
28
 
32
- # will poll every interval max_attempts times until something returns true
29
+ # Optionally set defaults.
30
+ #
31
+ Waiting.exp_base = exp_base # defaults to 1
32
+ Waiting.interval = interval # defaults to 5
33
+ Waiting.max_attempts = max_attempts # defaults to 60
34
+ Waiting.max_interval = max_interval # defaults to nil
35
+
36
+
37
+ # Will poll every interval, max_attempts times until something is true
38
+ #
33
39
  Waiting.wait do |waiter|
34
40
  waiter.done if something
35
41
  end
36
42
 
37
- # You can also specify the max_attempts and interval this way
38
- Waiting.wait(interval: interval, max_attempts: max_attempts) do |waiter|
43
+
44
+ # Override the defaults here
45
+ #
46
+ Waiting.wait(exp_base: exp_base,
47
+ interval: interval,
48
+ max_attempts: max_attempts,
49
+ max_interval: max_interval
50
+ ) do |waiter|
39
51
  waiter.done if something
40
52
  end
41
53
 
42
- # You can do exponential backoff
43
- # for example, exp_base of 2 and an interval of 1 second,
44
- # will wait for: 1,2,4,8...
45
- Waiting.wait(exp_base: 2) do |waiter|
54
+
55
+ # Or make an instance of Waiting to pass around
56
+ #
57
+ waiting = Waiting.new(exp_base: exp_base,
58
+ interval: interval,
59
+ max_attempts: max_attempts,
60
+ max_interval: max_interval
61
+ ) do |waiter|
46
62
  waiter.done if something
47
63
  end
48
64
 
49
- # or specify it as a default
50
- Waiting.default_exp_base = exp_base # exponential backoff base, defaults to 1
51
65
 
52
- # will log options, and give progress updates if you like
53
- Waiting.wait do |waiter|
54
- puts waiter.attempts
55
- puts waiter.exp_base
56
- puts waiter.interval
57
- puts waiter.max_attempts
66
+ # And get it to wait
67
+ #
68
+ waiting.wait
69
+
70
+
71
+ # Or overide any parameters here again
72
+ #
73
+ waiting.wait(exp_base: exp_base,
74
+ interval: interval,
75
+ max_attempts: max_attempts,
76
+ max_interval: max_interval
77
+ ) do |waiter|
78
+ waiter.done if something
79
+ end
80
+
81
+
82
+ # Access the wait parameters during the wait
83
+ #
84
+ waiting.wait do |waiter|
85
+ puts "attempts: #{waiter.attempts}"
86
+ puts "exp_base: #{waiter.exp_base}"
87
+ puts "interval: #{waiter.interval}"
88
+ puts "max_attempts: #{waiter.max_attempts}"
89
+ puts "max_interval: #{waiter.max_interval}"
90
+ waiter.done if something
91
+ end
92
+ # =>
93
+ # attempts: 0
94
+ # exp_base: 1
95
+ # interval: 5
96
+ # max_attempts: 60
97
+ # max_interval: nil
98
+
99
+
100
+ # Leverage exp base for exponential back off
101
+ #
102
+ # Will wait for: 1, 2, 4, 8, 16, 16, 16...
103
+ #
104
+ waiting.wait(exp_base: 2,
105
+ interval: 1,
106
+ max_attempts: 16
107
+ ) do |waiter|
108
+ waiter.done if something
58
109
  end
59
110
  ```
60
111
 
@@ -1,72 +1,103 @@
1
- require 'waiting/timed_out_error'
2
1
  require 'waiting/waiter'
3
- require 'waiting/version'
4
2
 
5
- module Waiting
6
- # get the default wait interval
7
- # @return [Fixnum] the interval in seconds
8
- def self.default_interval
9
- @@default_interval ||= 5
10
- end
3
+ # Waits for things so you don't have to
4
+ #
5
+ class Waiting
6
+ # @param interval [Numeric] Polling interval in seconds.
7
+ # @param max_attempts [Numeric] Number of attempts before timing out.
8
+ # @param exp_base [Numeric] Increases the interval by the power of attempts.
9
+ # @param max_interval [Numeric] Interval limit for exponential backoff.
10
+ #
11
+ # @yield Block to check if the wait is over.
12
+ # @yieldparam waiter [Waiting::Waiter] call +#done+ if the wait is over
13
+ #
14
+ def initialize(exp_base: self.class.default_exp_base,
15
+ interval: self.class.default_interval,
16
+ max_attempts: self.class.default_max_attempts,
17
+ max_interval: self.class.default_max_interval,
18
+ &block)
11
19
 
12
- # set the default wait interval
13
- # @param [Fixnum] interval the interval in seconds
14
- def self.default_interval=(interval)
15
- @@default_interval = interval
16
- end
20
+ @exp_base = exp_base
21
+ @interval = interval
22
+ @max_attempts = max_attempts
23
+ @max_interval = max_interval
17
24
 
18
- # get the default exponential base
19
- # @return [Float] the base for exponential backoff
20
- def self.default_exp_base
21
- @@default_exp_base ||= 1
25
+ @block = block
22
26
  end
23
27
 
24
- # set the default exponential base
25
- # @param [Float] exp_base the base for exponential backoff
26
- def self.default_exp_base=(exp_base)
27
- @@default_exp_base = exp_base
28
- end
28
+ class << self
29
+ # The default exp base
30
+ #
31
+ # @return [Numeric]
32
+ #
33
+ attr_accessor :default_exp_base
29
34
 
30
- # get the default max attempts
31
- # @return [Fixnum] the default max attempts
32
- def self.default_max_attempts
33
- @@default_max_attempts ||= 60
34
- end
35
+ # The default interval
36
+ #
37
+ # @return [Numeric]
38
+ #
39
+ attr_accessor :default_interval
35
40
 
36
- # set the default max attempts
37
- # @param [Fixnum] max_attempts the default max attempts
38
- def self.default_max_attempts=(max_attempts)
39
- @@default_max_attempts = max_attempts
40
- end
41
+ # The default max attempts
42
+ #
43
+ # @return [Numeric]
44
+ #
45
+ attr_accessor :default_max_attempts
41
46
 
42
- # wait for something, call #ok on the waiter to signal the wait is over
43
- # @param [Hash] opts the options to wait with.
44
- # @option opts [Fixnum] :interval polling interval in seconds for checking
45
- # @option opts [Fixnum] :max_attempts number of attempts before failing
46
- def self.wait(opts = {})
47
- interval = opts.fetch(:interval) { default_interval }
48
- exp_base = opts.fetch(:exp_base) { default_exp_base }
49
- max_attempts = opts.fetch(:max_attempts) { default_max_attempts }
47
+ # The default max interval
48
+ #
49
+ # @return [Numeric]
50
+ #
51
+ attr_accessor :default_max_interval
52
+ end
50
53
 
51
- waiter = Waiter.new
54
+ self.default_exp_base = 1
55
+ self.default_interval = 5
56
+ self.default_max_attempts = 60
57
+ self.default_max_interval = nil
52
58
 
53
- attempts = 0
59
+ # @param interval [Numeric] Polling interval in seconds.
60
+ # @param max_attempts [Numeric] Number of attempts before timing out.
61
+ # @param exp_base [Numeric] Increases the interval by the power of attempts.
62
+ # @param max_interval [Numeric] Interval limit for exponential backoff.
63
+ #
64
+ # @yield Block to check if the wait is over.
65
+ # @yieldparam waiter [Waiting::Waiter] call +#done+ if the wait is over
66
+ #
67
+ def wait(exp_base: @exp_base,
68
+ interval: @interval,
69
+ max_attempts: @max_attempts,
70
+ max_interval: @max_interval,
71
+ &block)
54
72
 
55
- loop do
56
- if attempts >= max_attempts
57
- fail(TimedOutError, "Timed out after #{interval * max_attempts}s")
58
- end
73
+ Waiter.new(
74
+ exp_base: exp_base,
75
+ interval: interval,
76
+ max_attempts: max_attempts,
77
+ max_interval: max_interval
78
+ ).wait(&(block || @block))
79
+ end
59
80
 
60
- waiter.attempts = attempts
61
- waiter.exp_base = exp_base
62
- waiter.interval = interval
63
- waiter.max_attempts = max_attempts
81
+ # @see +#wait+
82
+ #
83
+ # @param interval [Numeric] Polling interval in seconds.
84
+ # @param max_attempts [Numeric] Number of attempts before timing out.
85
+ # @param exp_base [Numeric] Increases the interval by the power of attempts.
86
+ # @param max_interval [Numeric] Interval limit for exponential backoff.
87
+ #
88
+ # @yield Block to check if the wait is over.
89
+ # @yieldparam waiter [Waiting::Waiter] call +#done+ if the wait is over
90
+ #
91
+ def self.wait(exp_base: default_exp_base,
92
+ interval: default_interval,
93
+ max_attempts: default_max_attempts,
94
+ max_interval: default_max_interval,
95
+ &block)
64
96
 
65
- yield(waiter)
66
- break if waiter.done?
67
- sleep exp_base ** attempts * interval
68
- attempts += 1
69
- end
97
+ new(exp_base: exp_base,
98
+ interval: interval,
99
+ max_attempts: max_attempts,
100
+ max_interval: max_interval,
101
+ &block).wait
70
102
  end
71
-
72
103
  end
@@ -1,5 +1,6 @@
1
- module Waiting
2
- class TimedOutError < StandardError
3
-
4
- end
5
- end
1
+ class Waiting
2
+ # Raised when the wait times out
3
+ #
4
+ class TimedOutError < StandardError
5
+ end
6
+ end
@@ -1,3 +1,5 @@
1
- module Waiting
2
- VERSION = '0.3.0'
1
+ class Waiting
2
+ # The version of Waiting
3
+ #
4
+ VERSION = '1.0.0'.freeze
3
5
  end
@@ -1,24 +1,97 @@
1
- module Waiting
2
- class Waiter
3
- attr_accessor :attempts
4
- attr_accessor :exp_base
5
- attr_accessor :interval
6
- attr_accessor :max_attempts
7
-
8
- # Waiter is in waiting state to start with
9
- def initialize
10
- @done = false
11
- end
12
-
13
- # Mark the waiter as done
14
- def done
15
- @done = true
16
- end
17
-
18
- # Is the waiter done?
19
- # @return [Boolean] if the waiter is done
20
- def done?
21
- @done
22
- end
23
- end
24
- end
1
+ require 'waiting/timed_out_error'
2
+
3
+ class Waiting
4
+ # The class that patiently waits
5
+ #
6
+ class Waiter
7
+ # The current attempt number
8
+ #
9
+ # @return [Integer]
10
+ #
11
+ attr_reader :attempts
12
+
13
+ # The exp base
14
+ #
15
+ # @return [Numeric]
16
+ #
17
+ attr_accessor :exp_base
18
+
19
+ # The interval
20
+ #
21
+ # @return [Numeric]
22
+ #
23
+ attr_accessor :interval
24
+
25
+ # The max attempts
26
+ #
27
+ # @return [Numeric]
28
+ #
29
+ attr_accessor :max_attempts
30
+
31
+ # The max interval
32
+ #
33
+ # @return [Numeric]
34
+ #
35
+ attr_accessor :max_interval
36
+
37
+ # @param interval [Numeric] Polling interval in seconds.
38
+ # @param max_attempts [Numeric] Number of attempts before timing out.
39
+ # @param exp_base [Numeric] Increases the interval by the power of attempts.
40
+ # @param max_interval [Numeric] Interval limit for exponential backoff.
41
+ #
42
+ # @yield Block to check if the wait is over.
43
+ # @yieldparam waiter [Waiting::Waiter] call +#done+ if the wait is over
44
+ #
45
+ def initialize(exp_base: Waiting.default_exp_base,
46
+ interval: Waiting.interval,
47
+ max_attempts: Waiting.max_attempts,
48
+ max_interval: Waiting.max_interval)
49
+
50
+ @exp_base = exp_base
51
+ @interval = interval
52
+ @max_attempts = max_attempts
53
+ @max_interval = max_interval
54
+
55
+ @done = false
56
+ @attempts = 0
57
+ end
58
+
59
+ # Mark the waiter as done
60
+ #
61
+ def done
62
+ @done = true
63
+ end
64
+
65
+ # Is the waiter done?
66
+ #
67
+ # @return [Boolean] if the waiter is done
68
+ #
69
+ def done?
70
+ @done
71
+ end
72
+
73
+ # Waits for +#done+ to be called
74
+ #
75
+ # @raise [Waiting::TimedOutError] if +#done+ is not called in time
76
+ #
77
+ def wait
78
+ loop do
79
+ if @attempts >= max_attempts
80
+ raise Waiting::TimedOutError,
81
+ "Timed out after #{interval * max_attempts}s"
82
+ end
83
+
84
+ yield(self)
85
+ break if done?
86
+ wait_once
87
+ end
88
+ end
89
+
90
+ private
91
+
92
+ def wait_once
93
+ sleep [exp_base**attempts * interval, max_interval].compact.min
94
+ @attempts += 1
95
+ end
96
+ end
97
+ end
@@ -14,12 +14,15 @@ Gem::Specification.new do |spec|
14
14
  spec.description = "Waits so you don't have to!"
15
15
  spec.homepage = 'https://github.com/meringu/waiting'
16
16
 
17
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
- spec.bindir = 'exe'
19
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
20
  spec.require_paths = ['lib']
21
21
 
22
22
  spec.add_development_dependency 'bundler', '~> 1.11'
23
+ spec.add_development_dependency 'guard-rspec', '~> 4.7'
23
24
  spec.add_development_dependency 'rake', '~> 10.0'
24
25
  spec.add_development_dependency 'rspec', '~> 3.0'
26
+ spec.add_development_dependency 'simplecov', '~> 0.13.0'
27
+ spec.add_development_dependency 'yard', '~> 0.9.8'
25
28
  end
metadata CHANGED
@@ -1,57 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waiting
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henry Muru Paenga
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-08 00:00:00.000000000 Z
11
+ date: 2017-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.11'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: guard-rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.7'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - ~>
45
+ - - "~>"
32
46
  - !ruby/object:Gem::Version
33
47
  version: '10.0'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - ~>
52
+ - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '10.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - ~>
59
+ - - "~>"
46
60
  - !ruby/object:Gem::Version
47
61
  version: '3.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - ~>
66
+ - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.13.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.13.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.9.8
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.9.8
55
97
  description: Waits so you don't have to!
56
98
  email:
57
99
  - meringu@gmail.com
@@ -59,10 +101,12 @@ executables: []
59
101
  extensions: []
60
102
  extra_rdoc_files: []
61
103
  files:
62
- - .gitignore
63
- - .rspec
64
- - .travis.yml
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".rubocop.yml"
107
+ - ".travis.yml"
65
108
  - Gemfile
109
+ - Guardfile
66
110
  - LICENSE
67
111
  - README.md
68
112
  - Rakefile
@@ -81,17 +125,17 @@ require_paths:
81
125
  - lib
82
126
  required_ruby_version: !ruby/object:Gem::Requirement
83
127
  requirements:
84
- - - ! '>='
128
+ - - ">="
85
129
  - !ruby/object:Gem::Version
86
130
  version: '0'
87
131
  required_rubygems_version: !ruby/object:Gem::Requirement
88
132
  requirements:
89
- - - ! '>='
133
+ - - ">="
90
134
  - !ruby/object:Gem::Version
91
135
  version: '0'
92
136
  requirements: []
93
137
  rubyforge_project:
94
- rubygems_version: 2.4.5
138
+ rubygems_version: 2.4.8
95
139
  signing_key:
96
140
  specification_version: 4
97
141
  summary: Waits so you don't have to!