ttytest2 0.9.8 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,157 +1,171 @@
1
- # frozen_string_literal: true
2
-
3
- module TTYtest
4
- # Assertions for ttytest2.
5
- module Matchers
6
- # Asserts the contents of a single row match the value expected
7
- # @param [Integer] row_number the row (starting from 0) to test against
8
- # @param [String] expected the expected value of the row. Any trailing whitespace is ignored
9
- # @raise [MatchError] if the row doesn't match exactly
10
- def assert_row(row_number, expected)
11
- expected = expected.rstrip
12
- actual = row(row_number)
13
- return if actual == expected
14
-
15
- raise MatchError,
16
- "expected row #{row_number} to be #{expected.inspect} but got #{actual.inspect}\nEntire screen:\n#{self}"
17
- end
18
-
19
- # Asserts the contents of a single row contains the expected string at a specific position
20
- # @param [Integer] row_number the row (starting from 0) to test against
21
- # @param [Integer] column_start the column position to start comparing expected against
22
- # @param [Integer] columns_end the column position to end comparing expected against
23
- # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
24
- # @raise [MatchError] if the row doesn't match
25
- def assert_row_at(row_number, column_start, column_end, expected)
26
- expected = expected.rstrip
27
- actual = row(row_number)
28
- column_end += 1
29
- return if actual[column_start, column_end].eql?(expected)
30
-
31
- raise MatchError,
32
- "expected row #{row_number} to contain #{expected[column_start,
33
- column_end]} at #{column_start}-#{column_end} and got #{actual[column_start,
34
- column_end]}\nEntire screen:\n#{self}"
35
- end
36
-
37
- # Asserts the contents of a single row contains the value expected
38
- # @param [Integer] row_number the row (starting from 0) to test against
39
- # @param [String] expected the expected value contained in the row. Any trailing whitespace is ignored
40
- # @raise [MatchError] if the row doesn't match
41
- def assert_row_like(row_number, expected)
42
- expected = expected.rstrip
43
- actual = row(row_number)
44
- return if actual.include?(expected)
45
-
46
- raise MatchError,
47
- "expected row #{row_number} to be like #{expected.inspect} but got #{actual.inspect}\nEntire screen:\n#{self}"
48
- end
49
-
50
- # Asserts the contents of a single row starts with expected string
51
- # @param [Integer] row_number the row (starting from 0) to test against
52
- # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
53
- # @raise [MatchError] if the row doesn't match
54
- def assert_row_starts_with(row_number, expected)
55
- expected = expected.rstrip
56
- actual = row(row_number)
57
- return if actual.start_with?(expected)
58
-
59
- raise MatchError,
60
- "expected row #{row_number} to start with #{expected.inspect} and got #{actual.inspect}\nEntire screen:\n#{self}"
61
- end
62
-
63
- # Asserts the contents of a single row end with expected
64
- # @param [Integer] row_number the row (starting from 0) to test against
65
- # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
66
- # @raise [MatchError] if the row doesn't match
67
- def assert_row_ends_with(row_number, expected)
68
- expected = expected.rstrip
69
- actual = row(row_number)
70
- return if actual.end_with?(expected)
71
-
72
- raise MatchError,
73
- "expected row #{row_number} to end with #{expected.inspect} and got #{actual.inspect}\nEntire screen:\n#{self}"
74
- end
75
-
76
- # Asserts that the cursor is in the expected position
77
- # @param [Integer] x cursor x (row) position, starting from 0
78
- # @param [Integer] y cursor y (column) position, starting from 0
79
- # @raise [MatchError] if the cursor position doesn't match
80
- def assert_cursor_position(x, y)
81
- expected = [x, y]
82
- actual = [cursor_x, cursor_y]
83
- return if actual == expected
84
-
85
- raise MatchError,
86
- "expected cursor to be at #{expected.inspect} but was at #{actual.inspect}\nEntire screen:\n#{self}"
87
- end
88
-
89
- # @raise [MatchError] if the cursor is hidden
90
- def assert_cursor_visible
91
- return if cursor_visible?
92
-
93
- raise MatchError, "expected cursor to be visible was hidden\nEntire screen:\n#{self}"
94
- end
95
-
96
- # @raise [MatchError] if the cursor is visible
97
- def assert_cursor_hidden
98
- return if cursor_hidden?
99
-
100
- raise MatchError, "expected cursor to be hidden was visible\nEntire screen:\n#{self}"
101
- end
102
-
103
- # Asserts the full contents of the terminal
104
- # @param [String] expected the full expected contents of the terminal. Trailing whitespace on each line is ignored
105
- # @raise [MatchError] if the terminal doesn't match the expected content
106
- def assert_contents(expected)
107
- expected_rows = expected.split("\n")
108
- diff = []
109
- matched = true
110
- rows.each_with_index do |actual_row, index|
111
- expected_row = (expected_rows[index] || '').rstrip
112
- if actual_row != expected_row
113
- diff << "-#{expected_row}"
114
- diff << "+#{actual_row}"
115
- matched = false
116
- else
117
- diff << " #{actual_row}".rstrip
118
- end
119
- end
120
-
121
- return if matched
122
-
123
- raise MatchError,
124
- "screen did not match expected content:\n--- expected\n+++ actual\n#{diff.join("\n")}"
125
- end
126
- alias assert_matches assert_contents
127
-
128
- # Asserts the contents of the terminal at specified rows
129
- # @param [String] expected the expected contents of the terminal at specified rows. Trailing whitespace on each line is ignored
130
- # @raise [MatchError] if the terminal doesn't match the expected content
131
- def assert_contents_at(row_start, row_end, expected)
132
- expected_rows = expected.split("\n")
133
- diff = []
134
- matched = true
135
- row_end += 1 if row_end.zero?
136
-
137
- rows.slice(row_start, row_end).each_with_index do |actual_row, index|
138
- expected_row = (expected_rows[index] || '').rstrip
139
- if actual_row != expected_row
140
- diff << "-#{expected_row}"
141
- diff << "+#{actual_row}"
142
- matched = false
143
- else
144
- diff << " #{actual_row}".rstrip
145
- end
146
- end
147
-
148
- return if matched
149
-
150
- raise MatchError,
151
- "screen did not match expected content:\n--- expected\n+++ actual\n#{diff.join("\n")}"
152
- end
153
- alias assert_matches_at assert_contents_at
154
-
155
- METHODS = public_instance_methods
156
- end
157
- end
1
+ # frozen_string_literal: true
2
+
3
+ module TTYtest
4
+ # Assertions for ttytest2.
5
+ module Matchers
6
+ # Asserts the contents of a single row match the value expected
7
+ # @param [Integer] row_number the row (starting from 0) to test against
8
+ # @param [String] expected the expected value of the row. Any trailing whitespace is ignored
9
+ # @raise [MatchError] if the row doesn't match exactly
10
+ def assert_row(row_number, expected)
11
+ expected = expected.rstrip
12
+ actual = row(row_number)
13
+ return if actual == expected
14
+
15
+ raise MatchError,
16
+ "expected row #{row_number} to be #{expected.inspect} but got #{actual.inspect}\nEntire screen:\n#{self}"
17
+ end
18
+
19
+ # Asserts the contents of a single row contains the expected string at a specific position
20
+ # @param [Integer] row_number the row (starting from 0) to test against
21
+ # @param [Integer] column_start the column position to start comparing expected against
22
+ # @param [Integer] columns_end the column position to end comparing expected against
23
+ # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
24
+ # @raise [MatchError] if the row doesn't match
25
+ def assert_row_at(row_number, column_start, column_end, expected)
26
+ expected = expected.rstrip
27
+ actual = row(row_number)
28
+ column_end += 1
29
+ return if actual[column_start, column_end].eql?(expected)
30
+
31
+ raise MatchError,
32
+ "expected row #{row_number} to contain #{expected[column_start,
33
+ column_end]} at #{column_start}-#{column_end} and got #{actual[column_start,
34
+ column_end]}\nEntire screen:\n#{self}"
35
+ end
36
+
37
+ # Asserts the contents of a single row contains the value expected
38
+ # @param [Integer] row_number the row (starting from 0) to test against
39
+ # @param [String] expected the expected value contained in the row. Any trailing whitespace is ignored
40
+ # @raise [MatchError] if the row doesn't match
41
+ def assert_row_like(row_number, expected)
42
+ expected = expected.rstrip
43
+ actual = row(row_number)
44
+ return if actual.include?(expected)
45
+
46
+ raise MatchError,
47
+ "expected row #{row_number} to be like #{expected.inspect} but got #{actual.inspect}\nEntire screen:\n#{self}"
48
+ end
49
+
50
+ # Asserts the contents of a single row starts with expected string
51
+ # @param [Integer] row_number the row (starting from 0) to test against
52
+ # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
53
+ # @raise [MatchError] if the row doesn't match
54
+ def assert_row_starts_with(row_number, expected)
55
+ expected = expected.rstrip
56
+ actual = row(row_number)
57
+ return if actual.start_with?(expected)
58
+
59
+ raise MatchError,
60
+ "expected row #{row_number} to start with #{expected.inspect} and got #{actual.inspect}\nEntire screen:\n#{self}"
61
+ end
62
+
63
+ # Asserts the contents of a single row end with expected
64
+ # @param [Integer] row_number the row (starting from 0) to test against
65
+ # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
66
+ # @raise [MatchError] if the row doesn't match
67
+ def assert_row_ends_with(row_number, expected)
68
+ expected = expected.rstrip
69
+ actual = row(row_number)
70
+ return if actual.end_with?(expected)
71
+
72
+ raise MatchError,
73
+ "expected row #{row_number} to end with #{expected.inspect} and got #{actual.inspect}\nEntire screen:\n#{self}"
74
+ end
75
+
76
+ # Asserts the contents of a single row match against the passed in regular expression
77
+ # @param [Integer] row_number the row (starting from 0) to test against
78
+ # @param [String] regexp_str the regular expression as a string that will be used to match with.
79
+ # @raise [MatchError] if the row doesn't match against the regular expression
80
+ def assert_row_regexp(row_number, regexp_str)
81
+ regexp = Regexp.new(regexp_str)
82
+ actual = row(row_number)
83
+
84
+ return if actual.match?(regexp)
85
+
86
+ raise MatchError,
87
+ "expected row #{row_number} to match regexp #{regexp_str} but it did not. Row value #{actual.inspect}\nEntire screen:\n#{self}"
88
+ end
89
+
90
+ # Asserts that the cursor is in the expected position
91
+ # @param [Integer] x cursor x (row) position, starting from 0
92
+ # @param [Integer] y cursor y (column) position, starting from 0
93
+ # @raise [MatchError] if the cursor position doesn't match
94
+ def assert_cursor_position(x, y)
95
+ expected = [x, y]
96
+ actual = [cursor_x, cursor_y]
97
+ return if actual == expected
98
+
99
+ raise MatchError,
100
+ "expected cursor to be at #{expected.inspect} but was at #{actual.inspect}\nEntire screen:\n#{self}"
101
+ end
102
+
103
+ # @raise [MatchError] if the cursor is hidden
104
+ def assert_cursor_visible
105
+ return if cursor_visible?
106
+
107
+ raise MatchError, "expected cursor to be visible was hidden\nEntire screen:\n#{self}"
108
+ end
109
+
110
+ # @raise [MatchError] if the cursor is visible
111
+ def assert_cursor_hidden
112
+ return if cursor_hidden?
113
+
114
+ raise MatchError, "expected cursor to be hidden was visible\nEntire screen:\n#{self}"
115
+ end
116
+
117
+ # Asserts the full contents of the terminal
118
+ # @param [String] expected the full expected contents of the terminal. Trailing whitespace on each line is ignored
119
+ # @raise [MatchError] if the terminal doesn't match the expected content
120
+ def assert_contents(expected)
121
+ expected_rows = expected.split("\n")
122
+ diff = []
123
+ matched = true
124
+ rows.each_with_index do |actual_row, index|
125
+ expected_row = (expected_rows[index] || '').rstrip
126
+ if actual_row != expected_row
127
+ diff << "-#{expected_row}"
128
+ diff << "+#{actual_row}"
129
+ matched = false
130
+ else
131
+ diff << " #{actual_row}".rstrip
132
+ end
133
+ end
134
+
135
+ return if matched
136
+
137
+ raise MatchError,
138
+ "screen did not match expected content:\n--- expected\n+++ actual\n#{diff.join("\n")}"
139
+ end
140
+ alias assert_matches assert_contents
141
+
142
+ # Asserts the contents of the terminal at specified rows
143
+ # @param [String] expected the expected contents of the terminal at specified rows. Trailing whitespace on each line is ignored
144
+ # @raise [MatchError] if the terminal doesn't match the expected content
145
+ def assert_contents_at(row_start, row_end, expected)
146
+ expected_rows = expected.split("\n")
147
+ diff = []
148
+ matched = true
149
+ row_end += 1 if row_end.zero?
150
+
151
+ rows.slice(row_start, row_end).each_with_index do |actual_row, index|
152
+ expected_row = (expected_rows[index] || '').rstrip
153
+ if actual_row != expected_row
154
+ diff << "-#{expected_row}"
155
+ diff << "+#{actual_row}"
156
+ matched = false
157
+ else
158
+ diff << " #{actual_row}".rstrip
159
+ end
160
+ end
161
+
162
+ return if matched
163
+
164
+ raise MatchError,
165
+ "screen did not match expected content:\n--- expected\n+++ actual\n#{diff.join("\n")}"
166
+ end
167
+ alias assert_matches_at assert_contents_at
168
+
169
+ METHODS = public_instance_methods
170
+ end
171
+ end
@@ -1,139 +1,141 @@
1
- # frozen_string_literal: true
2
-
3
- require 'forwardable'
4
- require 'ttytest/matchers'
5
- require 'ttytest/capture'
6
-
7
- module TTYtest
8
- # @attr [Integer] max_wait_time the maximum amount of time (in seconds) to retry assertions before failing.
9
- class Terminal
10
- extend Forwardable
11
-
12
- attr_accessor :max_wait_time
13
-
14
- # @api private
15
- # @see TTYtest.new_terminal
16
- def initialize(driver_terminal, max_wait_time: nil)
17
- @driver_terminal = driver_terminal
18
- @max_wait_time = max_wait_time || TTYtest.default_max_wait_time
19
- end
20
-
21
- # @!method send_keys(*keys)
22
- # Simulate typing keys into the terminal. For canonical cli's/shells which read line by line.
23
- # @param [String] keys keys to send to the terminal
24
- # @!method send_keys_one_at_a_time(keys)
25
- # Simulate typing keys into the terminal. For noncanonical cli's/shells which read character by character.
26
- # @param [String] keys keys to send to the terminal
27
- # @!method send_newline
28
- # Simulate typing enter by sending newline character to the terminal.
29
- # @!method send_newlines
30
- # Simulates sending newline the specified number of times.
31
- # @param [Integer] number of times to send newline
32
- # @!method send_delete
33
- # Simulate typing the delete key in the terminal.
34
- # @!method send_deletes
35
- # Simulates typing delete the specified number of times.
36
- # @param [Integer] number of times to send delete
37
- # @!method send_backspace
38
- # Simulate typing the backspace key in the terminal.
39
- # @!method send_backspaces
40
- # Simulates typing backspace the specified number of times.
41
- # @param [Integer] number of times to send backspace
42
- # @!method send_left_arrow
43
- # Simulate typing the left arrow key in the terminal.
44
- # @!method send_left_arrows
45
- # Simulates typing left arrow the specified number of times.
46
- # @param [Integer] number of times to send left arrow
47
- # @!method send_right_arrow
48
- # Simulate typing the right arrow key in the terminal.
49
- # @!method send_right_arrows
50
- # Simulates typing right arrow the specified number of times.
51
- # @param [Integer] number of times to send right arrow
52
- # @!method send_down_arrow
53
- # Simulate typing the down arrow key in the terminal.
54
- # @!method send_down_arrows
55
- # Simulates typing the down arrow the specified number of times.
56
- # @param [Integer] number of times to send down arrow
57
- # @!method send_up_arrow
58
- # Simulate typing the up arrow key in the terminal.
59
- # @!method send_up_arrows
60
- # Simulates typing the up arrow the specified number of times.
61
- # @param [Integer] number of times to send up arrow
62
- # @!method send_keys_exact
63
- # Send tmux send-keys command to the terminal, such as DC or Enter, to simulate pressing that key in the terminal.
64
- # @!method send_home
65
- # Simulates typing in the Home key in the terminal.
66
- # @!method send_end
67
- # Simulates typing in the End key in the terminal.
68
- # @!method send_clear
69
- # Clears the screen in the terminal using ascii clear command.
70
- # @!method capture
71
- # Capture the current state of the terminal
72
- # @return [Capture] instantaneous state of the terminal when called
73
- def_delegators :@driver_terminal,
74
- :send_keys, :send_keys_one_at_a_time,
75
- :send_newline, :send_newlines,
76
- :send_delete, :send_deletes,
77
- :send_backspace, :send_backspaces,
78
- :send_left_arrow, :send_left_arrows, :send_right_arrow, :send_right_arrows,
79
- :send_down_arrow, :send_down_arrows, :send_up_arrow, :send_up_arrows,
80
- :send_keys_exact, :send_home, :send_end, :send_clear,
81
- :capture
82
-
83
- # @!method print
84
- # Prints the current state of the terminal to stdout. See capture to get the raw string.
85
- # @!method print_rows
86
- # Prints the current state of the terminal as an array to stdout. See rows to get the raw array.
87
- # @!method rows
88
- # @return [Array<String>]
89
- # @see Capture#rows
90
- # @!method row(row)
91
- # @return [String]
92
- # @see Capture#row
93
- # @!method width
94
- # @see Capture#width
95
- # @return [Integer]
96
- # @!method height
97
- # @see Capture#height
98
- # @return [Integer]
99
- # @!method cursor_x
100
- # @see Capture#cursor_x
101
- # @return [Integer]
102
- # @!method cursor_y
103
- # @see Capture#cursor_y
104
- # @return [Integer]
105
- # @!method cursor_visible?
106
- # @see Capture#cursor_visible?
107
- # @return [true,false]
108
- # @!method cursor_hidden?
109
- # @see Capture#cursor_hidden?
110
- # @return [true,false]
111
- def_delegators :capture, :print, :print_rows,
112
- :rows, :row,
113
- :width, :height,
114
- :cursor_x, :cursor_y,
115
- :cursor_visible?, :cursor_hidden?
116
-
117
- TTYtest::Matchers::METHODS.each do |matcher_name|
118
- define_method matcher_name do |*args|
119
- synchronize do
120
- capture.public_send(matcher_name, *args)
121
- end
122
- end
123
- end
124
-
125
- private
126
-
127
- def synchronize(seconds = max_wait_time)
128
- start_time = Time.now
129
- begin
130
- yield
131
- rescue MatchError => e
132
- raise e if (Time.now - start_time) >= seconds
133
-
134
- sleep 0.05
135
- retry
136
- end
137
- end
138
- end
139
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'ttytest/matchers'
5
+ require 'ttytest/capture'
6
+
7
+ module TTYtest
8
+ # @attr [Integer] max_wait_time the maximum amount of time (in seconds) to retry assertions before failing.
9
+ class Terminal
10
+ extend Forwardable
11
+
12
+ attr_accessor :max_wait_time
13
+
14
+ # @api private
15
+ # @see TTYtest.new_terminal
16
+ def initialize(driver_terminal, max_wait_time: nil)
17
+ @driver_terminal = driver_terminal
18
+ @max_wait_time = max_wait_time || TTYtest.default_max_wait_time
19
+ end
20
+
21
+ # @!method send_keys(*keys)
22
+ # Simulate typing keys into the terminal. For canonical cli's/shells which read line by line.
23
+ # @param [String] keys keys to send to the terminal
24
+ # @!method send_keys_one_at_a_time(keys)
25
+ # Simulate typing keys into the terminal. For noncanonical cli's/shells which read character by character.
26
+ # @param [String] keys keys to send to the terminal
27
+ # @!method send_newline
28
+ # Simulate typing enter by sending newline character to the terminal.
29
+ # @!method send_newlines
30
+ # Simulates sending newline the specified number of times.
31
+ # @param [Integer] number of times to send newline
32
+ # @!method send_delete
33
+ # Simulate typing the delete key in the terminal.
34
+ # @!method send_deletes
35
+ # Simulates typing delete the specified number of times.
36
+ # @param [Integer] number of times to send delete
37
+ # @!method send_backspace
38
+ # Simulate typing the backspace key in the terminal.
39
+ # @!method send_backspaces
40
+ # Simulates typing backspace the specified number of times.
41
+ # @param [Integer] number of times to send backspace
42
+ # @!method send_left_arrow
43
+ # Simulate typing the left arrow key in the terminal.
44
+ # @!method send_left_arrows
45
+ # Simulates typing left arrow the specified number of times.
46
+ # @param [Integer] number of times to send left arrow
47
+ # @!method send_right_arrow
48
+ # Simulate typing the right arrow key in the terminal.
49
+ # @!method send_right_arrows
50
+ # Simulates typing right arrow the specified number of times.
51
+ # @param [Integer] number of times to send right arrow
52
+ # @!method send_down_arrow
53
+ # Simulate typing the down arrow key in the terminal.
54
+ # @!method send_down_arrows
55
+ # Simulates typing the down arrow the specified number of times.
56
+ # @param [Integer] number of times to send down arrow
57
+ # @!method send_up_arrow
58
+ # Simulate typing the up arrow key in the terminal.
59
+ # @!method send_up_arrows
60
+ # Simulates typing the up arrow the specified number of times.
61
+ # @param [Integer] number of times to send up arrow
62
+ # @!method send_keys_exact
63
+ # Send tmux send-keys command to the terminal, such as DC or Enter, to simulate pressing that key in the terminal.
64
+ # @!method send_home
65
+ # Simulates typing in the Home key in the terminal.
66
+ # @!method send_end
67
+ # Simulates typing in the End key in the terminal.
68
+ # @!method send_clear
69
+ # Clears the screen in the terminal using ascii clear command.
70
+ # @!method send_escape
71
+ # Simulates typing in the Escape (ESC) key in the terminal.
72
+ # @!method capture
73
+ # Capture the current state of the terminal
74
+ # @return [Capture] instantaneous state of the terminal when called
75
+ def_delegators :@driver_terminal,
76
+ :send_keys, :send_keys_one_at_a_time,
77
+ :send_newline, :send_newlines,
78
+ :send_delete, :send_deletes,
79
+ :send_backspace, :send_backspaces,
80
+ :send_left_arrow, :send_left_arrows, :send_right_arrow, :send_right_arrows,
81
+ :send_down_arrow, :send_down_arrows, :send_up_arrow, :send_up_arrows,
82
+ :send_keys_exact, :send_home, :send_end, :send_clear, :send_escape,
83
+ :capture
84
+
85
+ # @!method print
86
+ # Prints the current state of the terminal to stdout. See capture to get the raw string.
87
+ # @!method print_rows
88
+ # Prints the current state of the terminal as an array to stdout. See rows to get the raw array.
89
+ # @!method rows
90
+ # @return [Array<String>]
91
+ # @see Capture#rows
92
+ # @!method row(row)
93
+ # @return [String]
94
+ # @see Capture#row
95
+ # @!method width
96
+ # @see Capture#width
97
+ # @return [Integer]
98
+ # @!method height
99
+ # @see Capture#height
100
+ # @return [Integer]
101
+ # @!method cursor_x
102
+ # @see Capture#cursor_x
103
+ # @return [Integer]
104
+ # @!method cursor_y
105
+ # @see Capture#cursor_y
106
+ # @return [Integer]
107
+ # @!method cursor_visible?
108
+ # @see Capture#cursor_visible?
109
+ # @return [true,false]
110
+ # @!method cursor_hidden?
111
+ # @see Capture#cursor_hidden?
112
+ # @return [true,false]
113
+ def_delegators :capture, :print, :print_rows,
114
+ :rows, :row,
115
+ :width, :height,
116
+ :cursor_x, :cursor_y,
117
+ :cursor_visible?, :cursor_hidden?
118
+
119
+ Matchers::METHODS.each do |matcher_name|
120
+ define_method matcher_name do |*args|
121
+ synchronize do
122
+ capture.public_send(matcher_name, *args)
123
+ end
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ def synchronize(seconds = max_wait_time)
130
+ start_time = Time.now
131
+ begin
132
+ yield
133
+ rescue MatchError => e
134
+ raise e if (Time.now - start_time) >= seconds
135
+
136
+ sleep 0.05
137
+ retry
138
+ end
139
+ end
140
+ end
141
+ end