diff --git a/lib/irb.rb b/lib/irb.rb
index ba12bdbcab..a7e7944cc4 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -750,8 +750,8 @@ class Binding
#
# Potato.new
#
- # Running ruby potato.rb
will open an IRB session where
- # +binding.irb+ is called, and you will see the following:
+ # Running +ruby potato.rb+ will open an IRB session where +binding.irb+ is
+ # called, and you will see the following:
#
# $ ruby potato.rb
#
@@ -781,7 +781,7 @@ class Binding
# irb(#):004:0> @cooked = true
# => true
#
- # You can exit the IRB session with the +exit+ command. Note that exiting will
+ # You can exit the IRB session with the `exit` command. Note that exiting will
# resume execution where +binding.irb+ had paused it, as you can see from the
# output printed to standard output in this example:
#
diff --git a/lib/irb/cmd/fork.rb b/lib/irb/cmd/fork.rb
index 31d53dcaba..ae4d51b5d1 100644
--- a/lib/irb/cmd/fork.rb
+++ b/lib/irb/cmd/fork.rb
@@ -21,7 +21,7 @@ module IRB
class << self
alias_method :exit, ExtendCommand.irb_original_method_name('exit')
end
- if block_given?
+ if iterator?
begin
yield
ensure
diff --git a/lib/irb/color.rb b/lib/irb/color.rb
index 9606c7b68c..2e7a3e8bab 100644
--- a/lib/irb/color.rb
+++ b/lib/irb/color.rb
@@ -17,24 +17,28 @@ module IRB # :nodoc:
on_const: ['ENV'],
}
- TOKEN_SEQ_EXPRS = {
- on_CHAR: [[BLUE, BOLD], [Ripper::EXPR_END]],
- on_const: [[BLUE, BOLD, UNDERLINE], [Ripper::EXPR_ARG, Ripper::EXPR_CMDARG]],
- on_embexpr_beg: [[RED], [Ripper::EXPR_BEG, Ripper::EXPR_END]],
- on_embexpr_end: [[RED], [Ripper::EXPR_END, Ripper::EXPR_ENDFN]],
- on_ident: [[BLUE, BOLD], [Ripper::EXPR_ENDFN]],
- on_int: [[BLUE, BOLD], [Ripper::EXPR_END]],
- on_float: [[MAGENTA, BOLD], [Ripper::EXPR_END]],
- on_kw: [[GREEN], [Ripper::EXPR_ARG, Ripper::EXPR_CLASS, Ripper::EXPR_BEG, Ripper::EXPR_END, Ripper::EXPR_FNAME]],
- on_label: [[MAGENTA], [Ripper::EXPR_LABELED]],
- on_qwords_beg: [[RED], [Ripper::EXPR_BEG]],
- on_regexp_beg: [[RED, BOLD], [Ripper::EXPR_BEG]],
- on_regexp_end: [[RED, BOLD], [Ripper::EXPR_BEG]],
- on_symbeg: [[BLUE, BOLD], [Ripper::EXPR_FNAME]],
- on_tstring_beg: [[RED], [Ripper::EXPR_BEG, Ripper::EXPR_END, Ripper::EXPR_ARG, Ripper::EXPR_CMDARG]],
- on_tstring_content: [[RED], [Ripper::EXPR_BEG, Ripper::EXPR_ARG, Ripper::EXPR_CMDARG]],
- on_tstring_end: [[RED], [Ripper::EXPR_END]],
- }
+ begin
+ TOKEN_SEQ_EXPRS = {
+ on_CHAR: [[BLUE, BOLD], [Ripper::EXPR_END]],
+ on_const: [[BLUE, BOLD, UNDERLINE], [Ripper::EXPR_ARG, Ripper::EXPR_CMDARG]],
+ on_embexpr_beg: [[RED], [Ripper::EXPR_BEG, Ripper::EXPR_END]],
+ on_embexpr_end: [[RED], [Ripper::EXPR_END, Ripper::EXPR_ENDFN]],
+ on_ident: [[BLUE, BOLD], [Ripper::EXPR_ENDFN]],
+ on_int: [[BLUE, BOLD], [Ripper::EXPR_END]],
+ on_float: [[MAGENTA, BOLD], [Ripper::EXPR_END]],
+ on_kw: [[GREEN], [Ripper::EXPR_ARG, Ripper::EXPR_CLASS, Ripper::EXPR_BEG, Ripper::EXPR_END, Ripper::EXPR_FNAME]],
+ on_label: [[MAGENTA], [Ripper::EXPR_LABELED]],
+ on_qwords_beg: [[RED], [Ripper::EXPR_BEG]],
+ on_regexp_beg: [[RED, BOLD], [Ripper::EXPR_BEG]],
+ on_regexp_end: [[RED, BOLD], [Ripper::EXPR_BEG]],
+ on_symbeg: [[BLUE, BOLD], [Ripper::EXPR_FNAME]],
+ on_tstring_beg: [[RED], [Ripper::EXPR_BEG, Ripper::EXPR_END, Ripper::EXPR_ARG, Ripper::EXPR_CMDARG]],
+ on_tstring_content: [[RED], [Ripper::EXPR_BEG, Ripper::EXPR_ARG, Ripper::EXPR_CMDARG]],
+ on_tstring_end: [[RED], [Ripper::EXPR_END]],
+ }
+ rescue NameError
+ TOKEN_SEQ_EXPRS = {}
+ end
class << self
def colorable?
@@ -85,7 +89,7 @@ module IRB # :nodoc:
[BLUE, BOLD]
elsif TOKEN_KEYWORDS.fetch(token, []).include?(str)
[CYAN, BOLD]
- elsif (seq, exprs = TOKEN_SEQ_EXPRS[token]; exprs&.any? { |e| (expr & e) != Ripper::EXPR_NONE })
+ elsif (seq, exprs = TOKEN_SEQ_EXPRS[token]; exprs&.any? { |e| (expr & e) != 0 })
seq
else
nil
diff --git a/lib/irb/irb.gemspec b/lib/irb/irb.gemspec
index 57a44fecb7..d16d6b0ecc 100644
--- a/lib/irb/irb.gemspec
+++ b/lib/irb/irb.gemspec
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/ruby/irb"
spec.license = "BSD-2-Clause"
- spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "exe/irb", "irb.gemspec", "lib/irb.rb", "lib/irb/cmd/chws.rb", "lib/irb/cmd/fork.rb", "lib/irb/cmd/help.rb", "lib/irb/cmd/load.rb", "lib/irb/cmd/nop.rb", "lib/irb/cmd/pushws.rb", "lib/irb/cmd/subirb.rb", "lib/irb/completion.rb", "lib/irb/context.rb", "lib/irb/ext/change-ws.rb", "lib/irb/ext/history.rb", "lib/irb/ext/loader.rb", "lib/irb/ext/multi-irb.rb", "lib/irb/ext/save-history.rb", "lib/irb/ext/tracer.rb", "lib/irb/ext/use-loader.rb", "lib/irb/ext/workspaces.rb", "lib/irb/extend-command.rb", "lib/irb/frame.rb", "lib/irb/help.rb", "lib/irb/init.rb", "lib/irb/input-method.rb", "lib/irb/inspector.rb", "lib/irb/lc/.document", "lib/irb/lc/error.rb", "lib/irb/lc/help-message", "lib/irb/lc/ja/encoding_aliases.rb", "lib/irb/lc/ja/error.rb", "lib/irb/lc/ja/help-message", "lib/irb/locale.rb", "lib/irb/magic-file.rb", "lib/irb/notifier.rb", "lib/irb/output-method.rb", "lib/irb/ruby-lex.rb", "lib/irb/ruby-token.rb", "lib/irb/slex.rb", "lib/irb/src_encoding.rb", "lib/irb/version.rb", "lib/irb/workspace.rb", "lib/irb/ws-for-case-2.rb", "lib/irb/xmp.rb"]
+ spec.files = ["LICENSE.txt", "README.md", "exe/irb", "irb.gemspec", "lib/irb.rb", "lib/irb/cmd/chws.rb", "lib/irb/cmd/fork.rb", "lib/irb/cmd/help.rb", "lib/irb/cmd/load.rb", "lib/irb/cmd/nop.rb", "lib/irb/cmd/pushws.rb", "lib/irb/cmd/subirb.rb", "lib/irb/completion.rb", "lib/irb/context.rb", "lib/irb/ext/change-ws.rb", "lib/irb/ext/history.rb", "lib/irb/ext/loader.rb", "lib/irb/ext/multi-irb.rb", "lib/irb/ext/save-history.rb", "lib/irb/ext/tracer.rb", "lib/irb/ext/use-loader.rb", "lib/irb/ext/workspaces.rb", "lib/irb/extend-command.rb", "lib/irb/frame.rb", "lib/irb/help.rb", "lib/irb/init.rb", "lib/irb/input-method.rb", "lib/irb/inspector.rb", "lib/irb/lc/.document", "lib/irb/lc/error.rb", "lib/irb/lc/help-message", "lib/irb/lc/ja/encoding_aliases.rb", "lib/irb/lc/ja/error.rb", "lib/irb/lc/ja/help-message", "lib/irb/locale.rb", "lib/irb/magic-file.rb", "lib/irb/notifier.rb", "lib/irb/output-method.rb", "lib/irb/ruby-lex.rb", "lib/irb/ruby-token.rb", "lib/irb/slex.rb", "lib/irb/src_encoding.rb", "lib/irb/version.rb", "lib/irb/workspace.rb", "lib/irb/ws-for-case-2.rb", "lib/irb/xmp.rb"]
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
diff --git a/lib/irb/workspace.rb b/lib/irb/workspace.rb
index ff8f5da64f..bee59b9c3f 100644
--- a/lib/irb/workspace.rb
+++ b/lib/irb/workspace.rb
@@ -49,7 +49,7 @@ EOF
@binding = BINDING_QUEUE.pop
when 3 # binding in function on TOPLEVEL_BINDING(default)
- @binding = eval("self.class.remove_method(:irb_binding) if defined?(irb_binding); def irb_binding; private; binding; end; irb_binding",
+ @binding = eval("def irb_binding; private; binding; end; irb_binding",
TOPLEVEL_BINDING,
__FILE__,
__LINE__ - 3)
@@ -116,7 +116,11 @@ EOF
end
def code_around_binding
- file, pos = @binding.source_location
+ if @binding.respond_to?(:source_location)
+ file, pos = @binding.source_location
+ else
+ file, pos = @binding.eval('[__FILE__, __LINE__]')
+ end
if defined?(::SCRIPT_LINES__[file]) && lines = ::SCRIPT_LINES__[file]
code = ::SCRIPT_LINES__[file].join('')
diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb
index 4b1878545e..8439fd54f5 100644
--- a/test/irb/test_color.rb
+++ b/test/irb/test_color.rb
@@ -15,6 +15,11 @@ module TestIRB
CYAN = "\e[36m"
def test_colorize_code
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.5.0')
+ assert_equal({}, IRB::Color::TOKEN_SEQ_EXPRS)
+ skip "this Ripper version is not supported"
+ end
+
{
"1" => "#{BLUE}#{BOLD}1#{CLEAR}",
"2.3" => "#{MAGENTA}#{BOLD}2.3#{CLEAR}",
@@ -23,11 +28,22 @@ module TestIRB
"def self.foo; bar; end" => "#{GREEN}def#{CLEAR} #{CYAN}#{BOLD}self#{CLEAR}.#{BLUE}#{BOLD}foo#{CLEAR}; bar; #{GREEN}end#{CLEAR}",
'ERB.new("a#{nil}b", trim_mode: "-")' => "#{BLUE}#{BOLD}#{UNDERLINE}ERB#{CLEAR}.new(#{RED}\"#{CLEAR}#{RED}a#{CLEAR}#{RED}\#{#{CLEAR}#{CYAN}#{BOLD}nil#{CLEAR}#{RED}}#{CLEAR}#{RED}b#{CLEAR}#{RED}\"#{CLEAR}, #{MAGENTA}trim_mode:#{CLEAR} #{RED}\"#{CLEAR}#{RED}-#{CLEAR}#{RED}\"#{CLEAR})",
"# comment" => "#{BLUE}#{BOLD}# comment#{CLEAR}",
- '/r#{e}g/' => "#{RED}#{BOLD}/#{CLEAR}#{RED}r#{CLEAR}#{RED}\#{#{CLEAR}e}#{RED}g#{CLEAR}#{RED}#{BOLD}/#{CLEAR}",
"yield(hello)" => "#{GREEN}yield#{CLEAR}(hello)",
}.each do |code, result|
assert_equal(result, with_term { IRB::Color.colorize_code(code) })
end
+
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6.0')
+ {
+ '/r#{e}g/' => "#{RED}#{BOLD}/#{CLEAR}#{RED}r#{CLEAR}#{RED}\#{#{CLEAR}e}#{RED}g#{CLEAR}#{RED}#{BOLD}/#{CLEAR}",
+ }
+ else
+ {
+ '/r#{e}g/' => "#{RED}#{BOLD}/#{CLEAR}#{RED}r#{CLEAR}#{RED}\#{#{CLEAR}e#{RED}}#{CLEAR}#{RED}g#{CLEAR}#{RED}#{BOLD}/#{CLEAR}",
+ }
+ end.each do |code, result|
+ assert_equal(result, with_term { IRB::Color.colorize_code(code) })
+ end
end
def test_inspect_colorable
diff --git a/test/irb/test_completion.rb b/test/irb/test_completion.rb
new file mode 100644
index 0000000000..608c41bad9
--- /dev/null
+++ b/test/irb/test_completion.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: false
+require 'test/unit'
+
+module TestIRB
+ class TestCompletion < Test::Unit::TestCase
+ def test_nonstring_module_name
+ begin
+ require "irb/completion"
+ bug5938 = '[ruby-core:42244]'
+ cmds = %W[-rirb -rirb/completion -e IRB.setup(__FILE__)
+ -e IRB.conf[:MAIN_CONTEXT]=IRB::Irb.new.context
+ -e module\sFoo;def\sself.name;//;end;end
+ -e IRB::InputCompletor::CompletionProc.call("[1].first.")
+ -- -f --]
+ status = assert_in_out_err(cmds, "", //, [], bug5938)
+ assert(status.success?, bug5938)
+ rescue LoadError
+ skip "cannot load irb/completion"
+ end
+ end
+ end
+end
diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb
index 469599c11b..fa2432b3f3 100644
--- a/test/irb/test_context.rb
+++ b/test/irb/test_context.rb
@@ -55,7 +55,6 @@ module TestIRB
end
def test_eval_input
- verbose, $VERBOSE = $VERBOSE, nil
input = TestInputMethod.new([
"raise 'Foo'\n",
"_\n",
@@ -72,8 +71,6 @@ module TestIRB
:*, /0$/,
:*, /0$/,
/\s*/], out)
- ensure
- $VERBOSE = verbose
end
end
end
diff --git a/test/irb/test_raise_no_backtrace_exception.rb b/test/irb/test_raise_no_backtrace_exception.rb
index 72e82bf7f7..d3882a427c 100644
--- a/test/irb/test_raise_no_backtrace_exception.rb
+++ b/test/irb/test_raise_no_backtrace_exception.rb
@@ -4,7 +4,7 @@ require 'test/unit'
module TestIRB
class TestRaiseNoBacktraceException < Test::Unit::TestCase
def test_raise_exception
- assert_in_out_err(%w[-rirb -W1 -e IRB.start(__FILE__) -- -f --], <<-IRB, /Exception: foo/, [], success: true)
+ status = assert_in_out_err(%w[-rirb -e IRB.start(__FILE__) -- -f --], <<-IRB, /Exception: foo/, [])
e = Exception.new("foo")
def e.backtrace; nil; end
raise e
diff --git a/test/irb/test_ruby-lex.rb b/test/irb/test_ruby-lex.rb
new file mode 100644
index 0000000000..b07b4a2eb6
--- /dev/null
+++ b/test/irb/test_ruby-lex.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: false
+require 'test/unit'
+require 'irb/ruby-lex'
+require 'stringio'
+
+module TestIRB
+ class TestRubyLex < Test::Unit::TestCase
+ def setup
+ @scanner = RubyLex.new
+ end
+
+ def teardown
+ RubyLex.debug_level = 0
+ end
+
+ def test_set_input_proc
+ called = false
+ @scanner.set_input(nil) {called = true; nil}
+ @scanner.each_top_level_statement {}
+ assert(called)
+ end
+
+ def test_comment
+ assert_equal([["#\n", 1]], top_level_statement("#\n"))
+ end
+
+ def test_top_level_statement
+ result = top_level_statement("#{<<-"begin;"}#{<<~"end;"}")
+ begin;
+ begin
+ end
+ begin
+ end
+ end;
+ assert_equal([
+ ["begin\n""end\n", 1],
+ ["begin\n""end\n", 3],
+ ],
+ result)
+ end
+
+ def test_immature_statement
+ src = "if false\n"
+ assert_equal([[src, 1]], top_level_statement(src))
+ end
+
+ def test_prompt
+ prompts = []
+ @scanner.set_prompt {|*a|
+ a << @scanner.instance_variable_get(:@lex_state)
+ unless prompts.last == a
+ prompts << a
+ end
+ }
+ src, lineno = "#{<<-"begin;"}#{<<~'end;'}", __LINE__+1
+ begin;
+ # #;# LTYPE:INDENT:CONTINUE
+ x #;# -:0:-
+ x( #;# -:0:-
+ ) #;# -:1:*
+ a \ #;# -:0:-
+ #;# -:0:*
+ a; #;# -:0:-
+ a #;# -:0:-
+ #;# -:0:-
+ a #;# -:0:-
+ a = #;# -:0:-
+ ' #;# -:0:*
+ ' #;# ':0:*
+ if false or #;# -:0:-
+ true #;# -:1:*
+ a #;# -:1:-
+ " #;# -:1:-
+ " #;# ":1:-
+ begin #;# -:1:-
+ a #;# -:2:-
+ a #;# -:2:-
+ end #;# -:2:-
+ else #;# -:1:-
+ nil #;# -:1:-
+ end #;# -:1:-
+ end;
+ top_level_statement(src.gsub(/[ \t]*#;#.*/, ''))
+ src.each_line.with_index(1) do |line, i|
+ p = prompts.shift
+ next unless /#;#\s*(?:-|(?\S)):(?\d+):(?:(?\*)|-)(?:.*FIXME:(?.*))?/ =~ line
+ indent = indent.to_i
+ cont = (fixme && /`continue'/.match?(fixme)) ^ cont
+ assert_equal([ltype, indent, cont, i], p[0..3], "#{lineno+i}:#{p[4]}: #{line}")
+ end
+ end
+
+ def top_level_statement(lines)
+ input = InputLines.new(lines, "r")
+ scanned = []
+ @scanner.set_input(input)
+ @scanner.each_top_level_statement {|*e|
+ scanned << e
+ yield(*e) if defined?(yield)
+ }
+ scanned
+ end
+
+ class InputLines < StringIO
+ alias encoding external_encoding
+ end
+ end
+end
diff --git a/test/irb/test_workspace.rb b/test/irb/test_workspace.rb
index 9c87468cf7..fe63c3c225 100644
--- a/test/irb/test_workspace.rb
+++ b/test/irb/test_workspace.rb
@@ -7,7 +7,7 @@ require 'irb/color'
module TestIRB
class TestWorkSpace < Test::Unit::TestCase
def test_code_around_binding
- Tempfile.create do |f|
+ Tempfile.create('irb') do |f|
code = <<~RUBY
# 1
# 2
@@ -37,7 +37,7 @@ module TestIRB
skip 'chmod cannot make file unreadable on windows' if windows?
skip 'skipped in root privilege' if Process.uid == 0
- Tempfile.create do |f|
+ Tempfile.create('irb') do |f|
code = "IRB::WorkSpace.new(binding)\n"
f.print(code)
f.close
@@ -51,7 +51,7 @@ module TestIRB
def test_code_around_binding_with_script_lines__
with_script_lines do |script_lines|
- Tempfile.create do |f|
+ Tempfile.create('irb') do |f|
code = "IRB::WorkSpace.new(binding)\n"
script_lines[f.path] = code.split(/^/)