From 19b6c2060405583f9ac64db1d87f3bedfbe053f5 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Thu, 18 Mar 2021 00:28:04 -0700 Subject: [PATCH] Implement ls command --- lib/irb/cmd/ls.rb | 48 +++++++++++++++++++++++++++++++++++++++ lib/irb/cmd/nop.rb | 14 ++++++++---- lib/irb/extend-command.rb | 12 +++++++--- test/irb/test_cmd.rb | 17 ++++++++++++++ 4 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 lib/irb/cmd/ls.rb diff --git a/lib/irb/cmd/ls.rb b/lib/irb/cmd/ls.rb new file mode 100644 index 000000000..c39937d4d --- /dev/null +++ b/lib/irb/cmd/ls.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require_relative "nop" +require_relative "../color" + +# :stopdoc: +module IRB + module ExtendCommand + class Ls < Nop + def execute(*arg, grep: nil) + o = Output.new(grep: grep) + + obj = arg.empty? ? irb_context.workspace.main : arg.first + locals = arg.empty? ? irb_context.workspace.binding.local_variables : [] + klass = (obj.class == Class || obj.class == Module ? obj : obj.class) + + o.dump("constants", obj.constants) if obj.respond_to?(:constants) + o.dump("#{klass}.methods", obj.singleton_methods(false)) + o.dump("#{klass}#methods", klass.public_instance_methods(false)) + o.dump("instance variables", obj.instance_variables) + o.dump("class variables", klass.class_variables) + o.dump("locals", locals) + end + + class Output + def initialize(grep: nil) + @grep = grep + end + + def dump(name, strs) + strs = strs.grep(@grep) if @grep + strs = strs.sort + return if strs.empty? + + print "#{Color.colorize(name, [:BOLD, :BLUE])}: " + if strs.size > 7 + len = [strs.map(&:length).max, 16].min + puts; strs.each_slice(7) { |ss| puts " #{ss.map { |s| "%-#{len}s" % s }.join(" ")}" } + else + puts strs.join(" ") + end + end + end + private_constant :Output + end + end +end +# :startdoc: diff --git a/lib/irb/cmd/nop.rb b/lib/irb/cmd/nop.rb index fa3c011b5..d6f7a611a 100644 --- a/lib/irb/cmd/nop.rb +++ b/lib/irb/cmd/nop.rb @@ -14,10 +14,16 @@ module IRB module ExtendCommand class Nop - - def self.execute(conf, *opts, &block) - command = new(conf) - command.execute(*opts, &block) + if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0" + def self.execute(conf, *opts, **kwargs, &block) + command = new(conf) + command.execute(*opts, **kwargs, &block) + end + else + def self.execute(conf, *opts, &block) + command = new(conf) + command.execute(*opts, &block) + end end def initialize(conf) diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb index af076a615..e7b046ad4 100644 --- a/lib/irb/extend-command.rb +++ b/lib/irb/extend-command.rb @@ -125,6 +125,11 @@ def irb_context :irb_info, :Info, "irb/cmd/info" ], + [ + :irb_ls, :Ls, "irb/cmd/ls", + [:ls, NO_OVERRIDE], + ], + [ :irb_measure, :Measure, "irb/cmd/measure", [:measure, NO_OVERRIDE], @@ -169,12 +174,13 @@ def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases) end if load_file + kwargs = ", **kwargs" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0" line = __LINE__; eval %[ - def #{cmd_name}(*opts, &b) + def #{cmd_name}(*opts#{kwargs}, &b) require "#{load_file}" arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s } - args << "*opts" if arity < 0 + args << "*opts#{kwargs}" if arity < 0 args << "&block" args = args.join(", ") line = __LINE__; eval %[ @@ -185,7 +191,7 @@ def self.#{cmd_name}_(\#{args}) end end ], nil, __FILE__, line - __send__ :#{cmd_name}_, *opts, &b + __send__ :#{cmd_name}_, *opts#{kwargs}, &b end ], nil, __FILE__, line else diff --git a/test/irb/test_cmd.rb b/test/irb/test_cmd.rb index 41f84f192..4ff8657a2 100644 --- a/test/irb/test_cmd.rb +++ b/test/irb/test_cmd.rb @@ -372,5 +372,22 @@ def test_irb_load /=> "bug17564"\n/, ], out) end + + def test_ls + IRB.init_config(nil) + workspace = IRB::WorkSpace.new(self) + irb = IRB::Irb.new(workspace) + IRB.conf[:MAIN_CONTEXT] = irb.context + input = TestInputMethod.new([ + "ls Object.new.tap { |o| o.instance_variable_set(:@a, 1) }\n", + ]) + irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) + irb.context.return_format = "=> %s\n" + out, err = capture_output do + irb.eval_input + end + assert_empty err + assert_match(/^instance variables: @a\n/, out) + end end end