In Files

  • irb.rb
  • irb/ext/multi-irb.rb

IRB::Irb

Attributes

context[R]

Returns the current context of this irb session

scanner[RW]

The lexer used by this irb session

Public Class Methods

new(workspace = nil, input_method = nil) click to toggle source

Creates a new irb session

 
               # File irb.rb, line 455
def initialize(workspace = nil, input_method = nil)
  @context = Context.new(self, workspace, input_method)
  @context.main.extend ExtendCommandBundle
  @signal_status = :IN_IRB
  @scanner = RubyLex.new
end
            

Public Instance Methods

assignment_expression?(line) click to toggle source
 
               # File irb.rb, line 816
def assignment_expression?(line)
  # Try to parse the line and check if the last of possibly multiple
  # expressions is an assignment type.

  # If the expression is invalid, Ripper.sexp should return nil which will
  # result in false being returned. Any valid expression should return an
  # s-expression where the second selement of the top level array is an
  # array of parsed expressions. The first element of each expression is the
  # expression's type.
  verbose, $VERBOSE = $VERBOSE, nil
  result = ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0))
  $VERBOSE = verbose
  result
end
            
eval_input() click to toggle source

Evaluates input for this session.

 
               # File irb.rb, line 485
def eval_input
  exc = nil

  @scanner.set_prompt do
    |ltype, indent, continue, line_no|
    if ltype
      f = @context.prompt_s
    elsif continue
      f = @context.prompt_c
    elsif indent > 0
      f = @context.prompt_n
    else
      f = @context.prompt_i
    end
    f = "" unless f
    if @context.prompting?
      @context.io.prompt = p = prompt(f, ltype, indent, line_no)
    else
      @context.io.prompt = p = ""
    end
    if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
      unless ltype
        prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
        ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
          indent * 2 - p.size
        ind += 2 if continue
        @context.io.prompt = p + " " * ind if ind > 0
      end
    end
    @context.io.prompt
  end

  @scanner.set_input(@context.io) do
    signal_status(:IN_INPUT) do
      if l = @context.io.gets
        print l if @context.verbose?
      else
        if @context.ignore_eof? and @context.io.readable_after_eof?
          l = "\n"
          if @context.verbose?
            printf "Use \"exit\" to leave %s\n", @context.ap_name
          end
        else
          print "\n"
        end
      end
      l
    end
  end

  @scanner.set_auto_indent(@context) if @context.auto_indent_mode

  @scanner.each_top_level_statement do |line, line_no|
    signal_status(:IN_EVAL) do
      begin
        line.untaint if RUBY_VERSION < '2.7'
        if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
          IRB.set_measure_callback
        end
        if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
          result = nil
          last_proc = proc{ result = @context.evaluate(line, line_no, exception: exc) }
          IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) { |chain, item|
            _name, callback, arg = item
            proc {
              callback.(@context, line, line_no, arg, exception: exc) do
                chain.call
              end
            }
          }.call
          @context.set_last_value(result)
        else
          @context.evaluate(line, line_no, exception: exc)
        end
        if @context.echo?
          if assignment_expression?(line)
            if @context.echo_on_assignment?
              output_value(@context.echo_on_assignment? == :truncate)
            end
          else
            output_value
          end
        end
      rescue Interrupt => exc
      rescue SystemExit, SignalException
        raise
      rescue Exception => exc
      else
        exc = nil
        next
      end
      handle_exception(exc)
    end
  end
end
            
handle_exception(exc) click to toggle source
 
               # File irb.rb, line 581
def handle_exception(exc)
  if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
     !(SyntaxError === exc) && !(EncodingError === exc)
    # The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno.
    irb_bug = true
  else
    irb_bug = false
  end

  if STDOUT.tty?
    attr = ATTR_TTY
    print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n"
  else
    attr = ATTR_PLAIN
  end
  messages = []
  lasts = []
  levels = 0
  if exc.backtrace
    count = 0
    exc.backtrace.each do |m|
      m = @context.workspace.filter_backtrace(m) or next unless irb_bug
      count += 1
      if attr == ATTR_TTY
        m = sprintf("%9d: from %s", count, m)
      else
        m = "\tfrom #{m}"
      end
      if messages.size < @context.back_trace_limit
        messages.push(m)
      elsif lasts.size < @context.back_trace_limit
        lasts.push(m).shift
        levels += 1
      end
    end
  end
  if attr == ATTR_TTY
    unless lasts.empty?
      puts lasts.reverse
      printf "... %d levels...\n", levels if levels > 0
    end
    puts messages.reverse
  end
  m = exc.to_s.split(/\n/)
  print "#{attr[1]}#{exc.class} (#{attr[4]}#{m.shift}#{attr[0, 1]})#{attr[]}\n"
  puts m.map {|s| "#{attr[1]}#{s}#{attr[]}\n"}
  if attr == ATTR_PLAIN
    puts messages
    unless lasts.empty?
      puts lasts
      printf "... %d levels...\n", levels if levels > 0
    end
  end
  print "Maybe IRB bug!\n" if irb_bug
end
            
inspect() click to toggle source

Outputs the local variables to this current session, including signal_status and context, using IRB::Locale.

 
               # File irb.rb, line 801
def inspect
  ary = []
  for iv in instance_variables
    case (iv = iv.to_s)
    when "@signal_status"
      ary.push format("%s=:%s", iv, @signal_status.id2name)
    when "@context"
      ary.push format("%s=%s", iv, eval(iv).__to_s__)
    else
      ary.push format("%s=%s", iv, eval(iv))
    end
  end
  format("#<%s: %s>", self.class, ary.join(", "))
end
            
run(conf = IRB.conf) click to toggle source
 
               # File irb.rb, line 462
def run(conf = IRB.conf)
  conf[:IRB_RC].call(context) if conf[:IRB_RC]
  conf[:MAIN_CONTEXT] = context

  trap("SIGINT") do
    signal_handle
  end

  begin
    catch(:IRB_EXIT) do
      eval_input
    end
  ensure
    conf[:AT_EXIT].each{|hook| hook.call}
  end
end
            
signal_handle() click to toggle source

Handler for the signal SIGINT, see Kernel#trap for more information.

 
               # File irb.rb, line 693
def signal_handle
  unless @context.ignore_sigint?
    print "\nabort!\n" if @context.verbose?
    exit
  end

  case @signal_status
  when :IN_INPUT
    print "^C\n"
    raise RubyLex::TerminateLineInput
  when :IN_EVAL
    IRB.irb_abort(self)
  when :IN_LOAD
    IRB.irb_abort(self, LoadAbort)
  when :IN_IRB
    # ignore
  else
    # ignore other cases as well
  end
end
            
signal_status(status) click to toggle source

Evaluates the given block using the given status.

 
               # File irb.rb, line 715
def signal_status(status)
  return yield if @signal_status == :IN_LOAD

  signal_status_back = @signal_status
  @signal_status = status
  begin
    yield
  ensure
    @signal_status = signal_status_back
  end
end
            
suspend_context(context) click to toggle source

Evaluates the given block using the given context as the Context.

 
               # File irb.rb, line 683
def suspend_context(context)
  @context, back_context = context, @context
  begin
    yield back_context
  ensure
    @context = back_context
  end
end
            
suspend_input_method(input_method) click to toggle source

Evaluates the given block using the given input_method as the Context#io.

Used by the irb commands source and irb_load, see IRB Sessions at IRB for more information.

 
               # File irb.rb, line 672
def suspend_input_method(input_method)
  back_io = @context.io
  @context.instance_eval{@io = input_method}
  begin
    yield back_io
  ensure
    @context.instance_eval{@io = back_io}
  end
end
            
suspend_name(path = nil, name = nil) click to toggle source

Evaluates the given block using the given path as the Context#irb_path and name as the Context#irb_name.

Used by the irb command source, see IRB Sessions at IRB for more information.

 
               # File irb.rb, line 642
def suspend_name(path = nil, name = nil)
  @context.irb_path, back_path = path, @context.irb_path if path
  @context.irb_name, back_name = name, @context.irb_name if name
  begin
    yield back_path, back_name
  ensure
    @context.irb_path = back_path if path
    @context.irb_name = back_name if name
  end
end
            
suspend_workspace(workspace) click to toggle source

Evaluates the given block using the given workspace as the Context#workspace.

Used by the irb command irb_load, see IRB Sessions at IRB for more information.

 
               # File irb.rb, line 658
def suspend_workspace(workspace)
  @context.workspace, back_workspace = workspace, @context.workspace
  begin
    yield back_workspace
  ensure
    @context.workspace = back_workspace
  end
end