diff --git a/lib/irb/command/irb_info.rb b/lib/irb/command/irb_info.rb index 00ce7a5f0..31e6d77d2 100644 --- a/lib/irb/command/irb_info.rb +++ b/lib/irb/command/irb_info.rb @@ -13,7 +13,8 @@ def execute str += "IRB version: #{IRB.version}\n" str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n" str += "Completion: #{IRB.CurrentContext.io.respond_to?(:completion_info) ? IRB.CurrentContext.io.completion_info : 'off'}\n" - str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file) + rc_files = IRB.rc_files.select { |rc| File.exist?(rc) } + str += ".irbrc paths: #{rc_files.join(", ")}\n" if rc_files.any? str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n" str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty? str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty? diff --git a/lib/irb/history.rb b/lib/irb/history.rb index dffdee32d..2489f7403 100644 --- a/lib/irb/history.rb +++ b/lib/irb/history.rb @@ -16,7 +16,7 @@ def load_history if history_file = IRB.conf[:HISTORY_FILE] history_file = File.expand_path(history_file) end - history_file = IRB.rc_file("_history") unless history_file + history_file = IRB.rc_files("_history").first unless history_file if File.exist?(history_file) File.open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f| f.each { |l| @@ -41,7 +41,7 @@ def save_history if history_file = IRB.conf[:HISTORY_FILE] history_file = File.expand_path(history_file) end - history_file = IRB.rc_file("_history") unless history_file + history_file = IRB.rc_files("_history").first unless history_file # Change the permission of a file that already exists[BUG #7694] begin diff --git a/lib/irb/init.rb b/lib/irb/init.rb index 107cba592..5813ff7ae 100644 --- a/lib/irb/init.rb +++ b/lib/irb/init.rb @@ -395,33 +395,41 @@ def IRB.parse_opts(argv: ::ARGV) # Run the config file def IRB.run_config if @CONF[:RC] - begin - file = rc_file + rc_files.each do |rc| # Because rc_file always returns `HOME/.irbrc` even if no rc file is present, we can't warn users about missing rc files. # Otherwise, it'd be very noisy. - load file if File.exist?(file) + load rc if File.exist?(rc) rescue StandardError, ScriptError => e - warn "Error loading RC file '#{file}':\n#{e.full_message(highlight: false)}" + warn "Error loading RC file '#{rc}':\n#{e.full_message(highlight: false)}" end end end IRBRC_EXT = "rc" def IRB.rc_file(ext = IRBRC_EXT) + warn "rc_file is deprecated, please use rc_files instead." + rc_files(ext).first + end + + def IRB.rc_files(ext = IRBRC_EXT) if !@CONF[:RC_NAME_GENERATOR] + @CONF[:RC_NAME_GENERATOR] ||= [] + existing_rc_file_generators = [] + rc_file_generators do |rcgen| - @CONF[:RC_NAME_GENERATOR] ||= rcgen - if File.exist?(rcgen.call(IRBRC_EXT)) - @CONF[:RC_NAME_GENERATOR] = rcgen - break - end + @CONF[:RC_NAME_GENERATOR] << rcgen + existing_rc_file_generators << rcgen if File.exist?(rcgen.call(ext)) + end + + if existing_rc_file_generators.any? + @CONF[:RC_NAME_GENERATOR] = existing_rc_file_generators end end - case rc_file = @CONF[:RC_NAME_GENERATOR].call(ext) - when String + + @CONF[:RC_NAME_GENERATOR].map do |rc| + rc_file = rc.call(ext) + fail IllegalRCNameGenerator unless rc_file.is_a?(String) rc_file - else - fail IllegalRCNameGenerator end end diff --git a/test/irb/test_command.rb b/test/irb/test_command.rb index 5c65a72ee..8e074e97f 100644 --- a/test/irb/test_command.rb +++ b/test/irb/test_command.rb @@ -75,6 +75,7 @@ def teardown def test_irb_info_multiline FileUtils.touch("#{@tmpdir}/.inputrc") FileUtils.touch("#{@tmpdir}/.irbrc") + FileUtils.touch("#{@tmpdir}/_irbrc") out, err = execute_lines( "irb_info", @@ -86,7 +87,7 @@ def test_irb_info_multiline IRB\sversion:\sirb\s.+\n InputMethod:\sAbstract\sInputMethod\n Completion: .+\n - \.irbrc\spath:\s.+\n + \.irbrc\spaths:.*\.irbrc.*_irbrc\n RUBY_PLATFORM:\s.+\n East\sAsian\sAmbiguous\sWidth:\s\d\n #{@is_win ? 'Code\spage:\s\d+\n' : ''} @@ -110,7 +111,7 @@ def test_irb_info_singleline IRB\sversion:\sirb\s.+\n InputMethod:\sAbstract\sInputMethod\n Completion: .+\n - \.irbrc\spath:\s.+\n + \.irbrc\spaths:\s.+\n RUBY_PLATFORM:\s.+\n East\sAsian\sAmbiguous\sWidth:\s\d\n #{@is_win ? 'Code\spage:\s\d+\n' : ''} @@ -196,7 +197,7 @@ def test_irb_info_lang IRB\sversion:\sirb .+\n InputMethod:\sAbstract\sInputMethod\n Completion: .+\n - \.irbrc\spath: .+\n + \.irbrc\spaths: .+\n RUBY_PLATFORM: .+\n LANG\senv:\sja_JP\.UTF-8\n LC_ALL\senv:\sen_US\.UTF-8\n diff --git a/test/irb/test_history.rb b/test/irb/test_history.rb index 2601bcad8..618dcc3d9 100644 --- a/test/irb/test_history.rb +++ b/test/irb/test_history.rb @@ -136,7 +136,7 @@ def test_history_concurrent_use_not_present io.class::HISTORY << 'line1' io.class::HISTORY << 'line2' - history_file = IRB.rc_file("_history") + history_file = IRB.rc_files("_history").first assert_not_send [File, :file?, history_file] File.write(history_file, "line0\n") io.save_history @@ -217,9 +217,10 @@ def assert_history(expected_history, initial_irb_history, input, input_method = backup_xdg_config_home = ENV.delete("XDG_CONFIG_HOME") IRB.conf[:LC_MESSAGES] = locale actual_history = nil + history_file = IRB.rc_files("_history").first Dir.mktmpdir("test_irb_history_") do |tmpdir| ENV["HOME"] = tmpdir - File.open(IRB.rc_file("_history"), "w") do |f| + File.open(history_file, "w") do |f| f.write(initial_irb_history) end @@ -229,7 +230,7 @@ def assert_history(expected_history, initial_irb_history, input, input_method = if block_given? previous_history = [] io.class::HISTORY.each { |line| previous_history << line } - yield IRB.rc_file("_history") + yield history_file io.class::HISTORY.clear previous_history.each { |line| io.class::HISTORY << line } end @@ -237,7 +238,7 @@ def assert_history(expected_history, initial_irb_history, input, input_method = io.save_history io.load_history - File.open(IRB.rc_file("_history"), "r") do |f| + File.open(history_file, "r") do |f| actual_history = f.read end end diff --git a/test/irb/test_init.rb b/test/irb/test_init.rb index 64bd96d02..fd1e06e39 100644 --- a/test/irb/test_init.rb +++ b/test/irb/test_init.rb @@ -11,7 +11,7 @@ def setup @backup_env = %w[HOME XDG_CONFIG_HOME IRBRC].each_with_object({}) do |env, hash| hash[env] = ENV.delete(env) end - ENV["HOME"] = @tmpdir = Dir.mktmpdir("test_irb_init_#{$$}") + ENV["HOME"] = @tmpdir = File.realpath(Dir.mktmpdir("test_irb_init_#{$$}")) end def teardown @@ -35,35 +35,133 @@ def test_setup_with_minimum_argv_does_not_change_dollar0 end def test_rc_file + verbose, $VERBOSE = $VERBOSE, nil tmpdir = @tmpdir Dir.chdir(tmpdir) do ENV["XDG_CONFIG_HOME"] = "#{tmpdir}/xdg" IRB.conf[:RC_NAME_GENERATOR] = nil - assert_equal(tmpdir+"/.irb#{IRB::IRBRC_EXT}", IRB.rc_file) + assert_equal(tmpdir+"/.irbrc", IRB.rc_file) assert_equal(tmpdir+"/.irb_history", IRB.rc_file("_history")) assert_file.not_exist?(tmpdir+"/xdg") IRB.conf[:RC_NAME_GENERATOR] = nil - FileUtils.touch(tmpdir+"/.irb#{IRB::IRBRC_EXT}") - assert_equal(tmpdir+"/.irb#{IRB::IRBRC_EXT}", IRB.rc_file) + FileUtils.touch(tmpdir+"/.irbrc") + assert_equal(tmpdir+"/.irbrc", IRB.rc_file) assert_equal(tmpdir+"/.irb_history", IRB.rc_file("_history")) assert_file.not_exist?(tmpdir+"/xdg") end + ensure + $VERBOSE = verbose end def test_rc_file_in_subdir + verbose, $VERBOSE = $VERBOSE, nil tmpdir = @tmpdir Dir.chdir(tmpdir) do FileUtils.mkdir_p("#{tmpdir}/mydir") Dir.chdir("#{tmpdir}/mydir") do IRB.conf[:RC_NAME_GENERATOR] = nil - assert_equal(tmpdir+"/.irb#{IRB::IRBRC_EXT}", IRB.rc_file) + assert_equal(tmpdir+"/.irbrc", IRB.rc_file) assert_equal(tmpdir+"/.irb_history", IRB.rc_file("_history")) IRB.conf[:RC_NAME_GENERATOR] = nil - FileUtils.touch(tmpdir+"/.irb#{IRB::IRBRC_EXT}") - assert_equal(tmpdir+"/.irb#{IRB::IRBRC_EXT}", IRB.rc_file) + FileUtils.touch(tmpdir+"/.irbrc") + assert_equal(tmpdir+"/.irbrc", IRB.rc_file) assert_equal(tmpdir+"/.irb_history", IRB.rc_file("_history")) end end + ensure + $VERBOSE = verbose + end + + def test_rc_files + tmpdir = @tmpdir + Dir.chdir(tmpdir) do + ENV["XDG_CONFIG_HOME"] = "#{tmpdir}/xdg" + IRB.conf[:RC_NAME_GENERATOR] = nil + assert_includes IRB.rc_files, tmpdir+"/.irbrc" + assert_includes IRB.rc_files("_history"), tmpdir+"/.irb_history" + assert_file.not_exist?(tmpdir+"/xdg") + IRB.conf[:RC_NAME_GENERATOR] = nil + FileUtils.touch(tmpdir+"/.irbrc") + assert_includes IRB.rc_files, tmpdir+"/.irbrc" + assert_includes IRB.rc_files("_history"), tmpdir+"/.irb_history" + assert_file.not_exist?(tmpdir+"/xdg") + end + end + + def test_rc_files_in_subdir + tmpdir = @tmpdir + Dir.chdir(tmpdir) do + FileUtils.mkdir_p("#{tmpdir}/mydir") + Dir.chdir("#{tmpdir}/mydir") do + IRB.conf[:RC_NAME_GENERATOR] = nil + assert_includes IRB.rc_files, tmpdir+"/.irbrc" + assert_includes IRB.rc_files("_history"), tmpdir+"/.irb_history" + IRB.conf[:RC_NAME_GENERATOR] = nil + FileUtils.touch(tmpdir+"/.irbrc") + assert_includes IRB.rc_files, tmpdir+"/.irbrc" + assert_includes IRB.rc_files("_history"), tmpdir+"/.irb_history" + end + end + end + + def test_rc_files_has_file_from_xdg_env + tmpdir = @tmpdir + ENV["XDG_CONFIG_HOME"] = "#{tmpdir}/xdg" + xdg_config = ENV["XDG_CONFIG_HOME"]+"/irb/irbrc" + + FileUtils.mkdir_p(xdg_config) + + Dir.chdir(tmpdir) do + IRB.conf[:RC_NAME_GENERATOR] = nil + assert_includes IRB.rc_files, xdg_config + end + ensure + ENV["XDG_CONFIG_HOME"] = nil + end + + def test_rc_files_has_file_from_irbrc_env + tmpdir = @tmpdir + ENV["IRBRC"] = "#{tmpdir}/irb" + + FileUtils.mkdir_p(ENV["IRBRC"]) + + Dir.chdir(tmpdir) do + IRB.conf[:RC_NAME_GENERATOR] = nil + assert_includes IRB.rc_files, ENV["IRBRC"] + end + ensure + ENV["IRBRC"] = nil + end + + def test_rc_files_has_file_from_home_env + tmpdir = @tmpdir + ENV["HOME"] = "#{tmpdir}/home" + + FileUtils.mkdir_p(ENV["HOME"]) + + Dir.chdir(tmpdir) do + IRB.conf[:RC_NAME_GENERATOR] = nil + assert_includes IRB.rc_files, ENV["HOME"]+"/.irbrc" + assert_includes IRB.rc_files, ENV["HOME"]+"/.config/irb/irbrc" + end + ensure + ENV["HOME"] = nil + end + + def test_rc_files_contains_non_env_files + tmpdir = @tmpdir + FileUtils.mkdir_p("#{tmpdir}/.irbrc") + FileUtils.mkdir_p("#{tmpdir}/_irbrc") + FileUtils.mkdir_p("#{tmpdir}/irb.rc") + FileUtils.mkdir_p("#{tmpdir}/$irbrc") + + Dir.chdir(tmpdir) do + IRB.conf[:RC_NAME_GENERATOR] = nil + assert_includes IRB.rc_files, tmpdir+"/.irbrc" + assert_includes IRB.rc_files, tmpdir+"/_irbrc" + assert_includes IRB.rc_files, tmpdir+"/irb.rc" + assert_includes IRB.rc_files, tmpdir+"/$irbrc" + end end def test_sigint_restore_default