Class: Ruber::IRB::IRBController
- Inherits:
-
Qt::Object
- Object
- Qt::Object
- Ruber::IRB::IRBController
- Defined in:
- plugins/irb/irb_controller.rb,
plugins/irb/irb_controller.rb,
plugins/irb/irb_controller.rb,
plugins/irb/irb_controller.rb
Constant Summary
- TIMER_INTERVAL =
100
- DEFAULT_OUTPUT_LINES =
100
Instance Attribute Summary (collapse)
-
- (Integer?) interval
The minimum time interval (in milliseconds) between two #output_ready methods.
-
- (<String>) irb_options
The options to pass to IRB.
-
- (String) irb_program
The path if the IRB program.
Instance Method Summary (collapse)
-
- (nil) change_irb_prompt
private
Sends IRB the command to change the prompt.
-
- (Boolean) has_output?
Whether or not there’s output ready to be read.
-
- (IRBController) initialize(irb, options, parent = nil)
constructor
A new instance of IRBController.
-
- (Object) interrupt
Interrupts IRB evaluation by sending IRB the
SIGINT
signal. -
- (nil) irb_finished
slot
private
Restarts IRB after it has been terminated.
-
- (<IrbLine>) output(n = 100)
Reads a number of lines of output.
- - (Object) output_ready slot private
-
- (<IrbLine>?) parse_output(lines)
slot
private
Parses output lines from IRB, converting them to IrbLine objects.
-
- (nil) process_output
slot
private
Slot called whenever IRB sends output after the prompt has correctly been set up.
-
- (nil) prompts(prompts)
Changes the prompt.
-
- (nil) restart_irb
slot
Stops and immediately restarts the IRB process The #about_to_stop_irb is emitted before stopping IRB.
-
- (Boolean) running?
Whether IRB is running or not.
-
- (nil) send_next_line
private
Sends the next line of input to the IRB process.
-
- (nil) send_signal(signal)
Sends IRB a signal.
-
- (nil) send_to_irb(input)
slot
Sends input to IRB.
-
- (nil) set_irb_env
private
Changes the environment associated with the IRB process.
-
- (Boolean) start_irb
Starts IRB.
-
- (Symbol) state
The state of the IRB process.
-
- (nil) stop(meth)
private
Helper method to stop IRB.
-
- (nil) stop_irb
Stops the IRB process.
-
- (nil) timer_ticked
slot
private
Slot called in response to the timer timing out.
-
- (Object) wait_for_prompt_changed
slot
private
Slot called whenever IRB sends output before changes to the prompt have taken effect.
Signal Summary
- - output_received
-
- about_to_stop_irb
Signal emitted just before IRB is stopped, for whatever reason.
-
- interrupting_evaluation
Signal emitted just before interrupting IRB by sending a
SIGINT
signal. -
- evaluation_interrupted
Signal emitted after IRB has been interrupted by sending a
SIGINT
signal. -
- ready
Signal emitted when IRB is ready to receive input (that is, when it gives a prompt when there aren’t lines yet to be sent).
Constructor Details
- (IRBController) initialize(irb, options, parent = nil)
A new instance of IRBController
160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'plugins/irb/irb_controller.rb', line 160 def initialize irb, , parent = nil super parent @irb_program = irb @irb_options = .dup @timer = Qt::Timer.new self connect @timer, SIGNAL(:timeout), self, SLOT(:timer_ticked) @pending_prompt = nil @interrupting = false @evaluating = false @input = [] @output = [] @interval = 100 end |
Instance Attribute Details
- (Integer?) interval
The minimum time interval (in milliseconds) between two #output_ready methods. If nil, the #output_ready signal will be emitted as soon as output is received from IRB. The default value is 100 milliseconds
154 155 156 |
# File 'plugins/irb/irb_controller.rb', line 154 def interval @interval end |
- (<String>) irb_options
The options to pass to IRB. Note that changing this after IRB has been started won’t have any effect until you restart IRB.
145 146 147 |
# File 'plugins/irb/irb_controller.rb', line 145 def @irb_options end |
- (String) irb_program
The path if the IRB program. Note that changing this after IRB has been started won’t have any effect until you restart IRB.
149 150 151 |
# File 'plugins/irb/irb_controller.rb', line 149 def irb_program @irb_program end |
Instance Method Details
- (nil) change_irb_prompt (private)
Sends IRB the command to change the prompt
IRB should not be given input until this command has been executed
358 359 360 361 362 363 364 365 366 |
# File 'plugins/irb/irb_controller.rb', line 358 def change_irb_prompt prompts = @prompt.prompts.dup prompts[:RETURN] += "%s\n" disconnect @irb, SIGNAL(:readyReadStandardOutput), self, SLOT(:process_output) connect @irb, SIGNAL(:readyReadStandardOutput), self, SLOT(:wait_for_prompt_changed) cmd = "IRB.conf[:PROMPT][:QUIRB]=#{prompts.inspect}\nconf.prompt_mode = :QUIRB\n" @irb.write cmd nil end |
- (Boolean) has_output?
Whether or not there’s output ready to be read
177 178 179 |
# File 'plugins/irb/irb_controller.rb', line 177 def has_output? !@output.empty? end |
- (Object) interrupt
Interrupts IRB evaluation by sending IRB the SIGINT
signal
This will also clear any pending input. The #output_ready signal won’t
be emitted until IRB sends an empty prompt. The #interrupting_evaluation
signal is emitted before sending IRB the SIGINT
signal
180 181 182 183 184 185 186 187 |
# File 'plugins/irb/irb_controller.rb', line 180 def interrupt @interrupting = true @timer.stop @input.clear emit interrupting_evaluation Process.kill :INT, @irb.pid nil end |
- (nil) irb_finished (private)
Restarts IRB after it has been terminated
This method is connected to the IRB process’s finished(int, QProcess::ExitStatus)
signal, so that a new IRB process can be automatically started. This doesn’t
happen when #stop_irb is used to kill the IRB process
439 440 441 442 443 |
# File 'plugins/irb/irb_controller.rb', line 439 def irb_finished @irb.delete_later start_irb nil end |
Slot Signature:
irb_finished()
- (<IrbLine>) output(n = 100)
Reads a number of lines of output
Lines which have been read are removed from the output buffer
324 325 326 327 328 329 |
# File 'plugins/irb/irb_controller.rb', line 324 def output n = 100 if n then n = [n, @output.size].min else n = @output.count end @output.shift n end |
- (Object) output_ready (private)
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'plugins/irb/irb_controller.rb', line 261 def output_ready new_lines = @irb.read_all_standard_output.to_s.split "\n" lines = process_output new_lines, false return unless lines @output.concat lines if @prompt and !@interrupting if lines.last and lines.last.category == :input and lines.last.text.empty? is_ready = true @pending_prompt = @output.pop end emit output_received if @output.count <= 100 @timer.start(TIMER_INTERVAL) if !@output.empty? and !@timer.active? send_next_line if (@in_evaluation and is_ready) or !@in_evaluation elsif @interrupting prompt_line = lines.find{|l| l.category == :input and l.text.empty?} if prompt_line @interrupting = false idx = lines.index prompt_line lines = @output.pop lines.size - idx + 1 emit evaluation_interrupted @output = lines emit output_received send_next_line end end end |
Slot Signature:
output_ready()
- (<IrbLine>?) parse_output(lines) (private)
Parses output lines from IRB, converting them to Ruber::IRB::IrbLine objects
If the prompt has been set up, the lines will be processed using PromptMatcher#match, otherwise they’ll all be considered output lines with no prompt.
If the controller is sending input to IRB and there’s a pending prompt, that prompt will be added to the beginning of the first line, then removed
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
# File 'plugins/irb/irb_controller.rb', line 516 def parse_output lines return if lines.empty? if @prompt parsed_lines = lines.map do |l| @prompt.match(l) || IrbLine.new( :output, l, '') end else parsed_lines = lines.map{|l| IrbLine.new :output, l, ''} end if @evaluating and @pending_prompt and parsed_lines[0].type == :output parsed_lines[0] = IrbLine.new :normal, lines[0], @pending_prompt.prompt @pending_prompt = nil end parsed_lines end |
Slot Signature:
parse_output()
- (nil) process_output (private)
Slot called whenever IRB sends output after the prompt has correctly been set up
It adds the output lines to the output buffer, after converting them to Ruber::IRB::IrbLine objects. If the last line is a prompt line and the controller is sending input to IRB, it calls #send_next_line.
If the controller is interrupting IRB and a prompt is found, the #evaluation_interrupted signal is emitted, followed by the #ready signal
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
# File 'plugins/irb/irb_controller.rb', line 468 def process_output new_lines = @irb.read_all_standard_output.to_s.split "\n" lines = parse_output new_lines return unless @prompt return unless lines @output.concat lines if lines.last and lines.last.category == :input and lines.last.text.empty? is_ready = true @pending_prompt = @output.pop end if @prompt and !@interrupting emit output_ready if !@interval or @output.count <= 100 @timer.start(@interval) if @interval and !@output.empty? and !@timer.active? send_next_line if (@evaluating and is_ready) or !@evaluating elsif @interrupting if is_ready @interrupting = false emit evaluation_interrupted @output.clear send_next_line end end nil end |
Slot Signature:
process_output()
- (nil) prompts=(prompts)
in the return prompt, don’t add the ending %s\n
, as it will be
added automatically
users must not use IRB.conf[:PROMPT]
or IRB.conf.prompt_mode=
to change IRB’s prompt, but always call this method. This is
because Ruber::IRB::IRBController, behind the scenes, needs to add a special string to the
prompt chosen by the user to work correctly
changing the prompt takes effect immediately, even if IRB has already been started
Changes the prompt
Calling this method is the same as adding a new entry to IRB.conf[:PROMPT]
and changing the current prompt using IRB.conf.prompt_mode=
.
284 285 286 287 288 |
# File 'plugins/irb/irb_controller.rb', line 284 def prompts= prompts id = Array.new(5){rand(10)}.join '' @prompt = PromptMatcher.new id, prompts change_irb_prompt if running? end |
- (nil) restart_irb
Stops and immediately restarts the IRB process The #about_to_stop_irb is emitted before stopping IRB. After emitting this signal, all output will be cleared, so you won’t be able to access it anymore.
239 240 241 242 |
# File 'plugins/irb/irb_controller.rb', line 239 def restart_irb stop :terminate nil end |
Slot Signature:
restart_irb()
- (Boolean) running?
Whether IRB is running or not
325 326 327 |
# File 'plugins/irb/irb_controller.rb', line 325 def running? @irb and (@irb.state == Qt::Process::Running) end |
- (nil) send_next_line (private)
Sends the next line of input to the IRB process
If there’s no queued input line, the #ready signal will be emitted
450 451 452 453 454 455 456 |
# File 'plugins/irb/irb_controller.rb', line 450 def send_next_line if @input.empty? @evaluating = false emit ready else @irb.write @input.shift + "\n" end end |
- (nil) send_signal(signal)
if you want to stop evaluation (for example, to exit and endless loop),
do not use this method to send a SIGINT
, but use #interrupt. Simply
sending a SIGINT
signal may not work very well in that case, as, if IRB
keeps sending output, #output_ready signals will kept being emitted
Sends IRB a signal
256 257 258 259 260 261 262 263 264 265 |
# File 'plugins/irb/irb_controller.rb', line 256 def send_signal signal pid = @irb.pid begin Process.kill signal, pid rescue Errno::EINVAL, RangeError, ArgumentError raise ArgumentError, "Invalid signal #{signal}" rescue Errno::ESRCH, Errno::EPERM raise RuntimeError, "It wasn't possible to send IRB a signal" end nil end |
- (nil) send_to_irb(input)
Sends input to IRB
The input lines are sent one by one, expecting a prompt before sending a new one. The #ready signal is emitted at the first prompt after the last line has been sent. If there are lines waiting to be sent, the new ones will be added at the end of the queue.
197 198 199 200 201 202 203 204 |
# File 'plugins/irb/irb_controller.rb', line 197 def send_to_irb input @input.concat input unless @evaluating @evaluating = true send_next_line end nil end |
Slot Signature:
send_to_irb()
- (nil) set_irb_env (private)
Changes the environment associated with the IRB process
The environment is changed by adding an IRBRC
variable which points to
the irbrc.rb
file in the same directory as irb_controller.rb
.
389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'plugins/irb/irb_controller.rb', line 389 def set_irb_env dir = File.dirname(__FILE__) vars = ['IRBRC', File.join(dir, 'irbrc.rb')] if defined? Qt::ProcessEnvironment env = Qt::ProcessEnvironment.system_environment env.insert *vars @irb.process_environment = env else env = @irb.system_environment env << vars.join('=') @irb.environment = env end nil end |
- (Boolean) start_irb
Starts IRB
If IRB is already running, it’ll be stopped. The #ready signal will be emitted when IRB is ready to accept output.
This method will wait for IRB to start for up to two seconds before returning.
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'plugins/irb/irb_controller.rb', line 301 def start_irb if @irb @irb.kill @irb.delete_later end @irb = Qt::Process.new self @irb.process_channel_mode = Qt::Process::MergedChannels set_irb_env connect @irb, SIGNAL('finished(int, QProcess::ExitStatus)'), self, SLOT(:irb_finished) = @irb_options + ['--noreadline'] @irb.start @irb_program, @irb.wait_for_started 2000 if @irb.state == Qt::Process::Running change_irb_prompt true else false end end |
- (Symbol) state
The state of the IRB process
333 334 335 336 337 338 339 340 341 342 |
# File 'plugins/irb/irb_controller.rb', line 333 def state if @irb case @irb.state when Qt::Process::Running then :running when Qt::Process::Starting then :starting else :not_running end else :not_running end end |
- (nil) stop(meth) (private)
Helper method to stop IRB
It’s used by both #stop_irb and #restart_irb. It takes care of reading any unread output from IRB, emitting the #about_to_stop_irb signal, stopping the timer and so on.
219 220 221 222 223 224 225 226 |
# File 'plugins/irb/irb_controller.rb', line 219 def stop meth parse_output @irb.read_all_standard_output.to_s.split("\n") emit about_to_stop_irb @timer.stop @irb.disconnect SIGNAL(:readyReadStandardOutput) @irb.send meth nil end |
- (nil) stop_irb
this method will wait for up to two seconds for IRB to stop. If it
Stops the IRB process
The #about_to_stop_irb is emitted before stopping IRB. No further #output_ready signals are emitted.
You’ll need to call #start_irb if you want IRB to be restarted after calling this method. If all you need is to stop IRB and immediately restart it, however, use #restart_irb rather than #stop
doesn’t stop by that time, it will return all the same.
226 227 228 229 230 231 |
# File 'plugins/irb/irb_controller.rb', line 226 def stop_irb disconnect @irb, SIGNAL('finished(int, QProcess::ExitStatus)'), self, SLOT(:irb_finished) stop :kill # It seems it takes some time before irb is killed. @irb.wait_for_finished 2000 end |
- (nil) timer_ticked (private)
Slot called in response to the timer timing out
It emits the #output_ready signal and stops the timer if there’s no more output
499 500 501 502 503 |
# File 'plugins/irb/irb_controller.rb', line 499 def timer_ticked emit output_ready @timer.stop if @output.empty? nil end |
Slot Signature:
timer_ticked()
- (Object) wait_for_prompt_changed (private)
Slot called whenever IRB sends output before changes to the prompt have taken effect
If the lines sent by IRB contain the correct prompt, the readyReadStandardOutput
signal from the IRB process will be connected to the #process_output
signal and the #ready signal will be emitted
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'plugins/irb/irb_controller.rb', line 410 def wait_for_prompt_changed lines = @irb.read_all_standard_output.to_s.split "\n" found = false lines.each do |l| if @prompt.match l disconnect @irb, SIGNAL(:readyReadStandardOutput), self, SLOT(:wait_for_prompt_changed) connect @irb, SIGNAL(:readyReadStandardOutput), self, SLOT(:process_output) found = true break end end if found empty_prompt = lines.reverse_each.find do |l| res = @prompt.match l res and res.category == :input and res.text.empty? end @pending_prompt = @prompt.match empty_prompt if empty_prompt end emit ready end |
Slot Signature:
wait_for_prompt_changed()
Signal Details
- output_received
- about_to_stop_irb
Signal emitted just before IRB is stopped, for whatever reason. Connecting to this signal is the last opportunity to read the output from it.
- interrupting_evaluation
Signal emitted just before interrupting IRB by sending a SIGINT
signal
- evaluation_interrupted
Signal emitted after IRB has been interrupted by sending a SIGINT
signal
- ready
Signal emitted when IRB is ready to receive input (that is, when it gives a prompt when there aren’t lines yet to be sent)