Creates a new irb session
# File irb.rb, line 454
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 766
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 484
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'
@context.evaluate(line, line_no, exception: exc)
output_value if @context.echo? && (@context.echo_on_assignment? || !assignment_expression?(line))
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 555
def handle_exception(exc)
if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
!(SyntaxError === exc)
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 751
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 461
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 666
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 688
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 656
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
IRB::Context#io.
Used by the irb commands source and irb_load, see
IRB Sessions at IRB for more information.
# File irb.rb, line 645
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 IRB::Context#irb_path and
name as the IRB::Context#irb_name.
Used by the irb command source, see IRB Sessions at IRB for
more information.
# File irb.rb, line 615
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 IRB::Context#workspace.
Used by the irb command irb_load, see IRB Sessions at IRB for
more information.
# File irb.rb, line 631
def suspend_workspace(workspace)
@context.workspace, back_workspace = workspace, @context.workspace
begin
yield back_workspace
ensure
@context.workspace = back_workspace
end
end