lib/irb.rb in irb-1.1.0.pre.2 vs lib/irb.rb in irb-1.1.0.pre.3
- old
+ new
@@ -8,10 +8,11 @@
# --
#
#
#
require "e2mmap"
+require "ripper"
require "irb/init"
require "irb/context"
require "irb/extend-command"
@@ -408,10 +409,39 @@
raise exception, "abort then interrupt!"
end
end
class Irb
+ ASSIGNMENT_NODE_TYPES = [
+ # 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,
+ ]
+ # Note: instance and index assignment expressions could also be written like:
+ # "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former
+ # be parsed as :assign and echo will be suppressed, but the latter is
+ # parsed as a :method_add_arg and the output won't be suppressed
+
# Creates a new irb session
def initialize(workspace = nil, input_method = nil, output_method = nil)
@context = Context.new(self, workspace, input_method, output_method)
@context.main.extend ExtendCommandBundle
@signal_status = :IN_IRB
@@ -496,11 +526,11 @@
@scanner.each_top_level_statement do |line, line_no|
signal_status(:IN_EVAL) do
begin
line.untaint
@context.evaluate(line, line_no, exception: exc)
- output_value if @context.echo?
+ output_value if @context.echo? && (@context.echo_on_assignment? || !assignment_expression?(line))
rescue Interrupt => exc
rescue SystemExit, SignalException
raise
rescue Exception => exc
else
@@ -715,10 +745,22 @@
end
end
format("#<%s: %s>", self.class, ary.join(", "))
end
+ 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.
+ ASSIGNMENT_NODE_TYPES.include?(Ripper.sexp(line)&.dig(1,-1,0))
+ end
+
ATTR_TTY = "\e[%sm"
def ATTR_TTY.[](*a) self % a.join(";"); end
ATTR_PLAIN = ""
def ATTR_PLAIN.[](*) self; end
end
@@ -803,10 +845,10 @@
# Cooked potato: true
#
#
# See IRB@IRB+Usage for more information.
def irb
- IRB.setup(eval("__FILE__"), argv: [])
+ IRB.setup(source_location[0], argv: [])
workspace = IRB::WorkSpace.new(self)
STDOUT.print(workspace.code_around_binding)
IRB::Irb.new(workspace).run(IRB.conf)
end
end