waiting 0.3.0 → 1.0.0

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.
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!