From 5170be384929c3179da98b2f9f262111459d6c3e Mon Sep 17 00:00:00 2001 From: Eike Send Date: Wed, 25 Feb 2026 10:09:49 +0100 Subject: [PATCH 1/4] Add ls command test --- test/irb/command/test_ls.rb | 71 +++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 test/irb/command/test_ls.rb diff --git a/test/irb/command/test_ls.rb b/test/irb/command/test_ls.rb new file mode 100644 index 000000000..d865fe576 --- /dev/null +++ b/test/irb/command/test_ls.rb @@ -0,0 +1,71 @@ +require "tempfile" +require_relative "../helper" + +module TestIRB + class LSTest < IntegrationTestCase + def setup + super + + write_ruby <<~'RUBY' + class Foo + class Bar + def bar + "this is bar" + end + end + + def foo + "this is foo" + end + end + + class BO < BasicObject + ONE = 1 + def baz + "this is baz" + end + end + + binding.irb + RUBY + end + + def test_ls_class + out = run_ruby_file do + type "ls Foo" + type "exit" + end + + assert_match(/constants: Bar/, out) + assert_match(/Foo#methods: foo/, out) + end + + def test_ls_instance + out = run_ruby_file do + type "ls Foo.new" + type "exit" + end + + assert_match(/Foo#methods: foo/, out) + end + + def test_ls_basic_object + out = run_ruby_file do + type "ls BO" + type "exit" + end + + assert_match(/constants:.*ONE/, out) + assert_match(/BO#methods: baz/, out) + end + + def test_ls_basic_object_instance + out = run_ruby_file do + type "ls BO.new" + type "exit" + end + + assert_match(/BO#methods: baz/, out) + end + end +end From a484a506da8df84f3869486dcca0fafb1902cc25 Mon Sep 17 00:00:00 2001 From: Eike Send Date: Wed, 25 Feb 2026 10:20:14 +0100 Subject: [PATCH 2/4] Make ls command work for BasicObjects --- lib/irb/command/ls.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/irb/command/ls.rb b/lib/irb/command/ls.rb index 944efd757..52eff612e 100644 --- a/lib/irb/command/ls.rb +++ b/lib/irb/command/ls.rb @@ -55,11 +55,13 @@ def execute(arg) o = Output.new(grep: grep) - klass = (obj.class == Class || obj.class == Module ? obj : obj.class) + klass = Kernel.instance_method(:class).bind(obj).call + is_class_or_module = klass == Class || klass == Module + klass = is_class_or_module ? obj : klass - o.dump("constants", obj.constants) if obj.respond_to?(:constants) + o.dump("constants", obj.constants) if is_class_or_module dump_methods(o, klass, obj) - o.dump("instance variables", obj.instance_variables) + o.dump("instance variables", Kernel.instance_method(:instance_variables).bind(obj).call) o.dump("class variables", klass.class_variables) o.dump("locals", locals) if locals o.print_result @@ -67,7 +69,7 @@ def execute(arg) end def dump_methods(o, klass, obj) - singleton_class = begin obj.singleton_class; rescue TypeError; nil end + singleton_class = begin Kernel.instance_method(:singleton_class).bind(obj).call; rescue TypeError; nil end dumped_mods = Array.new ancestors = klass.ancestors ancestors = ancestors.reject { |c| c >= Object } if klass < Object From 9e88e7081ff6125d9c739adc3d39be1d3d361351 Mon Sep 17 00:00:00 2001 From: Eike Send Date: Wed, 25 Feb 2026 15:32:31 +0100 Subject: [PATCH 3/4] Use is_a? to determine if obj is a Class or Module --- lib/irb/command/ls.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/irb/command/ls.rb b/lib/irb/command/ls.rb index 52eff612e..568e11b3d 100644 --- a/lib/irb/command/ls.rb +++ b/lib/irb/command/ls.rb @@ -56,10 +56,10 @@ def execute(arg) o = Output.new(grep: grep) klass = Kernel.instance_method(:class).bind(obj).call - is_class_or_module = klass == Class || klass == Module - klass = is_class_or_module ? obj : klass + obj_is_module = Kernel.instance_method(:is_a?).bind(obj).call(Module) # Class is also a Module + klass = obj_is_module ? obj : klass - o.dump("constants", obj.constants) if is_class_or_module + o.dump("constants", obj.constants) if obj_is_module dump_methods(o, klass, obj) o.dump("instance variables", Kernel.instance_method(:instance_variables).bind(obj).call) o.dump("class variables", klass.class_variables) From 301bf3f3abf4d8df358baf5cbaea5fa04c512448 Mon Sep 17 00:00:00 2001 From: Eike Send Date: Wed, 25 Feb 2026 17:22:08 +0100 Subject: [PATCH 4/4] Use === operator to determin if obj is a Class or Module --- lib/irb/command/ls.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/irb/command/ls.rb b/lib/irb/command/ls.rb index 568e11b3d..eae643ff4 100644 --- a/lib/irb/command/ls.rb +++ b/lib/irb/command/ls.rb @@ -56,10 +56,10 @@ def execute(arg) o = Output.new(grep: grep) klass = Kernel.instance_method(:class).bind(obj).call - obj_is_module = Kernel.instance_method(:is_a?).bind(obj).call(Module) # Class is also a Module - klass = obj_is_module ? obj : klass + obj_is_class_or_module = Module === obj + klass = obj_is_class_or_module ? obj : klass - o.dump("constants", obj.constants) if obj_is_module + o.dump("constants", obj.constants) if obj_is_class_or_module dump_methods(o, klass, obj) o.dump("instance variables", Kernel.instance_method(:instance_variables).bind(obj).call) o.dump("class variables", klass.class_variables)