Class: ScripTTY::Expect
- Inherits:
-
Object
- Object
- ScripTTY::Expect
- Defined in:
- lib/scriptty/expect.rb
Defined Under Namespace
Classes: Evaluator, Match, PatternHandle
Constant Summary collapse
- EXPORTED_METHODS =
Methods to export to Evaluator
Set.new [:init_term, :term, :connect, :screen, :expect, :on, :wait, :send, :send_password, :capture, :match, :push_patterns, :pop_patterns, :exit, :eval_script_file, :eval_script_inline, :sleep, :set_timeout, :load_screens, :print, :puts, :p, :pp ]
Instance Attribute Summary collapse
-
#capture ⇒ Object
(also: #match)
readonly
The last non-background captured fields.
-
#term ⇒ Object
readonly
The terminal emulation object.
-
#transcript_writer ⇒ Object
Set this to an instance of ScripTTY::Util::Transcript::Writer.
-
#transcript_writer_autoclose ⇒ Object
Set this to false to disable closing transcript_writer on exit.
Instance Method Summary collapse
-
#[](varname) ⇒ Object
Get instance variable from the Evaluator.
-
#[]=(varname, value) ⇒ Object
Set an instance variable on the Evaluator.
-
#connect(remote_address) ⇒ Object
Connect to the specified address.
-
#dump(filename = nil) ⇒ Object
Generate a ScreenPattern from the current terminal state, and optionally append it to the specified file.
-
#eval_script_file(path) ⇒ Object
Load and evaluate a script from a file.
-
#eval_script_inline(str, filename = nil, lineno = nil) ⇒ Object
Evaluate a script specified as a string.
-
#exit ⇒ Object
Close the connection and exit.
-
#expect(pattern = nil) ⇒ Object
Convenience function.
-
#init_term(name = nil) ⇒ Object
Initialize a terminal emulator.
-
#initialize(options = {}) ⇒ Expect
constructor
Initialize the Expect object.
-
#load_screens(filenames_or_glob) ⇒ Object
Load screens from the specified filenames.
-
#on(pattern, opts = {}, &block) ⇒ Object
Add the specified pattern to the effective pattern list.
-
#p(*args) ⇒ Object
Like regular Ruby “p”, but also logs to the transcript.
-
#pop_patterns ⇒ Object
Pop the effective pattern list from the stack.
-
#pp(*args) ⇒ Object
Like regular Ruby “pp”, but also logs to the transcript.
-
#print(*args) ⇒ Object
Like regular Ruby “print”, but also logs to the transcript.
-
#push_patterns ⇒ Object
Push a copy of the effective pattern list to an internal stack.
-
#puts(*args) ⇒ Object
Like regular Ruby “puts”, but also logs to the transcript.
-
#screen(name) ⇒ Object
Return the named ScreenPattern (or nil if no such pattern exists).
-
#send(bytes) ⇒ Object
Send bytes to the remote application.
-
#send_password(bytes) ⇒ Object
Send password to the remote application.
- #set_timeout(seconds) ⇒ Object
-
#sleep(seconds) ⇒ Object
Sleep for the specified number of seconds.
-
#wait ⇒ Object
Wait for an effective pattern to match.
Constructor Details
#initialize(options = {}) ⇒ Expect
Initialize the Expect object.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/scriptty/expect.rb', line 42 def initialize(={}) @net = ScripTTY::Net::EventLoop.new @suspended = false @effective_patterns = nil @term_name = nil @effective_patterns = [] # Array of PatternHandle objects @pattern_stack = [] @wait_finished = false @evaluator = Evaluator.new(self) @match_buffer = "" @timeout = nil @timeout_timer = nil @transcript_writer = [:transcript_writer] @transcript_writer_autoclose = [:transcript_writer_autoclose].nil? ? true : [:transcript_writer_autoclose] @screen_patterns = {} end |
Instance Attribute Details
#capture ⇒ Object (readonly) Also known as: match
The last non-background captured fields. For a ScreenPattern match, this is a Hash of fields. For a String or Regexp match, this is a MatchData object.
35 36 37 |
# File 'lib/scriptty/expect.rb', line 35 def capture @capture end |
#term ⇒ Object (readonly)
The terminal emulation object
33 34 35 |
# File 'lib/scriptty/expect.rb', line 33 def term @term end |
#transcript_writer ⇒ Object
Set this to an instance of ScripTTY::Util::Transcript::Writer
38 39 40 |
# File 'lib/scriptty/expect.rb', line 38 def transcript_writer @transcript_writer end |
#transcript_writer_autoclose ⇒ Object
Set this to false to disable closing transcript_writer on exit
39 40 41 |
# File 'lib/scriptty/expect.rb', line 39 def transcript_writer_autoclose @transcript_writer_autoclose end |
Instance Method Details
#[](varname) ⇒ Object
Get instance variable from the Evaluator
60 61 62 |
# File 'lib/scriptty/expect.rb', line 60 def [](varname) @evaluator.instance_variable_get("@#{varname}") end |
#[]=(varname, value) ⇒ Object
Set an instance variable on the Evaluator
65 66 67 |
# File 'lib/scriptty/expect.rb', line 65 def []=(varname, value) @evaluator.instance_variable_set("@#{varname}", value) end |
#connect(remote_address) ⇒ Object
Connect to the specified address. Return true if the connection was successful. Otherwise, raise an exception.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/scriptty/expect.rb', line 113 def connect(remote_address) @transcript_writer.info("Script executing command", "connect", *remote_address.map{|a| a.inspect}) if @transcript_writer connected = false connect_error = nil @conn = @net.connect(remote_address) do |c| c.on_connect { connected = true; handle_connect; @net.suspend } c.on_connect_error { |e| connect_error = e; @net.suspend } c.on_receive_bytes { |bytes| handle_receive_bytes(bytes) } c.on_close { @conn = nil; handle_connection_close } end dispatch until connected or connect_error or @net.done? if connect_error transcribe_connect_error(connect_error) raise ScripTTY::Exception::ConnectError.new(connect_error) end refresh_timeout connected end |
#dump(filename = nil) ⇒ Object
Generate a ScreenPattern from the current terminal state, and optionally append it to the specified file.
NOTE: This method is intended for script development only; it is not exported to the Evaluator.
284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/scriptty/expect.rb', line 284 def dump(filename=nil) fail_unexpected_block if block_given? result = ScreenPattern.from_term(@term).generate if filename File.open(filename, "a") { |outfile| outfile.puts(result); outfile.puts("") } nil else result end end |
#eval_script_file(path) ⇒ Object
Load and evaluate a script from a file.
82 83 84 85 |
# File 'lib/scriptty/expect.rb', line 82 def eval_script_file(path) fail_unexpected_block if block_given? eval_script_inline(File.read(path), path) end |
#eval_script_inline(str, filename = nil, lineno = nil) ⇒ Object
Evaluate a script specified as a string.
88 89 90 91 |
# File 'lib/scriptty/expect.rb', line 88 def eval_script_inline(str, filename=nil, lineno=nil) fail_unexpected_block if block_given? @evaluator.instance_eval(str, filename || "(inline)", lineno || 1) end |
#exit ⇒ Object
Close the connection and exit.
271 272 273 274 275 276 277 |
# File 'lib/scriptty/expect.rb', line 271 def exit fail_unexpected_block if block_given? @transcript_writer.info("Script executing command", "exit") if @transcript_writer @net.exit dispatch until @net.done? @transcript_writer.close if @transcript_writer && @transcript_writer_autoclose end |
#expect(pattern = nil) ⇒ Object
Convenience function.
Examples
# Wait for a single pattern to match.
expect("login: ")
# Wait for one of several patterns to match.
expect {
on("login successful") { ... }
on("login incorrect") { ... }
}
207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/scriptty/expect.rb', line 207 def expect(pattern=nil) raise ArgumentError.new("no pattern and no block given") if !pattern and !block_given? @transcript_writer.info("Script expect block BEGIN") if @transcript_writer and block_given? push_patterns begin on(pattern) if pattern yield if block_given? wait ensure pop_patterns @transcript_writer.info("Script expect block END") if @transcript_writer and block_given? end end |
#init_term(name = nil) ⇒ Object
Initialize a terminal emulator.
If a name is specified, use that terminal type. Otherwise, use the previous terminal type.
97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/scriptty/expect.rb', line 97 def init_term(name=nil) @transcript_writer.info("Script executing command", "init_term", name || "") if @transcript_writer name ||= @term_name @term_name = name raise ArgumentError.new("No previous terminal specified") unless name without_timeout { @term = ScripTTY::Term.new(name) @term.on_unknown_sequence do |seq| @transcript_writer.info("Unknown escape sequence", seq) if @transcript_writer end } nil end |
#load_screens(filenames_or_glob) ⇒ Object
Load screens from the specified filenames
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/scriptty/expect.rb', line 179 def load_screens(filenames_or_glob) fail_unexpected_block if block_given? if filenames_or_glob.is_a?(String) filenames = Dir.glob(filenames_or_glob) elsif filenames_or_glob.is_a?(Array) filenames = filenames_or_glob else raise ArgumentError.new("load_screens takes a string(glob) or an array, not #{filenames.class.name}") end filenames.each do |filename| ScreenPattern.parse(File.read(filename)).each do |pattern| @screen_patterns[pattern.name.to_sym] = pattern end end nil end |
#on(pattern, opts = {}, &block) ⇒ Object
Add the specified pattern to the effective pattern list.
Return the PatternHandle for the pattern.
Options:
- :continue
-
If true, matching this pattern will not cause the wait method to return.
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/scriptty/expect.rb', line 140 def on(pattern, opts={}, &block) case pattern when String @transcript_writer.info("Script executing command", "on", "String", pattern.inspect) if @transcript_writer ph = PatternHandle.new(/#{Regexp.escape(pattern)}/n, block, opts[:background]) when Regexp @transcript_writer.info("Script executing command", "on", "Regexp", pattern.inspect) if @transcript_writer if pattern.kcode == "none" ph = PatternHandle.new(pattern, block, opts[:background]) else ph = PatternHandle.new(/#{pattern}/n, block, opts[:background]) end when ScreenPattern @transcript_writer.info("Script executing command", "on", "ScreenPattern", pattern.name, opts[:background] ? "BACKGROUND" : "") if @transcript_writer ph = PatternHandle.new(pattern, block, opts[:background]) else raise TypeError.new("Unsupported pattern type: #{pattern.class.inspect}") end @effective_patterns << ph ph end |
#p(*args) ⇒ Object
Like regular Ruby “p”, but also logs to the transcript.
310 311 312 313 |
# File 'lib/scriptty/expect.rb', line 310 def p(*args) @transcript_writer.info("p", *args.map{|a| a.to_s}) if @transcript_writer Kernel.p(*args) end |
#pop_patterns ⇒ Object
Pop the effective pattern list from the stack.
228 229 230 231 232 |
# File 'lib/scriptty/expect.rb', line 228 def pop_patterns fail_unexpected_block if block_given? raise ArgumentError.new("pattern stack empty") if @pattern_stack.empty? @effective_patterns = @pattern_stack.pop end |
#pp(*args) ⇒ Object
Like regular Ruby “pp”, but also logs to the transcript.
316 317 318 319 |
# File 'lib/scriptty/expect.rb', line 316 def pp(*args) @transcript_writer.info("pp", *args.map{|a| a.to_s}) if @transcript_writer PP.pp(*args) end |
#print(*args) ⇒ Object
Like regular Ruby “print”, but also logs to the transcript.
304 305 306 307 |
# File 'lib/scriptty/expect.rb', line 304 def print(*args) @transcript_writer.info("print", *args.map{|a| a.to_s}) if @transcript_writer Kernel.print(*args) end |
#push_patterns ⇒ Object
Push a copy of the effective pattern list to an internal stack.
222 223 224 225 |
# File 'lib/scriptty/expect.rb', line 222 def push_patterns fail_unexpected_block if block_given? @pattern_stack << @effective_patterns.dup end |
#puts(*args) ⇒ Object
Like regular Ruby “puts”, but also logs to the transcript.
298 299 300 301 |
# File 'lib/scriptty/expect.rb', line 298 def puts(*args) @transcript_writer.info("puts", *args.map{|a| a.to_s}) if @transcript_writer Kernel.puts(*args) end |
#screen(name) ⇒ Object
Return the named ScreenPattern (or nil if no such pattern exists)
173 174 175 176 |
# File 'lib/scriptty/expect.rb', line 173 def screen(name) fail_unexpected_block if block_given? @screen_patterns[name.to_sym] end |
#send(bytes) ⇒ Object
Send bytes to the remote application.
NOTE: This method returns immediately, even if not all the bytes are finished being sent. Remaining bytes will be sent during an expect, wait, or sleep call.
252 253 254 255 256 257 |
# File 'lib/scriptty/expect.rb', line 252 def send(bytes) fail_unexpected_block if block_given? @transcript_writer.from_client(bytes) if @transcript_writer @conn.write(bytes) true end |
#send_password(bytes) ⇒ Object
Send password to the remote application.
This works like the send method, but “PASSWORD” is shown in the transcript instead of the actual bytes sent.
263 264 265 266 267 268 |
# File 'lib/scriptty/expect.rb', line 263 def send_password(bytes) fail_unexpected_block if block_given? @transcript_writer.from_client("**PASSWORD**") if @transcript_writer @conn.write(bytes) true end |
#set_timeout(seconds) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/scriptty/expect.rb', line 69 def set_timeout(seconds) fail_unexpected_block if block_given? raise ArgumentError.new("argument to set_timeout must be Numeric or nil") unless seconds.is_a?(Numeric) or seconds.nil? if seconds @timeout = seconds.to_f else @timeout = nil end refresh_timeout nil end |
#sleep(seconds) ⇒ Object
Sleep for the specified number of seconds
163 164 165 166 167 168 169 170 |
# File 'lib/scriptty/expect.rb', line 163 def sleep(seconds) @transcript_writer.info("Script executing command", "sleep", seconds.inspect) if @transcript_writer sleep_done = false @net.timer(seconds) { sleep_done = true ; @net.suspend } dispatch until sleep_done refresh_timeout nil end |
#wait ⇒ Object
Wait for an effective pattern to match.
Clears the character-match buffer on return.
237 238 239 240 241 242 243 244 245 |
# File 'lib/scriptty/expect.rb', line 237 def wait fail_unexpected_block if block_given? @transcript_writer.info("Script executing command", "wait") if @transcript_writer check_expect_match unless @wait_finished dispatch until @wait_finished refresh_timeout @wait_finished = false nil end |