aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraycabta <aycabta@gmail.com>2020-09-16 11:19:17 +0900
committernagachika <nagachika@ruby-lang.org>2020-09-16 21:08:31 +0900
commit2159798f4c0f71007db733cddd82b99186c8e424 (patch)
tree4e79977d4c6cbc84221d06adad3acfb4234cc911
parent3bb503e0e8f92c039ce50f430b14649a36c03feb (diff)
downloadruby-2159798f4c0f71007db733cddd82b99186c8e424.tar.gz
Merge IRB 1.2.6
-rw-r--r--lib/irb.rb58
-rw-r--r--lib/irb/cmd/fork.rb2
-rw-r--r--lib/irb/cmd/info.rb24
-rw-r--r--lib/irb/cmd/pushws.rb1
-rw-r--r--lib/irb/color.rb44
-rw-r--r--lib/irb/completion.rb17
-rw-r--r--lib/irb/context.rb32
-rw-r--r--lib/irb/ext/change-ws.rb1
-rw-r--r--lib/irb/ext/history.rb2
-rw-r--r--lib/irb/ext/loader.rb1
-rw-r--r--lib/irb/ext/save-history.rb13
-rw-r--r--lib/irb/ext/tracer.rb1
-rw-r--r--lib/irb/ext/use-loader.rb4
-rw-r--r--lib/irb/ext/workspaces.rb1
-rw-r--r--lib/irb/extend-command.rb13
-rw-r--r--lib/irb/help.rb1
-rw-r--r--lib/irb/init.rb14
-rw-r--r--lib/irb/input-method.rb61
-rw-r--r--lib/irb/inspector.rb6
-rw-r--r--lib/irb/irb.gemspec4
-rw-r--r--lib/irb/ruby-lex.rb119
-rw-r--r--lib/irb/ruby_logo.aa1
-rw-r--r--lib/irb/version.rb4
-rw-r--r--lib/irb/xmp.rb2
-rw-r--r--test/irb/test_cmd.rb127
-rw-r--r--test/irb/test_context.rb176
-rw-r--r--test/irb/test_history.rb153
-rw-r--r--test/irb/test_ruby_lex.rb136
-rw-r--r--test/irb/test_workspace.rb1
29 files changed, 913 insertions, 106 deletions
diff --git a/lib/irb.rb b/lib/irb.rb
index ee6979c6d0..d8e1209f2c 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -10,18 +10,19 @@
#
#
require "ripper"
+require "reline"
-require "irb/init"
-require "irb/context"
-require "irb/extend-command"
+require_relative "irb/init"
+require_relative "irb/context"
+require_relative "irb/extend-command"
-require "irb/ruby-lex"
-require "irb/input-method"
-require "irb/locale"
-require "irb/color"
+require_relative "irb/ruby-lex"
+require_relative "irb/input-method"
+require_relative "irb/locale"
+require_relative "irb/color"
-require "irb/version"
-require "irb/easter-egg"
+require_relative "irb/version"
+require_relative "irb/easter-egg"
# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
# expressions read from the standard input.
@@ -271,7 +272,7 @@ require "irb/easter-egg"
# On the other hand, each conf in IRB@Command+line+options is used to
# individually configure IRB.irb.
#
-# If a proc is set for IRB.conf[:IRB_RC], its will be invoked after execution
+# If a proc is set for <code>IRB.conf[:IRB_RC]</code>, its will be invoked after execution
# of that proc with the context of the current session as its argument. Each
# session can be configured using this mechanism.
#
@@ -399,7 +400,7 @@ module IRB
irb.run(@CONF)
end
- # Calls each event hook of IRB.conf[:AT_EXIT] when the current session quits.
+ # Calls each event hook of <code>IRB.conf[:TA_EXIT]</code> when the current session quits.
def IRB.irb_at_exit
@CONF[:AT_EXIT].each{|hook| hook.call}
end
@@ -538,7 +539,15 @@ module IRB
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))
+ if @context.echo?
+ if assignment_expression?(line)
+ if @context.echo_on_assignment?
+ output_value(@context.omit_on_assignment?)
+ end
+ else
+ output_value
+ end
+ end
rescue Interrupt => exc
rescue SystemExit, SignalException
raise
@@ -737,9 +746,32 @@ module IRB
p
end
- def output_value # :nodoc:
+ 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...\e[0m" % lines.first
+ multiline_p = false
+ else
+ str.gsub!(/(\A.*?\n).*/m, "\\1...")
+ 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...\e[0m" % lines.first
+ end
+ end
+ end
if multiline_p && @context.newline_before_multiline_output?
printf @context.return_format, "\n#{str}"
else
diff --git a/lib/irb/cmd/fork.rb b/lib/irb/cmd/fork.rb
index 31d53dcaba..19c78fc910 100644
--- a/lib/irb/cmd/fork.rb
+++ b/lib/irb/cmd/fork.rb
@@ -35,5 +35,3 @@ module IRB
end
end
# :startdoc:
-
-
diff --git a/lib/irb/cmd/info.rb b/lib/irb/cmd/info.rb
new file mode 100644
index 0000000000..53ec71d754
--- /dev/null
+++ b/lib/irb/cmd/info.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: false
+
+require_relative "nop"
+
+# :stopdoc:
+module IRB
+ module ExtendCommand
+ class Info < Nop
+ def execute
+ Class.new {
+ def inspect
+ str = "Ruby version: #{RUBY_VERSION}\n"
+ str += "IRB version: #{IRB.version}\n"
+ str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
+ str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
+ str
+ end
+ alias_method :to_s, :inspect
+ }.new
+ end
+ end
+ end
+end
+# :startdoc:
diff --git a/lib/irb/cmd/pushws.rb b/lib/irb/cmd/pushws.rb
index 187b276e48..612157d8a0 100644
--- a/lib/irb/cmd/pushws.rb
+++ b/lib/irb/cmd/pushws.rb
@@ -38,4 +38,3 @@ module IRB
end
end
# :startdoc:
-
diff --git a/lib/irb/color.rb b/lib/irb/color.rb
index d2b9674a71..0f49291d85 100644
--- a/lib/irb/color.rb
+++ b/lib/irb/color.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'reline'
require 'ripper'
+require 'irb/ruby-lex'
module IRB # :nodoc:
module Color
@@ -145,37 +146,38 @@ module IRB # :nodoc:
seen.delete(obj)
end
- # Ripper::Lexer::Elem#state is supported on Ruby 2.5+
def supported?
return @supported if defined?(@supported)
- @supported = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
+ @supported = Ripper::Lexer::Elem.method_defined?(:state)
end
def scan(code, allow_last_error:)
pos = [1, 0]
verbose, $VERBOSE = $VERBOSE, nil
- lexer = Ripper::Lexer.new(code)
- if lexer.respond_to?(:scan) # Ruby 2.7+
- lexer.scan.each do |elem|
- str = elem.tok
- next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
- next if ([elem.pos[0], elem.pos[1] + str.bytesize] <=> pos) <= 0
-
- str.each_line do |line|
- if line.end_with?("\n")
- pos[0] += 1
- pos[1] = 0
- else
- pos[1] += line.bytesize
+ RubyLex.compile_with_errors_suppressed(code) do |inner_code, line_no|
+ lexer = Ripper::Lexer.new(inner_code, '(ripper)', line_no)
+ if lexer.respond_to?(:scan) # Ruby 2.7+
+ lexer.scan.each do |elem|
+ str = elem.tok
+ next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
+ next if ([elem.pos[0], elem.pos[1] + str.bytesize] <=> pos) <= 0
+
+ str.each_line do |line|
+ if line.end_with?("\n")
+ pos[0] += 1
+ pos[1] = 0
+ else
+ pos[1] += line.bytesize
+ end
end
- end
- yield(elem.event, str, elem.state)
- end
- else
- lexer.parse.each do |elem|
- yield(elem.event, elem.tok, elem.state)
+ yield(elem.event, str, elem.state)
+ end
+ else
+ lexer.parse.each do |elem|
+ yield(elem.event, elem.tok, elem.state)
+ end
end
end
$VERBOSE = verbose
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index c44aa9039e..c9328e5c5a 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -7,7 +7,6 @@
# From Original Idea of shugo@ruby-lang.org
#
-require "readline"
autoload :RDoc, "rdoc"
module IRB
@@ -97,17 +96,13 @@ module IRB
when /^(:[^:.]*)$/
# Symbol
return nil if doc_namespace
- if Symbol.respond_to?(:all_symbols)
- sym = $1
- candidates = Symbol.all_symbols.collect do |s|
- ":" + s.id2name.encode(Encoding.default_external)
- rescue Encoding::UndefinedConversionError
- # ignore
- end
- candidates.grep(/^#{Regexp.quote(sym)}/)
- else
- []
+ sym = $1
+ candidates = Symbol.all_symbols.collect do |s|
+ ":" + s.id2name.encode(Encoding.default_external)
+ rescue Encoding::UndefinedConversionError
+ # ignore
end
+ candidates.grep(/^#{Regexp.quote(sym)}/)
when /^::([A-Z][^:\.\(]*)$/
# Absolute Constant or class methods
diff --git a/lib/irb/context.rb b/lib/irb/context.rb
index 218f7c6037..4f001729e1 100644
--- a/lib/irb/context.rb
+++ b/lib/irb/context.rb
@@ -131,7 +131,12 @@ module IRB
@echo_on_assignment = IRB.conf[:ECHO_ON_ASSIGNMENT]
if @echo_on_assignment.nil?
- @echo_on_assignment = false
+ @echo_on_assignment = true
+ end
+
+ @omit_on_assignment = IRB.conf[:OMIT_ON_ASSIGNMENT]
+ if @omit_on_assignment.nil?
+ @omit_on_assignment = true
end
@newline_before_multiline_output = IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT]
@@ -240,7 +245,7 @@ module IRB
attr_accessor :ignore_eof
# Whether to echo the return value to output or not.
#
- # Uses IRB.conf[:ECHO] if available, or defaults to +true+.
+ # Uses <code>IRB.conf[:ECHO]</code> if available, or defaults to +true+.
#
# puts "hello"
# # hello
@@ -251,16 +256,30 @@ module IRB
attr_accessor :echo
# Whether to echo for assignment expressions
#
- # Uses IRB.conf[:ECHO_ON_ASSIGNMENT] if available, or defaults to +false+.
+ # Uses <code>IRB.conf[:ECHO_ON_ASSIGNMENT]</code> if available, or defaults to +true+.
#
# a = "omg"
- # IRB.CurrentContext.echo_on_assignment = true
- # a = "omg"
# #=> omg
+ # IRB.CurrentContext.echo_on_assignment = false
+ # a = "omg"
attr_accessor :echo_on_assignment
+ # Whether to omit echo for assignment expressions
+ #
+ # Uses <code>IRB.conf[:OMIT_ON_ASSIGNMENT]</code> if available, or defaults to +true+.
+ #
+ # a = [1] * 10
+ # #=> [1, 1, 1, 1, 1, 1, 1, 1, ...
+ # [1] * 10
+ # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
+ # IRB.CurrentContext.omit_on_assignment = false
+ # a = [1] * 10
+ # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
+ # [1] * 10
+ # #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
+ attr_accessor :omit_on_assignment
# Whether a newline is put before multiline output.
#
- # Uses IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] if available,
+ # Uses <code>IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT]</code> if available,
# or defaults to +true+.
#
# "abc\ndef"
@@ -306,6 +325,7 @@ module IRB
alias ignore_eof? ignore_eof
alias echo? echo
alias echo_on_assignment? echo_on_assignment
+ alias omit_on_assignment? omit_on_assignment
alias newline_before_multiline_output? newline_before_multiline_output
# Returns whether messages are displayed or not.
diff --git a/lib/irb/ext/change-ws.rb b/lib/irb/ext/change-ws.rb
index 94bfe62bc0..4c57e44eab 100644
--- a/lib/irb/ext/change-ws.rb
+++ b/lib/irb/ext/change-ws.rb
@@ -43,4 +43,3 @@ module IRB # :nodoc:
end
end
end
-
diff --git a/lib/irb/ext/history.rb b/lib/irb/ext/history.rb
index 30e3fb901f..fc304c6f6c 100644
--- a/lib/irb/ext/history.rb
+++ b/lib/irb/ext/history.rb
@@ -153,5 +153,3 @@ module IRB # :nodoc:
end
end
end
-
-
diff --git a/lib/irb/ext/loader.rb b/lib/irb/ext/loader.rb
index 840226db30..1b683d88e5 100644
--- a/lib/irb/ext/loader.rb
+++ b/lib/irb/ext/loader.rb
@@ -126,4 +126,3 @@ module IRB # :nodoc:
end
end
end
-
diff --git a/lib/irb/ext/save-history.rb b/lib/irb/ext/save-history.rb
index edc4f234cc..ac358c8ccb 100644
--- a/lib/irb/ext/save-history.rb
+++ b/lib/irb/ext/save-history.rb
@@ -9,8 +9,6 @@
#
#
-require "readline"
-
module IRB
module HistorySavingAbility # :nodoc:
end
@@ -27,7 +25,7 @@ module IRB
IRB.conf[:SAVE_HISTORY]
end
- remove_method :save_history= if method_defined?(:save_history=)
+ remove_method(:save_history=) if method_defined?(:save_history=)
# Sets <code>IRB.conf[:SAVE_HISTORY]</code> to the given +val+ and calls
# #init_save_history with this context.
#
@@ -89,7 +87,7 @@ module IRB
def save_history
return unless self.class.const_defined?(:HISTORY)
history = self.class::HISTORY
- if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) > 0
+ if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) != 0
if history_file = IRB.conf[:HISTORY_FILE]
history_file = File.expand_path(history_file)
end
@@ -109,7 +107,12 @@ module IRB
open(history_file, "w:#{IRB.conf[:LC_MESSAGES].encoding}", 0600) do |f|
hist = history.map{ |l| l.split("\n").join("\\\n") }
- f.puts(hist[-num..-1] || hist)
+ begin
+ hist = hist.last(num) if hist.size > num and num > 0
+ rescue RangeError # bignum too big to convert into `long'
+ # Do nothing because the bignum should be treated as inifinity
+ end
+ f.puts(hist)
end
end
end
diff --git a/lib/irb/ext/tracer.rb b/lib/irb/ext/tracer.rb
index e3e325e6e5..67ac4bb965 100644
--- a/lib/irb/ext/tracer.rb
+++ b/lib/irb/ext/tracer.rb
@@ -82,4 +82,3 @@ module IRB
IRB.initialize_tracer
end
-
diff --git a/lib/irb/ext/use-loader.rb b/lib/irb/ext/use-loader.rb
index cb10e8a254..1897bc89e0 100644
--- a/lib/irb/ext/use-loader.rb
+++ b/lib/irb/ext/use-loader.rb
@@ -47,7 +47,7 @@ module IRB
alias use_loader? use_loader
remove_method :use_loader= if method_defined?(:use_loader=)
- # Sets IRB.conf[:USE_LOADER]
+ # Sets <code>IRB.conf[:USE_LOADER]</code>
#
# See #use_loader for more information.
def use_loader=(opt)
@@ -73,5 +73,3 @@ module IRB
end
end
end
-
-
diff --git a/lib/irb/ext/workspaces.rb b/lib/irb/ext/workspaces.rb
index 5bd72c194f..730b58e64d 100644
--- a/lib/irb/ext/workspaces.rb
+++ b/lib/irb/ext/workspaces.rb
@@ -64,4 +64,3 @@ module IRB # :nodoc:
end
end
end
-
diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb
index de145e962d..2f4fcfb5c6 100644
--- a/lib/irb/extend-command.rb
+++ b/lib/irb/extend-command.rb
@@ -121,6 +121,10 @@ module IRB # :nodoc:
[:help, NO_OVERRIDE],
],
+ [
+ :irb_info, :Info, "irb/cmd/info"
+ ],
+
]
# Installs the default irb commands:
@@ -169,11 +173,14 @@ module IRB # :nodoc:
args << "&block"
args = args.join(", ")
line = __LINE__; eval %[
- def #{cmd_name}(\#{args})
- ExtendCommand::#{cmd_class}.execute(irb_context, \#{args})
+ unless self.class.class_variable_defined?(:@@#{cmd_name}_)
+ self.class.class_variable_set(:@@#{cmd_name}_, true)
+ def #{cmd_name}_(\#{args})
+ ExtendCommand::#{cmd_class}.execute(irb_context, \#{args})
+ end
end
], nil, __FILE__, line
- send :#{cmd_name}, *opts, &b
+ send :#{cmd_name}_, *opts, &b
end
], nil, __FILE__, line
else
diff --git a/lib/irb/help.rb b/lib/irb/help.rb
index 7868a70a6c..3eeaf841b0 100644
--- a/lib/irb/help.rb
+++ b/lib/irb/help.rb
@@ -34,4 +34,3 @@ module IRB
}
end
end
-
diff --git a/lib/irb/init.rb b/lib/irb/init.rb
index 37d1f8d609..44383609bd 100644
--- a/lib/irb/init.rb
+++ b/lib/irb/init.rb
@@ -52,6 +52,7 @@ module IRB # :nodoc:
@CONF[:IGNORE_EOF] = false
@CONF[:ECHO] = nil
@CONF[:ECHO_ON_ASSIGNMENT] = nil
+ @CONF[:OMIT_ON_ASSIGNMENT] = nil
@CONF[:VERBOSE] = nil
@CONF[:EVAL_HISTORY] = nil
@@ -177,6 +178,10 @@ module IRB # :nodoc:
@CONF[:ECHO_ON_ASSIGNMENT] = true
when "--noecho-on-assignment"
@CONF[:ECHO_ON_ASSIGNMENT] = false
+ when "--omit-on-assignment"
+ @CONF[:OMIT_ON_ASSIGNMENT] = true
+ when "--noomit-on-assignment"
+ @CONF[:OMIT_ON_ASSIGNMENT] = false
when "--verbose"
@CONF[:VERBOSE] = true
when "--noverbose"
@@ -271,10 +276,19 @@ module IRB # :nodoc:
if irbrc = ENV["IRBRC"]
yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc}
end
+ if xdg_config_home = ENV["XDG_CONFIG_HOME"]
+ irb_home = File.join(xdg_config_home, "irb")
+ unless File.exist? irb_home
+ require 'fileutils'
+ FileUtils.mkdir_p irb_home
+ end
+ yield proc{|rc| irb_home + "/irb#{rc}"}
+ end
if home = ENV["HOME"]
yield proc{|rc| home+"/.irb#{rc}"}
end
current_dir = Dir.pwd
+ yield proc{|rc| current_dir+"/.config/irb/irb#{rc}"}
yield proc{|rc| current_dir+"/.irb#{rc}"}
yield proc{|rc| current_dir+"/irb#{rc.sub(/\A_?/, '.')}"}
yield proc{|rc| current_dir+"/_irb#{rc}"}
diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb
index 9fbbaeb0f3..6e87488753 100644
--- a/lib/irb/input-method.rb
+++ b/lib/irb/input-method.rb
@@ -12,6 +12,7 @@
require_relative 'src_encoding'
require_relative 'magic-file'
require_relative 'completion'
+require 'io/console'
require 'reline'
module IRB
@@ -36,6 +37,14 @@ module IRB
end
public :gets
+ def winsize
+ if instance_variable_defined?(:@stdout)
+ @stdout.winsize
+ else
+ [24, 80]
+ end
+ end
+
# Whether this input method is still readable when there is no more data to
# read.
#
@@ -43,6 +52,11 @@ module IRB
def readable_after_eof?
false
end
+
+ # For debug message
+ def inspect
+ 'Abstract InputMethod'
+ end
end
class StdioInputMethod < InputMethod
@@ -93,6 +107,11 @@ module IRB
def encoding
@stdin.external_encoding
end
+
+ # For debug message
+ def inspect
+ 'StdioInputMethod'
+ end
end
# Use a File for IO with irb, see InputMethod
@@ -125,14 +144,25 @@ module IRB
def encoding
@io.external_encoding
end
+
+ # For debug message
+ def inspect
+ 'FileInputMethod'
+ end
end
begin
- require "readline"
class ReadlineInputMethod < InputMethod
- include Readline
+ def self.initialize_readline
+ require "readline"
+ rescue LoadError
+ else
+ include ::Readline
+ end
+
# Creates a new input method object using Readline
def initialize
+ self.class.initialize_readline
if Readline.respond_to?(:encoding_system_needs)
IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false)
end
@@ -197,13 +227,15 @@ module IRB
@stdin.external_encoding
end
- if Readline.respond_to?("basic_word_break_characters=")
- Readline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
+ # For debug message
+ def inspect
+ readline_impl = (defined?(Reline) && Readline == Reline) ? 'Reline' : 'ext/readline'
+ str = "ReadlineInputMethod with #{readline_impl} #{Readline::VERSION}"
+ inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc')
+ str += " and #{inputrc_path}" if File.exist?(inputrc_path)
+ str
end
- Readline.completion_append_character = nil
- Readline.completion_proc = IRB::InputCompletor::CompletionProc
end
- rescue LoadError
end
class ReidlineInputMethod < InputMethod
@@ -227,7 +259,7 @@ module IRB
Reline.completion_proc = IRB::InputCompletor::CompletionProc
Reline.output_modifier_proc =
if IRB.conf[:USE_COLORIZE]
- proc do |output, complete:|
+ proc do |output, complete: |
next unless IRB::Color.colorable?
IRB::Color.colorize_code(output, complete: complete)
end
@@ -297,5 +329,18 @@ module IRB
def encoding
@stdin.external_encoding
end
+
+ # For debug message
+ def inspect
+ config = Reline::Config.new
+ str = "ReidlineInputMethod with Reline #{Reline::VERSION}"
+ if config.respond_to?(:inputrc_path)
+ inputrc_path = File.expand_path(config.inputrc_path)
+ else
+ inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc')
+ end
+ str += " and #{inputrc_path}" if File.exist?(inputrc_path)
+ str
+ end
end
end
diff --git a/lib/irb/inspector.rb b/lib/irb/inspector.rb
index bc7fb0b125..671b32b6e8 100644
--- a/lib/irb/inspector.rb
+++ b/lib/irb/inspector.rb
@@ -113,6 +113,7 @@ module IRB # :nodoc:
result
rescue NoMethodError
puts "(Object doesn't support #inspect)"
+ ''
end
}
Inspector.def_inspector([:pp, :pretty_inspect], proc{require "pp"}){|v|
@@ -135,8 +136,3 @@ module IRB # :nodoc:
Marshal.dump(v)
}
end
-
-
-
-
-
diff --git a/lib/irb/irb.gemspec b/lib/irb/irb.gemspec
index 658fe813f1..af40a32452 100644
--- a/lib/irb/irb.gemspec
+++ b/lib/irb/irb.gemspec
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
spec.summary = %q{Interactive Ruby command-line tool for REPL (Read Eval Print Loop).}
spec.description = %q{Interactive Ruby command-line tool for REPL (Read Eval Print Loop).}
spec.homepage = "https://github.com/ruby/irb"
- spec.license = "BSD-2-Clause"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.files = [
".document",
@@ -78,7 +78,7 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = Gem::Requirement.new(">= 2.5")
- spec.add_dependency "reline", ">= 0.0.1"
+ spec.add_dependency "reline", ">= 0.1.5"
spec.add_development_dependency "bundler"
spec.add_development_dependency "rake"
end
diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb
index d5630c8b52..7be77fd12e 100644
--- a/lib/irb/ruby-lex.rb
+++ b/lib/irb/ruby-lex.rb
@@ -11,6 +11,7 @@
#
require "ripper"
+require "jruby" if RUBY_ENGINE == "jruby"
# :stopdoc:
class RubyLex
@@ -29,6 +30,18 @@ class RubyLex
@prompt = nil
end
+ def self.compile_with_errors_suppressed(code)
+ line_no = 1
+ begin
+ result = yield code, line_no
+ rescue ArgumentError
+ code = ";\n#{code}"
+ line_no = 0
+ result = yield code, line_no
+ end
+ result
+ end
+
# io functions
def set_input(io, p = nil, &block)
@io = io
@@ -75,7 +88,10 @@ class RubyLex
def ripper_lex_without_warning(code)
verbose, $VERBOSE = $VERBOSE, nil
- tokens = Ripper.lex(code)
+ tokens = nil
+ self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
+ tokens = Ripper.lex(inner_code, '-', line_no)
+ end
$VERBOSE = verbose
tokens
end
@@ -209,7 +225,9 @@ class RubyLex
when 'jruby'
JRuby.compile_ir(code)
else
- RubyVM::InstructionSequence.compile(code)
+ self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
+ RubyVM::InstructionSequence.compile(inner_code, nil, nil, line_no)
+ end
end
rescue EncodingError
# This is for a hash with invalid encoding symbol, {"\xAE": 1}
@@ -285,9 +303,33 @@ class RubyLex
def process_nesting_level
indent = 0
+ in_oneliner_def = nil
@tokens.each_with_index { |t, index|
+ # detecting one-liner method definition
+ if in_oneliner_def.nil?
+ if t[3].allbits?(Ripper::EXPR_ENDFN)
+ in_oneliner_def = :ENDFN
+ end
+ else
+ if t[3].allbits?(Ripper::EXPR_ENDFN)
+ # continuing
+ elsif t[3].allbits?(Ripper::EXPR_BEG)
+ if t[2] == '='
+ in_oneliner_def = :BODY
+ end
+ elsif t[3].allbits?(Ripper::EXPR_END)
+ if in_oneliner_def == :BODY
+ # one-liner method definition
+ indent -= 1
+ end
+ in_oneliner_def = nil
+ else
+ in_oneliner_def = nil
+ end
+ end
+
case t[1]
- when :on_lbracket, :on_lbrace, :on_lparen
+ when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
indent += 1
when :on_rbracket, :on_rbrace, :on_rparen
indent -= 1
@@ -306,7 +348,7 @@ class RubyLex
when 'def', 'case', 'for', 'begin', 'class', 'module'
indent += 1
when 'if', 'unless', 'while', 'until'
- # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
+ # postfix if/unless/while/until must be Ripper::EXPR_LABEL
indent += 1 unless t[3].allbits?(Ripper::EXPR_LABEL)
when 'end'
indent -= 1
@@ -320,7 +362,31 @@ class RubyLex
def check_newline_depth_difference
depth_difference = 0
open_brace_on_line = 0
+ in_oneliner_def = nil
@tokens.each_with_index do |t, index|
+ # detecting one-liner method definition
+ if in_oneliner_def.nil?
+ if t[3].allbits?(Ripper::EXPR_ENDFN)
+ in_oneliner_def = :ENDFN
+ end
+ else
+ if t[3].allbits?(Ripper::EXPR_ENDFN)
+ # continuing
+ elsif t[3].allbits?(Ripper::EXPR_BEG)
+ if t[2] == '='
+ in_oneliner_def = :BODY
+ end
+ elsif t[3].allbits?(Ripper::EXPR_END)
+ if in_oneliner_def == :BODY
+ # one[-liner method definition
+ depth_difference -= 1
+ end
+ in_oneliner_def = nil
+ else
+ in_oneliner_def = nil
+ end
+ end
+
case t[1]
when :on_ignored_nl, :on_nl, :on_comment
if index != (@tokens.size - 1)
@@ -332,7 +398,7 @@ class RubyLex
next
end
case t[1]
- when :on_lbracket, :on_lbrace, :on_lparen
+ when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
depth_difference += 1
open_brace_on_line += 1
when :on_rbracket, :on_rbrace, :on_rparen
@@ -351,12 +417,12 @@ class RubyLex
end
when 'def', 'case', 'for', 'begin', 'class', 'module'
depth_difference += 1
- when 'if', 'unless', 'while', 'until'
+ when 'if', 'unless', 'while', 'until', 'rescue'
# postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
unless t[3].allbits?(Ripper::EXPR_LABEL)
depth_difference += 1
end
- when 'else', 'elsif', 'rescue', 'ensure', 'when', 'in'
+ when 'else', 'elsif', 'ensure', 'when', 'in'
depth_difference += 1
end
end
@@ -371,7 +437,36 @@ class RubyLex
spaces_of_nest = []
spaces_at_line_head = 0
open_brace_on_line = 0
+ in_oneliner_def = nil
@tokens.each_with_index do |t, index|
+ # detecting one-liner method definition
+ if in_oneliner_def.nil?
+ if t[3].allbits?(Ripper::EXPR_ENDFN)
+ in_oneliner_def = :ENDFN
+ end
+ else
+ if t[3].allbits?(Ripper::EXPR_ENDFN)
+ # continuing
+ elsif t[3].allbits?(Ripper::EXPR_BEG)
+ if t[2] == '='
+ in_oneliner_def = :BODY
+ end
+ elsif t[3].allbits?(Ripper::EXPR_END)
+ if in_oneliner_def == :BODY
+ # one-liner method definition
+ if is_first_printable_of_line
+ corresponding_token_depth = spaces_of_nest.pop
+ else
+ spaces_of_nest.pop
+ corresponding_token_depth = nil
+ end
+ end
+ in_oneliner_def = nil
+ else
+ in_oneliner_def = nil
+ end
+ end
+
case t[1]
when :on_ignored_nl, :on_nl, :on_comment
corresponding_token_depth = nil
@@ -386,7 +481,7 @@ class RubyLex
next
end
case t[1]
- when :on_lbracket, :on_lbrace, :on_lparen
+ when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
spaces_of_nest.push(spaces_at_line_head + open_brace_on_line * 2)
open_brace_on_line += 1
when :on_rbracket, :on_rbrace, :on_rparen
@@ -402,12 +497,16 @@ class RubyLex
case t[2]
when 'def', 'do', 'case', 'for', 'begin', 'class', 'module'
spaces_of_nest.push(spaces_at_line_head)
+ when 'rescue'
+ unless t[3].allbits?(Ripper::EXPR_LABEL)
+ corresponding_token_depth = spaces_of_nest.last
+ end
when 'if', 'unless', 'while', 'until'
- # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
+ # postfix if/unless/while/until must be Ripper::EXPR_LABEL
unless t[3].allbits?(Ripper::EXPR_LABEL)
spaces_of_nest.push(spaces_at_line_head)
end
- when 'else', 'elsif', 'rescue', 'ensure', 'when', 'in'
+ when 'else', 'elsif', 'ensure', 'when', 'in'
corresponding_token_depth = spaces_of_nest.last
when 'end'
if is_first_printable_of_line
diff --git a/lib/irb/ruby_logo.aa b/lib/irb/ruby_logo.aa
index 043e6f85fb..a34a3e2f28 100644
--- a/lib/irb/ruby_logo.aa
+++ b/lib/irb/ruby_logo.aa
@@ -35,4 +35,3 @@
m7 NW H N HSVO1z=?11-
NgTH bB kH WBHWWHBHWmQgg&gggggNNN
NNggggggNN
-
diff --git a/lib/irb/version.rb b/lib/irb/version.rb
index 7669c1c535..8b61eb3ef9 100644
--- a/lib/irb/version.rb
+++ b/lib/irb/version.rb
@@ -11,7 +11,7 @@
#
module IRB # :nodoc:
- VERSION = "1.2.3"
+ VERSION = "1.2.6"
@RELEASE_VERSION = VERSION
- @LAST_UPDATE_DATE = "2020-02-15"
+ @LAST_UPDATE_DATE = "2020-09-14"
end
diff --git a/lib/irb/xmp.rb b/lib/irb/xmp.rb
index 60cf3b4e4d..88cbd88525 100644
--- a/lib/irb/xmp.rb
+++ b/lib/irb/xmp.rb
@@ -10,7 +10,7 @@
#
#
-require "irb"
+require_relative "../irb"
require_relative "frame"
# An example printer for irb.
diff --git a/test/irb/test_cmd.rb b/test/irb/test_cmd.rb
new file mode 100644
index 0000000000..bb33f535b6
--- /dev/null
+++ b/test/irb/test_cmd.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: false
+require "test/unit"
+require "irb"
+require "irb/extend-command"
+
+module TestIRB
+ class ExtendCommand < Test::Unit::TestCase
+ def setup
+ @pwd = Dir.pwd
+ @tmpdir = File.join(Dir.tmpdir, "test_reline_config_#{$$}")
+ begin
+ Dir.mkdir(@tmpdir)
+ rescue Errno::EEXIST
+ FileUtils.rm_rf(@tmpdir)
+ Dir.mkdir(@tmpdir)
+ end
+ Dir.chdir(@tmpdir)
+ @home_backup = ENV["HOME"]
+ ENV["HOME"] = @tmpdir
+ @default_encoding = [Encoding.default_external, Encoding.default_internal]
+ @stdio_encodings = [STDIN, STDOUT, STDERR].map {|io| [io.external_encoding, io.internal_encoding] }
+ IRB.instance_variable_get(:@CONF).clear
+ end
+
+ def teardown
+ ENV["HOME"] = @home_backup
+ Dir.chdir(@pwd)
+ FileUtils.rm_rf(@tmpdir)
+ EnvUtil.suppress_warning {
+ Encoding.default_external, Encoding.default_internal = *@default_encoding
+ [STDIN, STDOUT, STDERR].zip(@stdio_encodings) do |io, encs|
+ io.set_encoding(*encs)
+ end
+ }
+ end
+
+ def test_irb_info_multiline
+ FileUtils.touch("#{@tmpdir}/.inputrc")
+ FileUtils.touch("#{@tmpdir}/.irbrc")
+ IRB.setup(__FILE__, argv: [])
+ IRB.conf[:USE_MULTILINE] = true
+ IRB.conf[:USE_SINGLELINE] = false
+ IRB.conf[:VERBOSE] = false
+ workspace = IRB::WorkSpace.new(self)
+ irb = IRB::Irb.new(workspace)
+ IRB.conf[:MAIN_CONTEXT] = irb.context
+ expected = %r{
+ Ruby\sversion: .+\n
+ IRB\sversion:\sirb .+\n
+ InputMethod:\sReidlineInputMethod\swith\sReline .+ and .+\n
+ \.irbrc\spath: .+
+ }x
+ assert_match expected, irb.context.main.irb_info.to_s
+ end
+
+ def test_irb_info_singleline
+ FileUtils.touch("#{@tmpdir}/.inputrc")
+ FileUtils.touch("#{@tmpdir}/.irbrc")
+ IRB.setup(__FILE__, argv: [])
+ IRB.conf[:USE_MULTILINE] = false
+ IRB.conf[:USE_SINGLELINE] = true
+ IRB.conf[:VERBOSE] = false
+ workspace = IRB::WorkSpace.new(self)
+ irb = IRB::Irb.new(workspace)
+ IRB.conf[:MAIN_CONTEXT] = irb.context
+ expected = %r{
+ Ruby\sversion: .+\n
+ IRB\sversion:\sirb .+\n
+ InputMethod:\sReadlineInputMethod\swith .+ and .+\n
+ \.irbrc\spath: .+
+ }x
+ assert_match expected, irb.context.main.irb_info.to_s
+ end
+
+ def test_irb_info_multiline_without_rc_files
+ inputrc_backup = ENV["INPUTRC"]
+ ENV["INPUTRC"] = "unknown_inpurc"
+ ext_backup = IRB::IRBRC_EXT
+ IRB.__send__(:remove_const, :IRBRC_EXT)
+ IRB.const_set(:IRBRC_EXT, "unknown_ext")
+ IRB.setup(__FILE__, argv: [])
+ IRB.conf[:USE_MULTILINE] = true
+ IRB.conf[:USE_SINGLELINE] = false
+ IRB.conf[:VERBOSE] = false
+ workspace = IRB::WorkSpace.new(self)
+ irb = IRB::Irb.new(workspace)
+ IRB.conf[:MAIN_CONTEXT] = irb.context
+ expected = %r{
+ Ruby\sversion: .+\n
+ IRB\sversion:\sirb .+\n
+ InputMethod:\sReidlineInputMethod\swith\sReline\s[^ ]+(?!\sand\s.+)\n
+ \z
+ }x
+ assert_match expected, irb.context.main.irb_info.to_s
+ ensure
+ ENV["INPUTRC"] = inputrc_backup
+ IRB.__send__(:remove_const, :IRBRC_EXT)
+ IRB.const_set(:IRBRC_EXT, ext_backup)
+ end
+
+ def test_irb_info_singleline_without_rc_files
+ inputrc_backup = ENV["INPUTRC"]
+ ENV["INPUTRC"] = "unknown_inpurc"
+ ext_backup = IRB::IRBRC_EXT
+ IRB.__send__(:remove_const, :IRBRC_EXT)
+ IRB.const_set(:IRBRC_EXT, "unknown_ext")
+ IRB.setup(__FILE__, argv: [])
+ IRB.conf[:USE_MULTILINE] = false
+ IRB.conf[:USE_SINGLELINE] = true
+ IRB.conf[:VERBOSE] = false
+ workspace = IRB::WorkSpace.new(self)
+ irb = IRB::Irb.new(workspace)
+ IRB.conf[:MAIN_CONTEXT] = irb.context
+ expected = %r{
+ Ruby\sversion: .+\n
+ IRB\sversion:\sirb .+\n
+ InputMethod:\sReadlineInputMethod\swith\s(?~.*\sand\s.+)\n
+ \z
+ }x
+ assert_match expected, irb.context.main.irb_info.to_s
+ ensure
+ ENV["INPUTRC"] = inputrc_backup
+ IRB.__send__(:remove_const, :IRBRC_EXT)
+ IRB.const_set(:IRBRC_EXT, ext_backup)
+ end
+ end
+end
diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb
index d03cc30c78..fa628bba46 100644
--- a/test/irb/test_context.rb
+++ b/test/irb/test_context.rb
@@ -30,6 +30,10 @@ module TestIRB
def reset
@line_no = 0
end
+
+ def winsize
+ [10, 20]
+ end
end
def setup
@@ -98,6 +102,21 @@ module TestIRB
$VERBOSE = verbose
end
+ def test_eval_object_without_inspect_method
+ verbose, $VERBOSE = $VERBOSE, nil
+ input = TestInputMethod.new([
+ "BasicObject.new\n",
+ ])
+ irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
+ out, err = capture_output do
+ irb.eval_input
+ end
+ assert_empty err
+ assert(/\(Object doesn't support #inspect\)\n(=> )?\n/, out)
+ ensure
+ $VERBOSE = verbose
+ end
+
def test_default_config
assert_equal(true, @context.use_colorize?)
end
@@ -198,6 +217,151 @@ module TestIRB
assert_equal("", out)
end
+ def test_omit_on_assignment
+ input = TestInputMethod.new([
+ "a = [1] * 100\n",
+ "a\n",
+ ])
+ value = [1] * 100
+ irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
+ irb.context.return_format = "=> %s\n"
+
+ irb.context.echo = true
+ irb.context.echo_on_assignment = false
+ irb.context.omit_on_assignment = true
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("=> #{value.inspect}\n", out)
+
+ input.reset
+ irb.context.echo = true
+ irb.context.echo_on_assignment = true
+ irb.context.omit_on_assignment = true
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("=> #{value.inspect[0..(input.winsize.last - 9)]}...\e[0m\n=> #{value.inspect}\n", out)
+
+ input.reset
+ irb.context.echo = true
+ irb.context.echo_on_assignment = true
+ irb.context.omit_on_assignment = false
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("=> #{value.inspect}\n=> #{value.inspect}\n", out)
+
+ input.reset
+ irb.context.echo = false
+ irb.context.echo_on_assignment = false
+ irb.context.omit_on_assignment = true
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("", out)
+
+ input.reset
+ irb.context.echo = false
+ irb.context.echo_on_assignment = true
+ irb.context.omit_on_assignment = true
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("", out)
+
+ input.reset
+ irb.context.echo = false
+ irb.context.echo_on_assignment = true
+ irb.context.omit_on_assignment = false
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("", out)
+ end
+
+ def test_omit_multiline_on_assignment
+ input = TestInputMethod.new([
+ "class A; def inspect; ([?* * 1000] * 3).join(%{\\n}); end; end; a = A.new\n",
+ "a\n"
+ ])
+ value = ([?* * 1000] * 3).join(%{\n})
+ value_first_line = (?* * 1000).to_s
+ irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
+ irb.context.return_format = "=> %s\n"
+
+ irb.context.echo = true
+ irb.context.echo_on_assignment = false
+ irb.context.omit_on_assignment = true
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("=> \n#{value}\n", out)
+ irb.context.evaluate('A.remove_method(:inspect)', 0)
+
+ input.reset
+ irb.context.echo = true
+ irb.context.echo_on_assignment = true
+ irb.context.omit_on_assignment = true
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("=> #{value_first_line[0..(input.winsize.last - 9)]}...\e[0m\n=> \n#{value}\n", out)
+ irb.context.evaluate('A.remove_method(:inspect)', 0)
+
+ input.reset
+ irb.context.echo = true
+ irb.context.echo_on_assignment = true
+ irb.context.omit_on_assignment = false
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("=> \n#{value}\n=> \n#{value}\n", out)
+ irb.context.evaluate('A.remove_method(:inspect)', 0)
+
+ input.reset
+ irb.context.echo = false
+ irb.context.echo_on_assignment = false
+ irb.context.omit_on_assignment = true
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("", out)
+ irb.context.evaluate('A.remove_method(:inspect)', 0)
+
+ input.reset
+ irb.context.echo = false
+ irb.context.echo_on_assignment = true
+ irb.context.omit_on_assignment = true
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("", out)
+ irb.context.evaluate('A.remove_method(:inspect)', 0)
+
+ input.reset
+ irb.context.echo = false
+ irb.context.echo_on_assignment = true
+ irb.context.omit_on_assignment = false
+ out, err = capture_io do
+ irb.eval_input
+ end
+ assert_empty err
+ assert_equal("", out)
+ irb.context.evaluate('A.remove_method(:inspect)', 0)
+ end
+
def test_echo_on_assignment_conf
# Default
IRB.conf[:ECHO] = nil
@@ -206,22 +370,26 @@ module TestIRB
irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
assert(irb.context.echo?, "echo? should be true by default")
- refute(irb.context.echo_on_assignment?, "echo_on_assignment? should be false by default")
+ assert(irb.context.echo_on_assignment?, "echo_on_assignment? should be true by default")
+ assert(irb.context.omit_on_assignment?, "omit_on_assignment? should be true by default")
# Explicitly set :ECHO to false
IRB.conf[:ECHO] = false
irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
refute(irb.context.echo?, "echo? should be false when IRB.conf[:ECHO] is set to false")
- refute(irb.context.echo_on_assignment?, "echo_on_assignment? should be false by default")
+ assert(irb.context.echo_on_assignment?, "echo_on_assignment? should be true by default")
+ assert(irb.context.omit_on_assignment?, "omit_on_assignment? should be true by default")
# Explicitly set :ECHO_ON_ASSIGNMENT to true
IRB.conf[:ECHO] = nil
- IRB.conf[:ECHO_ON_ASSIGNMENT] = true
+ IRB.conf[:ECHO_ON_ASSIGNMENT] = false
+ IRB.conf[:OMIT_ON_ASSIGNMENT] = false
irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input)
assert(irb.context.echo?, "echo? should be true by default")
- assert(irb.context.echo_on_assignment?, "echo_on_assignment? should be true when IRB.conf[:ECHO_ON_ASSIGNMENT] is set to true")
+ refute(irb.context.echo_on_assignment?, "echo_on_assignment? should be false when IRB.conf[:ECHO_ON_ASSIGNMENT] is set to false")
+ refute(irb.context.omit_on_assignment?, "omit_on_assignment? should be false when IRB.conf[:OMIT_ON_ASSIGNMENT] is set to false")
end
def test_multiline_output_on_default_inspector
diff --git a/test/irb/test_history.rb b/test/irb/test_history.rb
new file mode 100644
index 0000000000..3591f88f59
--- /dev/null
+++ b/test/irb/test_history.rb
@@ -0,0 +1,153 @@
+# frozen_string_literal: false
+require 'test/unit'
+require 'irb'
+require 'readline'
+
+module TestIRB
+ class TestHistory < Test::Unit::TestCase
+ def setup
+ IRB.conf[:RC_NAME_GENERATOR] = nil
+ end
+
+ def teardown
+ IRB.conf[:RC_NAME_GENERATOR] = nil
+ end
+
+ def test_history_save_1
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
+ IRB.conf[:USE_READLINE] = true
+ IRB.conf[:SAVE_HISTORY] = 1
+ IRB.conf[:USE_READLINE] = true
+ IRBRC
+ 1
+ 2
+ 3
+ 4
+ IRB_HISTORY
+ stdin.write("5\nexit\n")
+ end
+
+ assert_equal(<<~HISTORY_FILE, result_history_file)
+ exit
+ HISTORY_FILE
+ end
+
+ def test_history_save_100
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
+ IRB.conf[:USE_READLINE] = true
+ IRB.conf[:SAVE_HISTORY] = 100
+ IRB.conf[:USE_READLINE] = true
+ IRBRC
+ 1
+ 2
+ 3
+ 4
+ IRB_HISTORY
+ stdin.write("5\nexit\n")
+ end
+
+ assert_equal(<<~HISTORY_FILE, result_history_file)
+ 1
+ 2
+ 3
+ 4
+ 5
+ exit
+ HISTORY_FILE
+ end
+
+ def test_history_save_bignum
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
+ IRB.conf[:USE_READLINE] = true
+ IRB.conf[:SAVE_HISTORY] = 10 ** 19
+ IRB.conf[:USE_READLINE] = true
+ IRBRC
+ 1
+ 2
+ 3
+ 4
+ IRB_HISTORY
+ stdin.write("5\nexit\n")
+ end
+
+ assert_equal(<<~HISTORY_FILE, result_history_file)
+ 1
+ 2
+ 3
+ 4
+ 5
+ exit
+ HISTORY_FILE
+ end
+
+ def test_history_save_minus_as_infinity
+ omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
+ _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
+ IRB.conf[:USE_READLINE] = true
+ IRB.conf[:SAVE_HISTORY] = -1 # infinity
+ IRB.conf[:USE_READLINE] = true
+ IRBRC
+ 1
+ 2
+ 3
+ 4
+ IRB_HISTORY
+ stdin.write("5\nexit\n")
+ end
+
+ assert_equal(<<~HISTORY_FILE, result_history_file)
+ 1
+ 2
+ 3
+ 4
+ 5
+ exit
+ HISTORY_FILE
+ end
+
+ private
+
+ def launch_irb_with_irbrc_and_irb_history(irbrc, irb_history)
+ result = nil
+ result_history = nil
+ backup_irbrc = ENV.delete("IRBRC")
+ backup_home = ENV["HOME"]
+ Dir.mktmpdir("test_irb_history_#{$$}") do |tmpdir|
+ ENV["HOME"] = tmpdir
+ open(IRB.rc_file, "w") do |f|
+ f.write(irbrc)
+ end
+ open(IRB.rc_file("_history"), "w") do |f|
+ f.write(irb_history)
+ end
+
+ with_temp_stdio do |stdin, stdout|
+ yield(stdin, stdout)
+ stdin.close
+ stdout.flush
+ system('ruby', '-Ilib', '-Itest', '-W0', '-rirb', '-e', 'IRB.start(__FILE__)', in: stdin.path, out: stdout.path)
+ result = stdout.read
+ stdout.close
+ end
+ open(IRB.rc_file("_history"), "r") do |f|
+ result_history = f.read
+ end
+ end
+ [result, result_history]
+ ensure
+ ENV["HOME"] = backup_home
+ ENV["IRBRC"] = backup_irbrc
+ end
+
+ def with_temp_stdio
+ Tempfile.create("test_readline_stdin") do |stdin|
+ Tempfile.create("test_readline_stdout") do |stdout|
+ yield stdin, stdout
+ end
+ end
+ end
+ end
+end if not RUBY_PLATFORM.match?(/solaris|mswin|mingw/i)
diff --git a/test/irb/test_ruby_lex.rb b/test/irb/test_ruby_lex.rb
index dd5a1f7ca5..14b43f5718 100644
--- a/test/irb/test_ruby_lex.rb
+++ b/test/irb/test_ruby_lex.rb
@@ -5,7 +5,7 @@ require 'ostruct'
module TestIRB
class TestRubyLex < Test::Unit::TestCase
- Row = Struct.new(:content, :current_line_spaces, :new_line_spaces)
+ Row = Struct.new(:content, :current_line_spaces, :new_line_spaces, :nesting_level)
class MockIO
def initialize(params, &assertion)
@@ -34,6 +34,15 @@ module TestIRB
ruby_lex.set_auto_indent(context)
end
+ def assert_nesting_level(lines, expected)
+ ruby_lex = RubyLex.new()
+ io = proc{ lines.join("\n") }
+ ruby_lex.set_input(io, io)
+ ruby_lex.lex
+ error_message = "Calculated the wrong number of nesting level for:\n #{lines.join("\n")}"
+ assert_equal(expected, ruby_lex.instance_variable_get(:@indent), error_message)
+ end
+
def test_auto_indent
input_with_correct_indents = [
Row.new(%q(def each_top_level_statement), nil, 2),
@@ -126,5 +135,130 @@ module TestIRB
assert_indenting(lines, row.new_line_spaces, true)
end
end
+
+ def test_incomplete_coding_magic_comment
+ input_with_correct_indents = [
+ Row.new(%q(#coding:u), nil, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+
+ def test_incomplete_encoding_magic_comment
+ input_with_correct_indents = [
+ Row.new(%q(#encoding:u), nil, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+
+ def test_incomplete_emacs_coding_magic_comment
+ input_with_correct_indents = [
+ Row.new(%q(# -*- coding: u), nil, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+
+ def test_incomplete_vim_coding_magic_comment
+ input_with_correct_indents = [
+ Row.new(%q(# vim:set fileencoding=u), nil, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+
+ def test_mixed_rescue
+ input_with_correct_indents = [
+ Row.new(%q(def m), nil, 2),
+ Row.new(%q( begin), nil, 4),
+ Row.new(%q( begin), nil, 6),
+ Row.new(%q( x = a rescue 4), nil, 6),
+ Row.new(%q( y = [(a rescue 5)]), nil, 6),
+ Row.new(%q( [x, y]), nil, 6),
+ Row.new(%q( rescue => e), 4, 6),
+ Row.new(%q( raise e rescue 8), nil, 6),
+ Row.new(%q( end), 4, 4),
+ Row.new(%q( rescue), 2, 4),
+ Row.new(%q( raise rescue 11), nil, 4),
+ Row.new(%q( end), 2, 2),
+ Row.new(%q(rescue => e), 0, 2),
+ Row.new(%q( raise e rescue 14), nil, 2),
+ Row.new(%q(end), 0, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+
+ def test_oneliner_method_definition
+ input_with_correct_indents = [
+ Row.new(%q(class A), nil, 2),
+ Row.new(%q( def foo0), nil, 4),
+ Row.new(%q( 3), nil, 4),
+ Row.new(%q( end), 2, 2),
+ Row.new(%q( def foo1()), nil, 4),
+ Row.new(%q( 3), nil, 4),
+ Row.new(%q( end), 2, 2),
+ Row.new(%q( def foo2(a, b)), nil, 4),
+ Row.new(%q( a + b), nil, 4),
+ Row.new(%q( end), 2, 2),
+ Row.new(%q( def foo3 a, b), nil, 4),
+ Row.new(%q( a + b), nil, 4),
+ Row.new(%q( end), 2, 2),
+ Row.new(%q( def bar0() = 3), nil, 2),
+ Row.new(%q( def bar1(a) = a), nil, 2),
+ Row.new(%q( def bar2(a, b) = a + b), nil, 2),
+ Row.new(%q(end), 0, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ end
+ end
+
+ def test_tlambda
+ input_with_correct_indents = [
+ Row.new(%q(if true), nil, 2, 1),
+ Row.new(%q( -> {), nil, 4, 2),
+ Row.new(%q( }), 2, 2, 1),
+ Row.new(%q(end), 0, 0, 0),
+ ]
+
+ lines = []
+ input_with_correct_indents.each do |row|
+ lines << row.content
+ assert_indenting(lines, row.current_line_spaces, false)
+ assert_indenting(lines, row.new_line_spaces, true)
+ assert_nesting_level(lines, row.nesting_level)
+ end
+ end
end
end
diff --git a/test/irb/test_workspace.rb b/test/irb/test_workspace.rb
index 992cdd4516..15c77315a8 100644
--- a/test/irb/test_workspace.rb
+++ b/test/irb/test_workspace.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: false
require 'test/unit'
require 'tempfile'
+require 'rubygems'
require 'irb'
require 'irb/workspace'
require 'irb/color'