diff options
author | Stan Lo <stan001212@gmail.com> | 2023-02-28 22:36:06 +0800 |
---|---|---|
committer | git <svn-admin@ruby-lang.org> | 2023-02-28 14:36:12 +0000 |
commit | 9ddd73060bb64ef6da38f77fc032ac852636de99 (patch) | |
tree | 430ec538a1e06577d95194bcaa3fe6c1cdb849ed | |
parent | 2d6097a0f588527a6b23679fc1503c361c068200 (diff) | |
download | ruby-9ddd73060bb64ef6da38f77fc032ac852636de99.tar.gz |
[ruby/irb] Display and prioritise instance methods in `ls
<module/class>`
(https://github.com/ruby/irb/pull/496)
https://github.com/ruby/irb/commit/e3d21f9329
-rw-r--r-- | lib/irb/cmd/ls.rb | 27 | ||||
-rw-r--r-- | test/irb/test_cmd.rb | 60 |
2 files changed, 80 insertions, 7 deletions
diff --git a/lib/irb/cmd/ls.rb b/lib/irb/cmd/ls.rb index b65fae2bf1..d5a371a4d6 100644 --- a/lib/irb/cmd/ls.rb +++ b/lib/irb/cmd/ls.rb @@ -38,21 +38,34 @@ module IRB def dump_methods(o, klass, obj) singleton_class = begin obj.singleton_class; rescue TypeError; nil end - maps = class_method_map((singleton_class || klass).ancestors) + dumped_mods = Array.new + # singleton_class' ancestors should be at the front + maps = class_method_map(singleton_class&.ancestors || [], dumped_mods) + class_method_map(klass.ancestors, dumped_mods) maps.each do |mod, methods| name = mod == singleton_class ? "#{klass}.methods" : "#{mod}#methods" o.dump(name, methods) end end - def class_method_map(classes) - dumped = Array.new - classes.reject { |mod| mod >= Object }.map do |mod| - methods = mod.public_instance_methods(false).select do |m| - dumped.push(m) unless dumped.include?(m) + def class_method_map(classes, dumped_mods) + dumped_methods = Array.new + classes = classes.reject { |mod| mod >= Object } + classes.map do |mod| + next if dumped_mods.include? mod + + dumped_mods << mod + + methods = mod.public_instance_methods(false).select do |method| + if dumped_methods.include? method + false + else + dumped_methods << method + true + end end + [mod, methods] - end.reverse + end.compact end class Output diff --git a/test/irb/test_cmd.rb b/test/irb/test_cmd.rb index c2d952cc44..dc71c784e9 100644 --- a/test/irb/test_cmd.rb +++ b/test/irb/test_cmd.rb @@ -672,6 +672,66 @@ module TestIRB assert_match(/C.methods:\s+m5\n/m, out) end + def test_ls_class + out, err = execute_lines( + "module M1\n", + " def m2; end\n", + " def m3; end\n", + "end\n", + + "class C1\n", + " def m1; end\n", + " def m2; end\n", + "end\n", + + "class C2 < C1\n", + " include M1\n", + " def m3; end\n", + " def m4; end\n", + " def self.m3; end\n", + " def self.m5; end\n", + "end\n", + "ls C2" + ) + + assert_empty err + assert_match(/C2.methods:\s+m3\s+m5\n/, out) + assert_match(/C2#methods:\s+m3\s+m4\n.*M1#methods:\s+m2\n.*C1#methods:\s+m1\n/, out) + end + + def test_ls_module + out, err = execute_lines( + "module M1\n", + " def m1; end\n", + " def m2; end\n", + "end\n", + + "module M2\n", + " include M1\n", + " def m1; end\n", + " def m3; end\n", + " def self.m4; end\n", + "end\n", + "ls M2" + ) + + assert_empty err + assert_match(/M2\.methods:\s+m4\nModule#methods:/, out) + assert_match(/M2#methods:\s+m1\s+m3\n.*M1#methods:\s+m2\n/, out) + end + + def test_ls_instance + out, err = execute_lines( + "class Foo; def bar; end; end\n", + "ls Foo.new" + ) + + assert_empty err + assert_match(/Foo#methods:\s+bar/, out) + # don't duplicate + assert_not_match(/Foo#methods:\s+bar\n.*Foo#methods/, out) + end + def test_ls_grep pend if RUBY_ENGINE == 'truffleruby' out, err = execute_lines("ls 42\n") |