From b2f562176befd79e316c155af6a9151f7cec1f01 Mon Sep 17 00:00:00 2001 From: st0012 Date: Mon, 19 Sep 2022 16:14:03 +0100 Subject: [PATCH] Handle non-String $LOAD_PATH values more carefully In addition to String values, $LOAD_PATH can also take objects that respond_to the `to_path` method, like Pathname objects. So `irb` should be able to handle those objects too. And if $LOAD_PATH contains objects that can't be converted into String, `irb` should simply ignore it. --- lib/irb/completion.rb | 9 +++++++- test/irb/test_completion.rb | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb index 9121174a5..bfe6c7e7a 100644 --- a/lib/irb/completion.rb +++ b/lib/irb/completion.rb @@ -60,7 +60,14 @@ def self.retrieve_gem_and_system_load_path end } }.flatten if defined?(Gem::Specification) - (gem_paths.to_a | $LOAD_PATH).sort + candidates = (gem_paths.to_a | $LOAD_PATH) + candidates.map do |p| + if p.respond_to?(:to_path) + p.to_path + else + String(p) rescue nil + end + end.compact.sort end def self.retrieve_files_to_require_from_load_path diff --git a/test/irb/test_completion.rb b/test/irb/test_completion.rb index 3aa99d74d..4bc3fc778 100644 --- a/test/irb/test_completion.rb +++ b/test/irb/test_completion.rb @@ -4,6 +4,11 @@ module TestIRB class TestCompletion < Test::Unit::TestCase + def setup + # make sure require completion candidates are not cached + IRB::InputCompletor.class_variable_set(:@@files_from_load_path, nil) + end + def test_nonstring_module_name begin require "irb/completion" @@ -84,6 +89,43 @@ def test_complete_require end end + def test_complete_require_with_pathname_in_load_path + temp_dir = Dir.mktmpdir + File.write(File.join(temp_dir, "foo.rb"), "test") + test_path = Pathname.new(temp_dir) + $LOAD_PATH << test_path + + candidates = IRB::InputCompletor::CompletionProc.("'foo", "require ", "") + assert_equal ["'foo"], candidates + ensure + $LOAD_PATH.pop if test_path + FileUtils.remove_entry(temp_dir) if temp_dir + end + + def test_complete_require_with_string_convertable_in_load_path + temp_dir = Dir.mktmpdir + File.write(File.join(temp_dir, "foo.rb"), "test") + object = Object.new + object.define_singleton_method(:to_s) { temp_dir } + $LOAD_PATH << object + + candidates = IRB::InputCompletor::CompletionProc.("'foo", "require ", "") + assert_equal ["'foo"], candidates + ensure + $LOAD_PATH.pop if object + FileUtils.remove_entry(temp_dir) if temp_dir + end + + def test_complete_require_with_malformed_object_in_load_path + object = Object.new + def object.to_s; raise; end + $LOAD_PATH << object + + assert_empty IRB::InputCompletor::CompletionProc.("'foo", "require ", "") + ensure + $LOAD_PATH.pop if object + end + def test_complete_require_library_name_first pend 'Need to use virtual library paths' candidates = IRB::InputCompletor::CompletionProc.("'csv", "require ", "")