expect-pty 0.7.6 → 0.7.8
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/CHANGELOG.md +12 -0
- data/docs/API.md +1 -0
- data/lib/expect/interaction.rb +19 -21
- data/lib/expect/literal_prefix.rb +13 -2
- data/lib/expect/matcher.rb +30 -16
- data/lib/expect/redactor.rb +3 -1
- data/lib/expect/relay.rb +20 -14
- data/lib/expect/{session_resources.rb → resource_owner.rb} +6 -6
- data/lib/expect/session.rb +4 -4
- data/lib/expect/version.rb +1 -1
- data/lib/expect.rb +2 -2
- data/sig/expect.rbs +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad46afe78b754e37c5aa6995b9b1235d732a1f9faf372077b572e584ad186613
|
|
4
|
+
data.tar.gz: 7a3165503b1543396abde0d77713134296b7f2d818911c8bbca9e4b505d85227
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 78b96691fcf4e0ab916286bfec7a978c3bb1de6fdc082af0ac3e5408eba3f2119c06789fd867b6f3552460ef0acee1aa45302ebb4081c21943197bd124f714c5
|
|
7
|
+
data.tar.gz: 9c7f6b06eb593608b4474fac1b0a06464cda52965221e815fd921677af1d889cdbed29aefc801d9e08383685517df293a290dc97de92e724b473608b21165c94
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.7.8 - 2026-10-11
|
|
6
|
+
|
|
7
|
+
- 将内部资源所有权对象命名为 ResourceOwner,并统一源码、示例和测试辅助代码的中文注释。
|
|
8
|
+
- 补齐字节前缀算法、脱敏窗口及基准、API 校验和示例辅助方法的契约注释,明确缓存、输入和副作用边界。
|
|
9
|
+
|
|
10
|
+
## 0.7.7 - 2026-10-11
|
|
11
|
+
|
|
12
|
+
- 修复人工接管时终端模式交接中断、恢复异常覆盖业务主异常的问题;分别尝试恢复两侧输出、转义规则和终端模式。
|
|
13
|
+
- 修复 Matcher 与 Relay 在缓冲移交或归还期间被取消时丢失未消费输入的问题,仅在内部所有权交接期间延迟异步中断。
|
|
14
|
+
- 使用对象身份索引选择背压读取来源,减少多会话互为转发目标时的重复遍历,保持来源顺序和背压行为。
|
|
15
|
+
- SSH 示例保留 known_hosts 路径中的百分号,并在启动前拒绝 OpenSSH 会再次展开的 `${` 路径表达式。
|
|
16
|
+
|
|
5
17
|
## 0.7.6 - 2026-10-09
|
|
6
18
|
|
|
7
19
|
- 修复会话关闭时日志异常覆盖原始错误的问题,保留进程等待、线程中断或句柄关闭的失败原因,并继续尝试完成诊断与 transcript 收尾。
|
data/docs/API.md
CHANGED
|
@@ -114,6 +114,7 @@ DEBUG 关闭期间仍推进分片脱敏,但这些字节不会在重新启用
|
|
|
114
114
|
|
|
115
115
|
`interact(input: $stdin, escape: nil, output: nil, timeout: nil, raw: true)` 临时建立双向转接,退出后恢复
|
|
116
116
|
outputs、转义和本地终端模式。
|
|
117
|
+
各项恢复都会尝试;恢复中的常规错误不会覆盖已有的业务异常,没有业务异常时仍报告恢复错误。
|
|
117
118
|
`output: nil` 使用默认输出,`escape: nil` 不注册退出序列;显式 false 不是缺省值,非法输出或转义会在转发前报错。
|
|
118
119
|
`raw: false` 将终端设置留给调用方。transcript、logger 及自定义 writer 同步执行,应及时返回。
|
|
119
120
|
|
data/lib/expect/interaction.rb
CHANGED
|
@@ -64,20 +64,14 @@ module Expect
|
|
|
64
64
|
saved_self = outputs
|
|
65
65
|
saved_source = [source.outputs, source.sequences.dup]
|
|
66
66
|
terminal_state = prepare_interact_terminal(source) if raw
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if saved_self
|
|
76
|
-
self.outputs = saved_self
|
|
77
|
-
source.outputs, source.sequences = saved_source
|
|
78
|
-
end
|
|
79
|
-
ensure
|
|
80
|
-
restore_interact_terminal(terminal_state)
|
|
67
|
+
# 先持有恢复快照,再在同一清理作用域内切换终端;返回值交接中断不能留下 raw 模式。
|
|
68
|
+
Cleanup.always(-> { restore_interact(source, saved_self, saved_source, terminal_state) }) do
|
|
69
|
+
terminal_state&.first&.raw!
|
|
70
|
+
display = interact_display(source, output, terminal_state)
|
|
71
|
+
self.outputs = [display]
|
|
72
|
+
source.outputs = [self]
|
|
73
|
+
source.on_sequence(escape) unless escape.nil?
|
|
74
|
+
Relay.new([self, source], timeout).run
|
|
81
75
|
end
|
|
82
76
|
end
|
|
83
77
|
|
|
@@ -268,16 +262,20 @@ module Expect
|
|
|
268
262
|
@interact_inputs[input] ||= Expect.open(input)
|
|
269
263
|
end
|
|
270
264
|
|
|
271
|
-
#
|
|
265
|
+
# 只取得快照;实际 raw! 由持有快照的 interact 在清理作用域内执行。
|
|
272
266
|
def prepare_interact_terminal(source)
|
|
273
267
|
return unless source.tty?
|
|
274
268
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
269
|
+
io = source.to_io
|
|
270
|
+
[io, io.console_mode]
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# 独立尝试每项恢复;常规恢复错误不能覆盖业务主异常,新的中断仍按 Cleanup 契约传播。
|
|
274
|
+
def restore_interact(source, saved_self, saved_source, terminal_state)
|
|
275
|
+
Cleanup.always(-> { restore_interact_terminal(terminal_state) }) do
|
|
276
|
+
Cleanup.always(-> { source.sequences = saved_source.last }) do
|
|
277
|
+
Cleanup.always(-> { source.outputs = saved_source.first }) { self.outputs = saved_self }
|
|
278
|
+
end
|
|
281
279
|
end
|
|
282
280
|
end
|
|
283
281
|
|
|
@@ -2,14 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
module Expect
|
|
4
4
|
# 计算字节窗口尾部与规则真前缀重合的最长长度;转义暂存和流尾脱敏使用同一边界判断。
|
|
5
|
-
#
|
|
5
|
+
# 不持有输入或修改缓冲;仅长候选的扫描需要 KMP 回退表,冻结规则可跨调用缓存该表。
|
|
6
6
|
# @api private
|
|
7
7
|
module LiteralPrefix
|
|
8
|
+
# 返回 buffer 后缀与 pattern 真前缀重合的最大字节数;真前缀不包含完整 pattern。
|
|
9
|
+
# 例如 "xAB" 与 "ABC" 返回 2;空输入、长度不足 2 的规则或没有重合时返回 0。
|
|
10
|
+
# 两个字符串须由调用方转为二进制编码;此处不转码、不校验,也不修改它们。
|
|
11
|
+
# prefix_tables 为可选的可变 Hash;仅冻结 pattern 使用缓存,否则为本次调用建立临时表。
|
|
8
12
|
def self.length(buffer, pattern, prefix_tables = nil)
|
|
9
13
|
maximum = [pattern.bytesize - 1, buffer.bytesize].min
|
|
10
14
|
return 0 unless maximum.positive?
|
|
11
15
|
|
|
12
|
-
#
|
|
16
|
+
# 重合前缀的末字节必须等于输入尾字节;排除无法结束在该字节上的更长候选。
|
|
17
|
+
# 最长候选直接命中时不必构造回退表;小于 64 字节的候选改用有界枚举。
|
|
13
18
|
ending = pattern.rindex(buffer.byteslice(-1, 1), maximum - 1)
|
|
14
19
|
return 0 unless ending
|
|
15
20
|
|
|
@@ -19,6 +24,7 @@ module Expect
|
|
|
19
24
|
|
|
20
25
|
failure = prefix_tables && pattern.frozen? ? (prefix_tables[pattern] ||= []) : []
|
|
21
26
|
extend_failure_table(pattern, failure, maximum)
|
|
27
|
+
# 只扫描可能重合的尾部;不匹配时沿回退表保留已有重合,避免从每个候选起点重扫。
|
|
22
28
|
matched = 0
|
|
23
29
|
index = buffer.bytesize - maximum
|
|
24
30
|
while index < buffer.bytesize
|
|
@@ -30,6 +36,9 @@ module Expect
|
|
|
30
36
|
matched
|
|
31
37
|
end
|
|
32
38
|
|
|
39
|
+
# 将同一规则的可变回退表补齐到 length 项,已有项不重算,较长的缓存也不截断。
|
|
40
|
+
# failure[i] 是 pattern[0..i] 的最长真前缀与后缀重合长度,供失配时选择下一匹配状态。
|
|
41
|
+
# length 不超过规则的真前缀长度;表只能用于生成它的同一规则内容。
|
|
33
42
|
def self.extend_failure_table(pattern, failure, length)
|
|
34
43
|
failure << 0 if failure.empty?
|
|
35
44
|
matched = failure.last
|
|
@@ -49,6 +58,8 @@ module Expect
|
|
|
49
58
|
end
|
|
50
59
|
end
|
|
51
60
|
|
|
61
|
+
# 从 maximum 向下枚举短候选,返回首个后缀重合长度,无命中时返回 0。
|
|
62
|
+
# 调用方已限制候选规模;每次比较只切取规则前缀,不创建完整输入的副本或回退表。
|
|
52
63
|
def self.short_length(buffer, pattern, maximum)
|
|
53
64
|
maximum.downto(1) do |length|
|
|
54
65
|
return length if buffer.end_with?(pattern.byteslice(0, length))
|
data/lib/expect/matcher.rb
CHANGED
|
@@ -25,17 +25,7 @@ module Expect
|
|
|
25
25
|
# 运行匹配状态机;内部 :retry 表示继续循环,最终返回一个 Result。
|
|
26
26
|
def run
|
|
27
27
|
@relay_buffers = {}.compare_by_identity
|
|
28
|
-
|
|
29
|
-
buffer = session.interaction_buffer
|
|
30
|
-
if buffer
|
|
31
|
-
# 转义回调中的显式匹配临时接管读取,先消费转接已经预读的尾部。
|
|
32
|
-
@relay_buffers[session] = buffer
|
|
33
|
-
session.interaction_buffer = nil
|
|
34
|
-
session.restore_relay_buffer(buffer)
|
|
35
|
-
buffer.clear
|
|
36
|
-
end
|
|
37
|
-
session.reset_result
|
|
38
|
-
end
|
|
28
|
+
prepare_sessions
|
|
39
29
|
loop do
|
|
40
30
|
# 先消费已缓冲的匹配,再处理 EOF,最后读取;避免进程退出时丢失最后一个匹配。
|
|
41
31
|
result = if !@expired_eof_continuation && !hard_expired? && (matched = find_match)
|
|
@@ -50,15 +40,39 @@ module Expect
|
|
|
50
40
|
return result unless result == :retry
|
|
51
41
|
end
|
|
52
42
|
ensure
|
|
53
|
-
|
|
54
|
-
@relay_buffers.each do |session, buffer|
|
|
55
|
-
buffer.replace(session.take_buffer)
|
|
56
|
-
session.interaction_buffer = buffer
|
|
57
|
-
end
|
|
43
|
+
restore_relay_buffers
|
|
58
44
|
end
|
|
59
45
|
|
|
60
46
|
private
|
|
61
47
|
|
|
48
|
+
# 转义回调中的匹配临时接管预读尾部;缓冲登记和移交是一个不可拆开的状态变更。
|
|
49
|
+
# 仅内部所有权操作延迟异步取消,扫描、IO、日志及用户回调仍可立即中断。
|
|
50
|
+
def prepare_sessions
|
|
51
|
+
@sessions.each do |session|
|
|
52
|
+
if (buffer = session.interaction_buffer)
|
|
53
|
+
Thread.handle_interrupt(Object => :never) do
|
|
54
|
+
@relay_buffers[session] = buffer
|
|
55
|
+
session.interaction_buffer = nil
|
|
56
|
+
session.restore_relay_buffer(buffer)
|
|
57
|
+
buffer.clear
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
session.reset_result
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# 先归还所有借用来源再交付新的取消;返回尾部与恢复原缓冲对象不能被中断拆开。
|
|
65
|
+
def restore_relay_buffers
|
|
66
|
+
return if @relay_buffers.empty?
|
|
67
|
+
|
|
68
|
+
Thread.handle_interrupt(Object => :never) do
|
|
69
|
+
@relay_buffers.each do |session, buffer|
|
|
70
|
+
buffer.replace(session.take_buffer)
|
|
71
|
+
session.interaction_buffer = buffer
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
62
76
|
# 按声明组、会话、模式的顺序寻找首个匹配,不按文本中的出现位置重新排序。
|
|
63
77
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity -- 声明优先级与单轮缓冲须在同一次扫描保持一致。
|
|
64
78
|
def find_match
|
data/lib/expect/redactor.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Expect
|
|
|
13
13
|
filter.append(data) + filter.finish(partial: false)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
# pending 保存尚不能安全输出的原字节,hidden
|
|
16
|
+
# 复制冻结替换文本与规则;pending 保存尚不能安全输出的原字节,hidden 用 0/1 标记遮盖。
|
|
17
17
|
def initialize(patterns, replacement: "[FILTERED]")
|
|
18
18
|
unless replacement.is_a?(String) && !replacement.empty?
|
|
19
19
|
raise ArgumentError, "replacement must be a nonempty String"
|
|
@@ -67,6 +67,7 @@ module Expect
|
|
|
67
67
|
private
|
|
68
68
|
|
|
69
69
|
# 输出资格与秘密掩码分开保存;仅遇到被抑制的分片时才分配额外字节图。
|
|
70
|
+
# 三个字节窗口始终对齐;先标记完整命中,再释放最长规则长度减一之外的安全前缀。
|
|
70
71
|
def append_chunk(data, visible:)
|
|
71
72
|
raise ArgumentError, "data must be a String" unless data.is_a?(String)
|
|
72
73
|
|
|
@@ -147,6 +148,7 @@ module Expect
|
|
|
147
148
|
end
|
|
148
149
|
|
|
149
150
|
# 仅级别切换后的流需要按输出资格再分段,普通过滤不承担额外区间调用。
|
|
151
|
+
# 将指定掩码区间中可见的字节追加到 output;被抑制的明文会断开 masking,隐藏字节不会。
|
|
150
152
|
def release_suppressed(output, starting, ending, hidden:)
|
|
151
153
|
while starting < ending
|
|
152
154
|
suppressed = @suppressed.getbyte(starting) == 1
|
data/lib/expect/relay.rb
CHANGED
|
@@ -142,21 +142,27 @@ module Expect
|
|
|
142
142
|
|
|
143
143
|
@sessions.each { |session| session.relay_owner = @token }
|
|
144
144
|
end
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
@
|
|
148
|
-
|
|
145
|
+
# take_buffer 已移出会话后,必须先登记到本轮账本才能交付异步取消;此处不执行 IO 或用户回调。
|
|
146
|
+
Thread.handle_interrupt(Object => :never) do
|
|
147
|
+
@sessions.each do |session|
|
|
148
|
+
@previous[session] = session.interaction_buffer
|
|
149
|
+
@buffers[session] = session.take_buffer
|
|
150
|
+
session.interaction_buffer = @buffers.fetch(session)
|
|
151
|
+
end
|
|
149
152
|
end
|
|
150
153
|
end
|
|
151
154
|
|
|
152
155
|
# 未处理输入还给会话,已排队字节仍归游标;构造中断也只恢复已转移的缓冲及自己的标记。
|
|
153
156
|
def restore_sources
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
# 归还多来源缓冲和释放 token 属于同一交接,不能只恢复前几个来源就响应取消。
|
|
158
|
+
Thread.handle_interrupt(Object => :never) do
|
|
159
|
+
@previous.each { |session, buffer| session.interaction_buffer = buffer }
|
|
160
|
+
@buffers.each { |session, buffer| session.restore_relay_buffer(buffer) }
|
|
161
|
+
ensure
|
|
162
|
+
OWNERSHIP_MUTEX.synchronize do
|
|
163
|
+
@sessions.each do |session|
|
|
164
|
+
session.relay_owner = nil if session.relay_owner.equal?(@token)
|
|
165
|
+
end
|
|
160
166
|
end
|
|
161
167
|
end
|
|
162
168
|
end
|
|
@@ -184,13 +190,13 @@ module Expect
|
|
|
184
190
|
# 背压源暂停吸收新输入,限制排队增长;作为写入目标的会话仍需读取以解除双向等待。
|
|
185
191
|
def read_sources(pending)
|
|
186
192
|
# 输出目标可能也在等待我们读取;这些来源即使有待发送数据也必须继续排空。
|
|
187
|
-
targets = pending.
|
|
188
|
-
output.target if output.target.is_a?(Session)
|
|
193
|
+
targets = pending.each_with_object({}.compare_by_identity) do |output, index|
|
|
194
|
+
index[output.target] = true if output.target.is_a?(Session)
|
|
189
195
|
end
|
|
190
196
|
sources = @active.reject do |session|
|
|
191
|
-
session.pending_output? && targets.
|
|
197
|
+
session.pending_output? && !targets.key?(session)
|
|
192
198
|
end
|
|
193
|
-
(sources + targets).uniq { |session| session.to_io.object_id }.reject(&:eof?)
|
|
199
|
+
(sources + targets.keys).uniq { |session| session.to_io.object_id }.reject(&:eof?)
|
|
194
200
|
end
|
|
195
201
|
|
|
196
202
|
# 总期限结束时将可交付尾部转为发送游标,至多尝试一轮交付;余量由源会话保存。
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Expect
|
|
4
|
-
#
|
|
5
|
-
#
|
|
4
|
+
# 管理 IO 关闭责任和直属子进程归属,供显式关闭与 GC 回收共用。
|
|
5
|
+
# 不直接引用 Session、日志目标或用户回调;句柄关闭与进程退出分别记录。
|
|
6
6
|
# @api private
|
|
7
|
-
class
|
|
8
|
-
#
|
|
7
|
+
class ResourceOwner
|
|
8
|
+
# 缓存已取得的 Process::Status;被外部回收的进程仍保留未知状态,不伪造成功。
|
|
9
9
|
attr_accessor :status
|
|
10
10
|
# own 控制句柄关闭责任,owner 控制进程回收责任;fork 后两者不能混为一谈。
|
|
11
11
|
attr_reader :pid, :reader, :writer, :slave, :owner, :own
|
|
@@ -60,7 +60,7 @@ module Expect
|
|
|
60
60
|
status
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
# GC
|
|
63
|
+
# GC 兜底关闭所属句柄并终止尚存活的子进程;不调用会话日志或转义回调,也不进行软关闭等待。
|
|
64
64
|
# 可直接用绑定到资源对象的 Method 注册终结器,忽略 Ruby 传来的被回收对象 ID。
|
|
65
65
|
def finalize(_object_id = nil)
|
|
66
66
|
return unless owner == Process.pid
|
|
@@ -77,7 +77,7 @@ module Expect
|
|
|
77
77
|
|
|
78
78
|
private
|
|
79
79
|
|
|
80
|
-
# GC 只做一次非阻塞回收和最多两次信号尝试;失败也把等待交给 detach
|
|
80
|
+
# GC 只做一次非阻塞回收和最多两次信号尝试;失败也把等待交给 detach,不调用会话日志或转义回调。
|
|
81
81
|
def finalize_child
|
|
82
82
|
begin
|
|
83
83
|
reap
|
data/lib/expect/session.rb
CHANGED
|
@@ -5,7 +5,7 @@ require_relative "interaction"
|
|
|
5
5
|
|
|
6
6
|
module Expect
|
|
7
7
|
# 一个真实 PTY 或 IO 会话;缓冲、最近结果和所属进程都保存在本对象中。
|
|
8
|
-
#
|
|
8
|
+
# ResourceOwner 保存可独立回收的资源账本;Matcher、Relay 仅在操作期间借用会话状态。
|
|
9
9
|
# 日志与协议目标属于调用方,显式关闭和 GC 均不得接管这些借用对象。
|
|
10
10
|
class Session
|
|
11
11
|
include Logging
|
|
@@ -58,7 +58,7 @@ module Expect
|
|
|
58
58
|
|
|
59
59
|
@slave.raw! if raw
|
|
60
60
|
from_child = to_parent = nil
|
|
61
|
-
Cleanup.always(-> {
|
|
61
|
+
Cleanup.always(-> { ResourceOwner.close_handles(from_child, to_parent) }) do
|
|
62
62
|
# 错误管道的写端在 exec 成功时自动关闭;父进程据此区分成功启动与 exec 前失败。
|
|
63
63
|
# 管道返回到多重赋值之间也属于接管区间,确保 ensure 始终能找到两个端点。
|
|
64
64
|
Thread.handle_interrupt(Object => :never) { from_child, to_parent = IO.pipe }
|
|
@@ -290,7 +290,7 @@ module Expect
|
|
|
290
290
|
if @resources
|
|
291
291
|
close(graceful:)
|
|
292
292
|
elsif own
|
|
293
|
-
|
|
293
|
+
ResourceOwner.close_handles(reader, writer, slave)
|
|
294
294
|
end
|
|
295
295
|
end
|
|
296
296
|
|
|
@@ -386,7 +386,7 @@ module Expect
|
|
|
386
386
|
# 初始化前先登记所有权;参数校验失败也能释放已取得的端点。
|
|
387
387
|
def initialize_io(reader, writer:, slave: nil, own: false, timeout: nil, write_timeout: nil,
|
|
388
388
|
buffer_limit: nil, logger: nil, transcript: nil, outputs: [])
|
|
389
|
-
@resources =
|
|
389
|
+
@resources = ResourceOwner.new(reader, writer:, slave:, own:)
|
|
390
390
|
raise ArgumentError, "reader must be a real IO" unless reader.is_a?(IO) && !reader.closed?
|
|
391
391
|
raise ArgumentError, "writer must be a real IO" unless writer.is_a?(IO) && !writer.closed?
|
|
392
392
|
|
data/lib/expect/version.rb
CHANGED
data/lib/expect.rb
CHANGED
|
@@ -5,7 +5,7 @@ require "io/console"
|
|
|
5
5
|
require "stringio"
|
|
6
6
|
require_relative "expect/version"
|
|
7
7
|
require_relative "expect/result"
|
|
8
|
-
require_relative "expect/
|
|
8
|
+
require_relative "expect/resource_owner"
|
|
9
9
|
require_relative "expect/pattern"
|
|
10
10
|
require_relative "expect/pattern_list"
|
|
11
11
|
require_relative "expect/matcher"
|
|
@@ -72,7 +72,7 @@ module Expect
|
|
|
72
72
|
if session && (block_given? || !initialized)
|
|
73
73
|
session.cleanup_session(io, writer:, own:, graceful: initialized && graceful)
|
|
74
74
|
elsif !session && own
|
|
75
|
-
|
|
75
|
+
ResourceOwner.close_handles(io, writer)
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
78
|
Cleanup.always(cleanup) do
|
data/sig/expect.rbs
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: expect-pty
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- expect-pty contributors
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-11 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: io-console
|
|
@@ -76,9 +76,9 @@ files:
|
|
|
76
76
|
- lib/expect/redactor.rb
|
|
77
77
|
- lib/expect/relay.rb
|
|
78
78
|
- lib/expect/relay_writer.rb
|
|
79
|
+
- lib/expect/resource_owner.rb
|
|
79
80
|
- lib/expect/result.rb
|
|
80
81
|
- lib/expect/session.rb
|
|
81
|
-
- lib/expect/session_resources.rb
|
|
82
82
|
- lib/expect/version.rb
|
|
83
83
|
- sig/expect.rbs
|
|
84
84
|
homepage: https://github.com/gatework/expect-ruby
|