Skip to content

Commit

Permalink
Add the ability to fetch and load multiple irb files. (#859)
Browse files Browse the repository at this point in the history
This allows hierarchy when loading rc files for example both files below
are loaded;

project/.irbrc
~/.irbrc

Co-authored-by: Stan Lo <[email protected]>
  • Loading branch information
hahmed and st0012 authored Mar 5, 2024
1 parent 7efadc2 commit b53ebc6
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 30 deletions.
3 changes: 2 additions & 1 deletion lib/irb/command/irb_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
4 changes: 2 additions & 2 deletions lib/irb/history.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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|
Expand All @@ -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
Expand Down
34 changes: 21 additions & 13 deletions lib/irb/init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 4 additions & 3 deletions test/irb/test_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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' : ''}
Expand All @@ -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' : ''}
Expand Down Expand Up @@ -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
Expand Down
9 changes: 5 additions & 4 deletions test/irb/test_history.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -229,15 +230,15 @@ 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
input.split.each { |line| io.class::HISTORY << line }
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
Expand Down
112 changes: 105 additions & 7 deletions test/irb/test_init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit b53ebc6

Please sign in to comment.