Class: Expect::Matcher

Inherits:
Object
  • Object
show all
Defined in:
lib/expect/matcher.rb

Overview

驱动一次单会话或多会话匹配,管理模式优先级、EOF 和共享期限,不接管 IO 所有权。 调度只在扫描、回调和 IO 操作之间检查期限,不强行中断用户代码或单次正则计算。

Instance Method Summary collapse

Constructor Details

#initialize(patterns, timeout, deadline: nil) ⇒ Matcher

固定本次参与的会话及初始期限;已处理 EOF 的会话仅从本次等待中移除。



8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/expect/matcher.rb', line 8

def initialize(patterns, timeout, deadline: nil)
  @patterns = patterns
  @sessions = patterns.sessions
  @timeout = Expect.duration(timeout)
  # 相对期限可因接收或 continue 重算,总期限始终固定;两者共用单调时钟。
  @hard_deadline = deadline
  @deadline = next_deadline
  @handled_eof = []
  @stalled_matches = {}
  @polled = false
  @expired_eof_continuation = false
end

Instance Method Details

#run ⇒ Object

运行匹配状态机;内部 :retry 表示继续循环,最终返回一个 Result。



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/expect/matcher.rb', line 22

def run
  @relay_buffers = {}
  @sessions.each do |session|
    buffer = session.__send__(:interaction_buffer)
    if buffer
      # 转义回调中的显式匹配临时接管读取,先消费转接已经预读的尾部。
      @relay_buffers[session] = buffer
      session.__send__(:interaction_buffer=, nil)
      session.__send__(:restore_relay_buffer, buffer)
      buffer.clear
    end
    session.__send__(:reset_result)
  end
  loop do
    # 先消费已缓冲的匹配,再处理 EOF,最后读取;避免进程退出时丢失最后一个匹配。
    result = if !@expired_eof_continuation && !hard_expired? && (matched = find_match)
               handle_match(*matched)
             elsif (session = unhandled_eof)
               handle_eof(session)
             elsif @expired_eof_continuation || hard_expired?
               handle_timeout
             else
               read_next
             end
    return result unless result == :retry
  end
ensure
  # 嵌套 expect 即使异常退出,也要把未消费尾部还给原 Relay 的同一个缓冲对象。
  @relay_buffers.each do |session, buffer|
    buffer.replace(session.clear_buffer)
    session.__send__(:interaction_buffer=, buffer)
  end
end