Class: Expectr::Child
- Inherits:
-
Object
- Object
- Expectr::Child
- Includes:
- Interface
- Defined in:
- lib/expectr/child.rb,
lib/expectr/errstr.rb
Overview
Internal: The Expectr::Child class contains the interface to interacting with child processes.
All methods with the prefix ‘interface_’ in their name will return a Proc designed to be defined as an instance method in the primary Expectr object. These methods will all be documented as if they are the Proc in question.
Direct Known Subclasses
Defined Under Namespace
Modules: Errstr
Instance Attribute Summary collapse
-
#pid ⇒ Object
readonly
Returns the value of attribute pid.
-
#stdin ⇒ Object
readonly
Returns the value of attribute stdin.
-
#stdout ⇒ Object
readonly
Returns the value of attribute stdout.
Class Method Summary collapse
-
.spawn(cmd, args = {}) ⇒ Object
Public: Present a streamlined interface to create a new Expectr instance.
Instance Method Summary collapse
-
#initialize(cmd) ⇒ Child
constructor
Public: Initialize a new Expectr::Child object.
-
#interface_interact_thread ⇒ Object
Public: Create a Thread containing the loop which is responsible for handling input from the user in interact mode.
-
#interface_kill! ⇒ Object
Public: Send a signal to the running child process.
-
#interface_output_loop ⇒ Object
Public: Read the child process’s output, force UTF-8 encoding, then append to the internal buffer and print to $stdout if appropriate.
- #interface_prepare_interact_environment ⇒ Object
-
#interface_send ⇒ Object
Public: Send input to the active child process.
-
#interface_winsize ⇒ Object
Public: Return the PTY’s window size.
Methods included from Interface
#init_instance, #interface_prepare_interact_interface, #interface_restore_environment
Constructor Details
#initialize(cmd) ⇒ Child
Public: Initialize a new Expectr::Child object. Spawns a sub-process and attaches to STDIN and STDOUT for the new process.
cmd - A String or File referencing the application to launch.
Raises TypeError if argument is anything other than String or File.
24 25 26 27 28 29 30 31 32 |
# File 'lib/expectr/child.rb', line 24 def initialize(cmd) cmd = cmd.path if cmd.kind_of?(File) unless cmd.kind_of?(String) raise(TypeError, Errstr::STRING_FILE_EXPECTED) end @stdout,@stdin,@pid = PTY.spawn(cmd) @stdout.winsize = $stdout.winsize if $stdout.tty? end |
Instance Attribute Details
#pid ⇒ Object (readonly)
Returns the value of attribute pid.
15 16 17 |
# File 'lib/expectr/child.rb', line 15 def pid @pid end |
#stdin ⇒ Object (readonly)
Returns the value of attribute stdin.
13 14 15 |
# File 'lib/expectr/child.rb', line 13 def stdin @stdin end |
#stdout ⇒ Object (readonly)
Returns the value of attribute stdout.
14 15 16 |
# File 'lib/expectr/child.rb', line 14 def stdout @stdout end |
Class Method Details
.spawn(cmd, args = {}) ⇒ Object
Public: Present a streamlined interface to create a new Expectr instance.
cmd - A String or File referencing the application to launch. args - A Hash used to specify options for the new object, per
Expectr#initialize.
Returns a new Expectr object
160 161 162 163 |
# File 'lib/expectr/child.rb', line 160 def self.spawn(cmd, args = {}) args[:interface] = :child Expectr.new(cmd, args) end |
Instance Method Details
#interface_interact_thread ⇒ Object
Public: Create a Thread containing the loop which is responsible for handling input from the user in interact mode.
Returns a Thread containing the running loop.
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/expectr/child.rb', line 123 def interface_interact_thread -> { @interact = true env = prepare_interact_environment Thread.new do begin input = '' while @pid > 0 && @interact if select([$stdin], nil, nil, 1) c = $stdin.getc.chr send c unless c.nil? end end ensure restore_environment(env) end end } end |
#interface_kill! ⇒ Object
Public: Send a signal to the running child process.
signal - Symbol, String or FixNum corresponding to the symbol to be sent to the running process. (default: :TERM)
Returns a boolean indicating whether the process was successfully sent the signal. Raises ProcessError if the process is not running (@pid = 0).
42 43 44 45 46 47 48 49 |
# File 'lib/expectr/child.rb', line 42 def interface_kill! ->(signal = :TERM) { unless @pid > 0 raise(ProcessError, Errstr::PROCESS_NOT_RUNNING) end Process::kill(signal.to_sym, @pid) == 1 } end |
#interface_output_loop ⇒ Object
Public: Read the child process’s output, force UTF-8 encoding, then append to the internal buffer and print to $stdout if appropriate.
Returns nothing.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/expectr/child.rb', line 74 def interface_output_loop -> { while @pid > 0 unless select([@stdout], nil, nil, @timeout).nil? buf = '' begin @stdout.sysread(@buffer_size, buf) rescue Errno::EIO #Application is not running @pid = 0 return end process_output(buf) end end } end |
#interface_prepare_interact_environment ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/expectr/child.rb', line 92 def interface_prepare_interact_environment -> { env = {sig: {}} # Save old tty settings and set up the new environment env[:tty] = `stty -g` `stty -icanon min 1 time 0 -echo` # SIGINT should be sent to the child as \C-c env[:sig]['INT'] = trap 'INT' do send "\C-c" end # SIGTSTP should be sent to the process as \C-z env[:sig]['TSTP'] = trap 'TSTP' do send "\C-z" end # SIGWINCH should trigger an update to the child processes window size env[:sig]['WINCH'] = trap 'WINCH' do @stdout.winsize = $stdout.winsize end env } end |
#interface_send ⇒ Object
Public: Send input to the active child process.
str - String to be sent.
Returns nothing. Raises Expectr::ProcessError if the process is not running (@pid = 0)
57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/expectr/child.rb', line 57 def interface_send ->(str) { begin @stdin.syswrite str rescue Errno::EIO #Application is not running @pid = 0 end unless @pid > 0 raise(Expectr::ProcessError, Errstr::PROCESS_GONE) end } end |
#interface_winsize ⇒ Object
Public: Return the PTY’s window size.
Returns a two-element Array (same as IO#winsize)
147 148 149 150 151 |
# File 'lib/expectr/child.rb', line 147 def interface_winsize -> { @stdout.winsize } end |