Class: Ask::Tools::Repl::Kernel
- Inherits:
-
Object
- Object
- Ask::Tools::Repl::Kernel
- Defined in:
- lib/ask/tools/shell/repl.rb
Overview
A single long-lived Ruby subprocess executing the kernel script.
Communicates over newline-delimited JSON on stdin/stdout. One eval at a time per kernel; concurrent calls serialize on an internal monitor.
Defined Under Namespace
Classes: DeadError, Error, TimeoutError
Instance Attribute Summary collapse
-
#last_used ⇒ Time
readonly
Last time an evaluation completed.
-
#session ⇒ String
readonly
Session name this kernel belongs to.
Instance Method Summary collapse
-
#close ⇒ void
Terminate the kernel process and close pipes.
-
#dead? ⇒ Boolean
Whether the kernel process is gone.
-
#eval(code, timeout: Repl.eval_timeout) ⇒ Hash
Evaluate
codein the persistent binding. -
#idle_seconds ⇒ Float
Seconds since the last evaluation.
-
#initialize(session:, ruby: "ruby") ⇒ Kernel
constructor
A new instance of Kernel.
Constructor Details
#initialize(session:, ruby: "ruby") ⇒ Kernel
Returns a new instance of Kernel.
186 187 188 189 190 191 192 193 |
# File 'lib/ask/tools/shell/repl.rb', line 186 def initialize(session:, ruby: "ruby") @session = session @script = File.("repl/kernel_script.rb", __dir__) @monitor = Monitor.new @last_used = Time.now @next_id = 0 spawn_process(ruby) end |
Instance Attribute Details
#last_used ⇒ Time (readonly)
Returns last time an evaluation completed.
184 185 186 |
# File 'lib/ask/tools/shell/repl.rb', line 184 def last_used @last_used end |
#session ⇒ String (readonly)
Returns session name this kernel belongs to.
181 182 183 |
# File 'lib/ask/tools/shell/repl.rb', line 181 def session @session end |
Instance Method Details
#close ⇒ void
This method returns an undefined value.
Terminate the kernel process and close pipes. TERM is normally enough (the kernel script exits on it); KILL is the fallback for user code that overrode the trap or wedged the VM.
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/ask/tools/shell/repl.rb', line 244 def close @monitor.synchronize do return if @closed @closed = true if @pid begin Process.kill("TERM", @pid) rescue Errno::ESRCH, Errno::ECHILD @pid = nil end wait_for_exit(2) if @pid begin Process.kill("KILL", @pid) rescue Errno::ESRCH, Errno::ECHILD @pid = nil end wait_for_exit(1) end end @in_w.close unless @in_w.closed? @out_r.close unless @out_r.closed? @err_r.close unless @err_r.closed? end nil end |
#dead? ⇒ Boolean
Returns whether the kernel process is gone. Reaps the child if it already exited (zombies count as dead).
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/ask/tools/shell/repl.rb', line 202 def dead? return true if @closed return true unless @pid _, status = Process.waitpid(@pid, Process::WNOHANG) if status.nil? false else @pid = nil true end rescue Errno::ECHILD, Errno::ESRCH, Errno::EINTR @pid = nil true end |
#eval(code, timeout: Repl.eval_timeout) ⇒ Hash
Evaluate code in the persistent binding.
227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/ask/tools/shell/repl.rb', line 227 def eval(code, timeout: Repl.eval_timeout) @monitor.synchronize do raise DeadError, "process not running" if dead? id = (@next_id += 1) write_frame("id" => id, "code" => code) response = read_frame(id, timeout) @last_used = Time.now response end end |
#idle_seconds ⇒ Float
Returns seconds since the last evaluation.
196 197 198 |
# File 'lib/ask/tools/shell/repl.rb', line 196 def idle_seconds Time.now - @last_used end |