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
# 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
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
# 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
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
# 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
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
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
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
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
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
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