block_repeater 1.1.1 → 1.2.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 +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +28 -24
- data/README.md +37 -0
- data/block_repeater.gemspec +3 -2
- data/lib/block_repeater/replay.rb +36 -0
- data/lib/block_repeater/version.rb +1 -1
- data/lib/block_repeater.rb +2 -0
- metadata +23 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ea41f6457e3cf7aa83b6e1f5989f2a92b24174ebb6d12f48b564033661af1477
|
|
4
|
+
data.tar.gz: 7df266b49f3b8c32aff6a8d2826d18864b5d1885f41e3888ce80896bb715f73a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 75426f7a71bd028729e26a82424e142a9ffa40c2d88cc8704bf95f22051ddd2fc4c2677896d30d690d6c819a17c2e81d89013ff681d1511c224d56bb92eefd53
|
|
7
|
+
data.tar.gz: 414d3d2a92040b4e143d1fc4103f82ddb403fa9e154f0d2a688ef303b4b444c465d787260646bd0e875c41466484c7338c03941cadad06ba966289a33481998d
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,40 +1,43 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
block_repeater (1.
|
|
4
|
+
block_repeater (1.2.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
-
ast (2.4.
|
|
9
|
+
ast (2.4.3)
|
|
10
10
|
bump (0.10.0)
|
|
11
11
|
coderay (1.1.3)
|
|
12
|
-
diff-lcs (1.
|
|
13
|
-
json (2.
|
|
14
|
-
method_source (1.
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
diff-lcs (1.6.2)
|
|
13
|
+
json (2.21.1)
|
|
14
|
+
method_source (1.1.0)
|
|
15
|
+
ostruct (0.6.3)
|
|
16
|
+
parallel (1.28.0)
|
|
17
|
+
parser (3.3.12.0)
|
|
17
18
|
ast (~> 2.4.1)
|
|
18
|
-
|
|
19
|
+
racc
|
|
20
|
+
pry (0.14.2)
|
|
19
21
|
coderay (~> 1.1)
|
|
20
22
|
method_source (~> 1.0)
|
|
23
|
+
racc (1.8.1)
|
|
21
24
|
rainbow (3.1.1)
|
|
22
|
-
rake (
|
|
23
|
-
regexp_parser (2.
|
|
24
|
-
rexml (3.
|
|
25
|
-
rspec (3.
|
|
26
|
-
rspec-core (~> 3.
|
|
27
|
-
rspec-expectations (~> 3.
|
|
28
|
-
rspec-mocks (~> 3.
|
|
29
|
-
rspec-core (3.
|
|
30
|
-
rspec-support (~> 3.
|
|
31
|
-
rspec-expectations (3.
|
|
25
|
+
rake (13.4.2)
|
|
26
|
+
regexp_parser (2.12.0)
|
|
27
|
+
rexml (3.4.4)
|
|
28
|
+
rspec (3.13.2)
|
|
29
|
+
rspec-core (~> 3.13.0)
|
|
30
|
+
rspec-expectations (~> 3.13.0)
|
|
31
|
+
rspec-mocks (~> 3.13.0)
|
|
32
|
+
rspec-core (3.13.6)
|
|
33
|
+
rspec-support (~> 3.13.0)
|
|
34
|
+
rspec-expectations (3.13.5)
|
|
32
35
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
33
|
-
rspec-support (~> 3.
|
|
34
|
-
rspec-mocks (3.
|
|
36
|
+
rspec-support (~> 3.13.0)
|
|
37
|
+
rspec-mocks (3.13.8)
|
|
35
38
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
36
|
-
rspec-support (~> 3.
|
|
37
|
-
rspec-support (3.
|
|
39
|
+
rspec-support (~> 3.13.0)
|
|
40
|
+
rspec-support (3.13.7)
|
|
38
41
|
rubocop (1.50.2)
|
|
39
42
|
json (~> 2.3)
|
|
40
43
|
parallel (~> 1.10)
|
|
@@ -56,9 +59,10 @@ PLATFORMS
|
|
|
56
59
|
DEPENDENCIES
|
|
57
60
|
block_repeater!
|
|
58
61
|
bump (~> 0.6)
|
|
59
|
-
bundler (
|
|
62
|
+
bundler (>= 2.4)
|
|
63
|
+
ostruct
|
|
60
64
|
pry
|
|
61
|
-
rake (~>
|
|
65
|
+
rake (~> 13.0)
|
|
62
66
|
rspec (~> 3.8)
|
|
63
67
|
rubocop (~> 1.50.0)
|
|
64
68
|
|
data/README.md
CHANGED
|
@@ -115,6 +115,43 @@ Then an RSpec expectation can be used in the block for the `until` method. The e
|
|
|
115
115
|
expect(result.count).to be_positive, raise 'No result returned from databased'
|
|
116
116
|
end
|
|
117
117
|
```
|
|
118
|
+
### Replay method
|
|
119
|
+
The `replay` method provides a retry-with-refresh mechanism for UI actions that may fail due to transient errors. It is designed for use with browser automation tools like Capybara.
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
replay(exceptions: [Capybara::ElementNotFound], refresh: -> { page.refresh }) do
|
|
123
|
+
find('#submit-button').click
|
|
124
|
+
end
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`replay` takes five parameters:
|
|
128
|
+
- `times:` maximum retry attempts (defaults to 3)
|
|
129
|
+
- `delay:` seconds between retries (defaults to 0.5)
|
|
130
|
+
- `exceptions:` array of exception types to catch and retry on (defaults to [])
|
|
131
|
+
- `refresh:` a callable (Proc/lambda) to execute between retries for page refresh (defaults to nil)
|
|
132
|
+
- `logger:` any object responding to `#error` for error messages, or nil to silence logging (defaults to nil)
|
|
133
|
+
|
|
134
|
+
The block is executed and if a configured exception is raised, the error is logged, the refresh callable is invoked (if provided), and the block is retried. If the exception persists after all attempts, it is re-raised. The refresh is not called on the final attempt.
|
|
135
|
+
|
|
136
|
+
A typical setup with Capybara and locale handling:
|
|
137
|
+
```ruby
|
|
138
|
+
UI_ERRORS = [Capybara::ElementNotFound, Selenium::WebDriver::Error::ElementClickInterceptedError]
|
|
139
|
+
|
|
140
|
+
replay(exceptions: UI_ERRORS, refresh: -> { visit("#{current_path}?locale=#{I18n.locale}") }) do
|
|
141
|
+
click_link_or_button('Continue')
|
|
142
|
+
end
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
To use a custom logger:
|
|
146
|
+
```ruby
|
|
147
|
+
replay(exceptions: UI_ERRORS, logger: Rails.logger) { perform_action }
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
To silence logging:
|
|
151
|
+
```ruby
|
|
152
|
+
replay(exceptions: UI_ERRORS, logger: nil) { perform_action }
|
|
153
|
+
```
|
|
154
|
+
|
|
118
155
|
### Non predefined condition methods
|
|
119
156
|
Very simple conditions can be utilised without using a block. This expects either one or two method names which will be called against the result of repeating the main block.
|
|
120
157
|
The required format is `until_<method name>` or `until_<method name>_becomes_<method name>`.
|
data/block_repeater.gemspec
CHANGED
|
@@ -27,9 +27,10 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
spec.require_paths = ['lib']
|
|
28
28
|
|
|
29
29
|
spec.add_development_dependency 'bump', '~> 0.6'
|
|
30
|
-
spec.add_development_dependency 'bundler', '
|
|
30
|
+
spec.add_development_dependency 'bundler', '>= 2.4'
|
|
31
|
+
spec.add_development_dependency 'ostruct'
|
|
31
32
|
spec.add_development_dependency 'pry'
|
|
32
|
-
spec.add_development_dependency 'rake', '~>
|
|
33
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
|
33
34
|
spec.add_development_dependency 'rspec', '~> 3.8'
|
|
34
35
|
spec.add_development_dependency 'rubocop'
|
|
35
36
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BlockRepeater
|
|
4
|
+
##
|
|
5
|
+
# Provides a retry-with-refresh mechanism for UI actions
|
|
6
|
+
# that may fail due to transient driver/page errors.
|
|
7
|
+
#
|
|
8
|
+
# Consumers configure which exceptions to catch and how to refresh the page.
|
|
9
|
+
module Replay
|
|
10
|
+
##
|
|
11
|
+
# Execute a block, retrying on configured exceptions with optional page refresh.
|
|
12
|
+
#
|
|
13
|
+
# @param exceptions [Array<Class>] Exception types to catch and retry on
|
|
14
|
+
# @param times [Integer] Maximum retry attempts (default: 3)
|
|
15
|
+
# @param delay [Float] Seconds between retries (default: 0.5)
|
|
16
|
+
# @param refresh [Proc, nil] Callable to execute between retries for page refresh (default: nil)
|
|
17
|
+
# @param logger [#error, nil] Logger for error messages; nil to silence (default: nil)
|
|
18
|
+
# @param &block - The block of code to retry
|
|
19
|
+
# @return The result of the block
|
|
20
|
+
def replay(exceptions:, times: 3, delay: 0.5, refresh: nil, logger: nil, &block)
|
|
21
|
+
raise ArgumentError, 'replay requires a block' unless block
|
|
22
|
+
|
|
23
|
+
attempt = 0
|
|
24
|
+
|
|
25
|
+
repeat(times: times, delay: delay, &block).catch(exceptions: exceptions, behaviour: :continue) do |e|
|
|
26
|
+
attempt += 1
|
|
27
|
+
logger&.error { e.message }
|
|
28
|
+
raise(e) if attempt >= times
|
|
29
|
+
|
|
30
|
+
refresh&.call
|
|
31
|
+
end.until do |result|
|
|
32
|
+
!result.is_a?(Exception)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/block_repeater.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'block_repeater/version'
|
|
4
4
|
require 'block_repeater/repeatable'
|
|
5
|
+
require 'block_repeater/replay'
|
|
5
6
|
require 'block_repeater/repeater'
|
|
6
7
|
|
|
7
8
|
##
|
|
@@ -11,4 +12,5 @@ require 'block_repeater/repeater'
|
|
|
11
12
|
#
|
|
12
13
|
module BlockRepeater
|
|
13
14
|
include Repeatable
|
|
15
|
+
include Replay
|
|
14
16
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: block_repeater
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- William Bray
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bump
|
|
@@ -28,16 +28,30 @@ dependencies:
|
|
|
28
28
|
name: bundler
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: 2.4
|
|
33
|
+
version: '2.4'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.4'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: ostruct
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
39
46
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: pry
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,14 +72,14 @@ dependencies:
|
|
|
58
72
|
requirements:
|
|
59
73
|
- - "~>"
|
|
60
74
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
75
|
+
version: '13.0'
|
|
62
76
|
type: :development
|
|
63
77
|
prerelease: false
|
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
79
|
requirements:
|
|
66
80
|
- - "~>"
|
|
67
81
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
82
|
+
version: '13.0'
|
|
69
83
|
- !ruby/object:Gem::Dependency
|
|
70
84
|
name: rspec
|
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -119,6 +133,7 @@ files:
|
|
|
119
133
|
- lib/block_repeater/repeatable.rb
|
|
120
134
|
- lib/block_repeater/repeater.rb
|
|
121
135
|
- lib/block_repeater/repeater_methods.rb
|
|
136
|
+
- lib/block_repeater/replay.rb
|
|
122
137
|
- lib/block_repeater/version.rb
|
|
123
138
|
homepage: https://github.com/dvla/block-repeater
|
|
124
139
|
licenses:
|