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 [:basedir, :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_basedir, :set_timeout, :load_screens, :matched_screen, :matched_pattern, :print, :puts, :p, :pp ]
Instance Attribute Summary collapse
-
#basedir ⇒ Object
The base directory for eval_script_file and load_screens.
-
#capture ⇒ Object
(also: #match)
readonly
The last non-background captured fields.
-
#matched_pattern ⇒ Object
The last non-background pattern that matched (might be a RegExp or a ScreenPattern).
-
#matched_screen ⇒ Object
The last non-background ScreenPattern that matched.
-
#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_basedir(path) ⇒ Object
- #set_timeout(seconds) ⇒ Object
-
#sleep(seconds, options = {}) ⇒ 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.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/scriptty/expect.rb', line 49 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 = {} @basedir = "." @matched_pattern = nil @matched_screen = nil end |
Instance Attribute Details
#basedir ⇒ Object
The base directory for eval_script_file and load_screens. Defaults to “.”
46 47 48 |
# File 'lib/scriptty/expect.rb', line 46 def basedir @basedir end |
#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.
36 37 38 |
# File 'lib/scriptty/expect.rb', line 36 def capture @capture end |
#matched_pattern ⇒ Object
The last non-background pattern that matched (might be a RegExp or a ScreenPattern)
39 40 41 |
# File 'lib/scriptty/expect.rb', line 39 def matched_pattern @matched_pattern end |
#matched_screen ⇒ Object
The last non-background ScreenPattern that matched.
41 42 43 |
# File 'lib/scriptty/expect.rb', line 41 def matched_screen @matched_screen end |
#term ⇒ Object (readonly)
The terminal emulation object
34 35 36 |
# File 'lib/scriptty/expect.rb', line 34 def term @term end |
#transcript_writer ⇒ Object
Set this to an instance of ScripTTY::Util::Transcript::Writer
43 44 45 |
# File 'lib/scriptty/expect.rb', line 43 def transcript_writer @transcript_writer end |
#transcript_writer_autoclose ⇒ Object
Set this to false to disable closing transcript_writer on exit
44 45 46 |
# File 'lib/scriptty/expect.rb', line 44 def transcript_writer_autoclose @transcript_writer_autoclose end |
Instance Method Details
#[](varname) ⇒ Object
Get instance variable from the Evaluator
70 71 72 |
# File 'lib/scriptty/expect.rb', line 70 def [](varname) @evaluator.instance_variable_get("@#{varname}") end |
#[]=(varname, value) ⇒ Object
Set an instance variable on the Evaluator
75 76 77 |
# File 'lib/scriptty/expect.rb', line 75 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.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/scriptty/expect.rb', line 129 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.
304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/scriptty/expect.rb', line 304 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.
97 98 99 100 101 |
# File 'lib/scriptty/expect.rb', line 97 def eval_script_file(path) fail_unexpected_block if block_given? path = File.(path, @basedir) eval_script_inline(File.read(path), path) end |
#eval_script_inline(str, filename = nil, lineno = nil) ⇒ Object
Evaluate a script specified as a string.
104 105 106 107 |
# File 'lib/scriptty/expect.rb', line 104 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.
291 292 293 294 295 296 297 |
# File 'lib/scriptty/expect.rb', line 291 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") { ... }
}
227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/scriptty/expect.rb', line 227 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.
113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/scriptty/expect.rb', line 113 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
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/scriptty/expect.rb', line 197 def load_screens(filenames_or_glob) fail_unexpected_block if block_given? filenames_or_glob = filenames_or_glob.to_s if filenames_or_glob.is_a?(Pathname) if filenames_or_glob.is_a?(String) filenames_or_glob = File.(filenames_or_glob, @basedir) 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), 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.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/scriptty/expect.rb', line 156 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.
330 331 332 333 |
# File 'lib/scriptty/expect.rb', line 330 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.
248 249 250 251 252 |
# File 'lib/scriptty/expect.rb', line 248 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.
336 337 338 339 |
# File 'lib/scriptty/expect.rb', line 336 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.
324 325 326 327 |
# File 'lib/scriptty/expect.rb', line 324 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.
242 243 244 245 |
# File 'lib/scriptty/expect.rb', line 242 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.
318 319 320 321 |
# File 'lib/scriptty/expect.rb', line 318 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)
191 192 193 194 |
# File 'lib/scriptty/expect.rb', line 191 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.
272 273 274 275 276 277 |
# File 'lib/scriptty/expect.rb', line 272 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.
283 284 285 286 287 288 |
# File 'lib/scriptty/expect.rb', line 283 def send_password(bytes) fail_unexpected_block if block_given? @transcript_writer.from_client("**PASSWORD**") if @transcript_writer @conn.write(bytes) true end |
#set_basedir(path) ⇒ Object
91 92 93 94 |
# File 'lib/scriptty/expect.rb', line 91 def set_basedir(path) @basedir = path nil end |
#set_timeout(seconds) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/scriptty/expect.rb', line 79 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, options = {}) ⇒ Object
Sleep for the specified number of seconds
Pass :transcribe=>false to this method to suppress output to the transcript.
181 182 183 184 185 186 187 188 |
# File 'lib/scriptty/expect.rb', line 181 def sleep(seconds, ={}) @transcript_writer.info("Script executing command", "sleep", seconds.inspect) if @transcript_writer and [:transcribe] != false 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.
257 258 259 260 261 262 263 264 265 |
# File 'lib/scriptty/expect.rb', line 257 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 |