Class: IRB::Irb
Relationships & Source Files | |
Inherits: | Object |
Defined in: | lib/irb.rb, lib/irb/ext/multi-irb.rb |
Constant Summary
-
ASSIGNMENT_NODE_TYPES =
# File 'lib/irb.rb', line 444[ # Local, instance, global, class, constant, instance, and index assignment: # "foo = bar", # "@foo = bar", # "$foo = bar", # "@@foo = bar", # "::Foo = bar", # "a::Foo = bar", # "Foo = bar" # "foo.bar = 1" # "foo[1] = bar" :assign, # Operation assignment: # "foo += bar" # "foo -= bar" # "foo ||= bar" # "foo &&= bar" :opassign, # Multiple assignment: # "foo, bar = 1, 2 :massign, ]
-
ATTR_PLAIN =
# File 'lib/irb.rb', line 885""
-
ATTR_TTY =
# File 'lib/irb.rb', line 883"\e[%sm"
Class Method Summary
-
.new(workspace = nil, input_method = nil) ⇒ Irb
constructor
Creates a new irb session.
Instance Attribute Summary
Instance Method Summary
- #assignment_expression?(line) ⇒ Boolean
- #convert_invalid_byte_sequence(str, enc)
- #encode_with_invalid_byte_sequence(str, enc)
-
#eval_input
Evaluates input for this session.
- #handle_exception(exc)
-
#inspect
Outputs the local variables to this current session, including #signal_status and #context, using
Locale
. - #run(conf = IRB.conf)
-
#signal_handle
Handler for the signal SIGINT, see
Kernel.trap
for more information. -
#signal_status(status)
Evaluates the given block using the given
status
. - #suspend_context(context)
-
#suspend_input_method(input_method)
Evaluates the given block using the given
input_method
as the Context#io. -
#suspend_name(path = nil, name = nil)
Evaluates the given block using the given
path
as the Context#irb_path andname
as the Context#irb_name. -
#suspend_workspace(workspace)
Evaluates the given block using the given
workspace
as the Context#workspace. - #output_value(omit = false) Internal use only
- #prompt(prompt, ltype, indent, line_no) Internal use only
Constructor Details
.new(workspace = nil, input_method = nil) ⇒ Irb
Creates a new irb session
# File 'lib/irb.rb', line 474
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
Instance Attribute Details
#context (readonly)
Returns the current context of this irb session
# File 'lib/irb.rb', line 500
attr_reader :context
#scanner (rw)
The lexer used by this irb session
# File 'lib/irb.rb', line 502
attr_accessor :scanner
Instance Method Details
#assignment_expression?(line) ⇒ Boolean
# File 'lib/irb.rb', line 868
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 element 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
#convert_invalid_byte_sequence(str, enc)
[ GitHub ]# File 'lib/irb.rb', line 603
def convert_invalid_byte_sequence(str, enc) str.force_encoding(enc) str.scrub { |c| c.bytes.map{ |b| "\\x#{b.to_s(16).upcase}" }.join } end
#encode_with_invalid_byte_sequence(str, enc)
[ GitHub ]# File 'lib/irb.rb', line 610
def encode_with_invalid_byte_sequence(str, enc) conv = Encoding::Converter.new(str.encoding, enc) dst = String.new begin ret = conv.primitive_convert(str, dst) case ret when :invalid_byte_sequence conv.insert_output(conv.primitive_errinfo[3].dump[1..-2]) redo when :undefined_conversion c = conv.primitive_errinfo[3].dup.force_encoding(conv.primitive_errinfo[1]) conv.insert_output(c.dump[1..-2]) redo when :incomplete_input conv.insert_output(conv.primitive_errinfo[3].dump[1..-2]) when :finished end break end while nil dst end
#eval_input
Evaluates input for this session.
# File 'lib/irb.rb', line 505
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, context: @context) 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" if @context.prompting? 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) @context.workspace.local_variable_set(:_, exc) exc = nil end end end
#handle_exception(exc)
[ GitHub ]# File 'lib/irb.rb', line 632
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 exc.backtrace order = nil if '2.5.0' == RUBY_VERSION # Exception#full_message doesn't have keyword arguments. = exc. # the same of (highlight: true, order: bottom) order = :bottom elsif '2.5.1' <= RUBY_VERSION && RUBY_VERSION < '3.0.0' if STDOUT.tty? = exc. (order: :bottom) order = :bottom else = exc. (order: :top) order = :top end else # '3.0.0' <= RUBY_VERSION = exc. (order: :top) order = :top end = convert_invalid_byte_sequence(, exc. .encoding) = encode_with_invalid_byte_sequence(, IRB.conf[:LC_MESSAGES].encoding) unless .encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s) = .gsub(/((?:^\t.$\n))/) { |m| case order when :top lines = m.split("\n") when :bottom lines = m.split("\n").reverse end unless irb_bug lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact if lines.size > @context.back_trace_limit omit = lines.size - @context.back_trace_limit lines = lines[0..(@context.back_trace_limit - 1)] lines << "\t... %d levels..." % omit end end lines = lines.reverse if order == :bottom lines.map{ |l| l + "\n" }.join } # The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object. = .gsub(/\(irb\):(?<num>\d+):in `<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in `<main>'" } puts end print "Maybe IRB bug!\n" if irb_bug end
#inspect
Outputs the local variables to this current session, including #signal_status and #context, using Locale
.
# File 'lib/irb.rb', line 853
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
#output_value(omit = false)
# File 'lib/irb.rb', line 815
def output_value(omit = false) # :nodoc: str = @context.inspect_last_value multiline_p = str.include?("\n") if omit winwidth = @context.io.winsize.last if multiline_p first_line = str.split("\n").first result = @context.newline_before_multiline_output? ? (@context.return_format % first_line) : first_line output_width = Reline::Unicode.calculate_width(result, true) diff_size = output_width - Reline::Unicode.calculate_width(first_line, true) if diff_size.positive? and output_width > winwidth lines, _ = Reline::Unicode.split_by_width(first_line, winwidth - diff_size - 3) str = "%s..." % lines.first str += "\e[0m" if @context.use_colorize multiline_p = false else str = str.gsub(/(\A.*?\n).*/m, "\\1...") str += "\e[0m" if @context.use_colorize end else output_width = Reline::Unicode.calculate_width(@context.return_format % str, true) diff_size = output_width - Reline::Unicode.calculate_width(str, true) if diff_size.positive? and output_width > winwidth lines, _ = Reline::Unicode.split_by_width(str, winwidth - diff_size - 3) str = "%s..." % lines.first str += "\e[0m" if @context.use_colorize end end end if multiline_p && @context.newline_before_multiline_output? printf @context.return_format, "\n#{str}" else printf @context.return_format, str end end
#prompt(prompt, ltype, indent, line_no)
# File 'lib/irb.rb', line 776
def prompt(prompt, ltype, indent, line_no) # :nodoc: p = prompt.dup p.gsub!(/%([0-9]+)?([a-zA-Z])/) do case $2 when "N" @context.irb_name when "m" @context.main.to_s when "M" @context.main.inspect when "l" ltype when "i" if indent < 0 if $1 "-".rjust($1.to_i) else "-" end else if $1 format("%" + $1 + "d", indent) else indent.to_s end end when "n" if $1 format("%" + $1 + "d", line_no) else line_no.to_s end when "%" "%" end end p end
#run(conf = IRB.conf)
[ GitHub ]#signal_handle
Handler for the signal SIGINT, see Kernel.trap
for more information.
See additional method definition at file lib/irb.rb line 742.
# File 'lib/irb/ext/multi-irb.rb', line 238
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)
Evaluates the given block using the given status
.
# File 'lib/irb.rb', line 764
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)
[ GitHub ]#suspend_input_method(input_method)
Evaluates the given block using the given input_method
as the Context#io.
Used by the irb commands source
and irb_load
, see IRB@IRB+Sessions for more information.
# File 'lib/irb.rb', line 721
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)
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@IRB+Sessions for more information.
# File 'lib/irb.rb', line 691
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)
Evaluates the given block using the given workspace
as the Context#workspace.
Used by the irb command irb_load
, see IRB@IRB+Sessions for more information.
# File 'lib/irb.rb', line 707
def suspend_workspace(workspace) @context.workspace, back_workspace = workspace, @context.workspace begin yield back_workspace ensure @context.workspace = back_workspace end end