irb 1.7.1 → 1.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.document +1 -1
  3. data/Gemfile +10 -1
  4. data/README.md +265 -20
  5. data/Rakefile +13 -10
  6. data/doc/irb/irb.rd.ja +1 -3
  7. data/irb.gemspec +2 -1
  8. data/lib/irb/cmd/nop.rb +3 -52
  9. data/lib/irb/color.rb +4 -2
  10. data/lib/irb/command/backtrace.rb +17 -0
  11. data/lib/irb/command/base.rb +62 -0
  12. data/lib/irb/command/break.rb +17 -0
  13. data/lib/irb/command/catch.rb +17 -0
  14. data/lib/irb/command/chws.rb +40 -0
  15. data/lib/irb/command/context.rb +16 -0
  16. data/lib/irb/{cmd → command}/continue.rb +3 -3
  17. data/lib/irb/command/debug.rb +71 -0
  18. data/lib/irb/{cmd → command}/delete.rb +3 -3
  19. data/lib/irb/command/disable_irb.rb +19 -0
  20. data/lib/irb/command/edit.rb +63 -0
  21. data/lib/irb/command/exit.rb +18 -0
  22. data/lib/irb/{cmd → command}/finish.rb +3 -3
  23. data/lib/irb/command/force_exit.rb +18 -0
  24. data/lib/irb/command/help.rb +83 -0
  25. data/lib/irb/command/history.rb +45 -0
  26. data/lib/irb/command/info.rb +17 -0
  27. data/lib/irb/command/internal_helpers.rb +27 -0
  28. data/lib/irb/{cmd → command}/irb_info.rb +7 -7
  29. data/lib/irb/{cmd → command}/load.rb +23 -8
  30. data/lib/irb/{cmd → command}/ls.rb +42 -19
  31. data/lib/irb/{cmd → command}/measure.rb +18 -17
  32. data/lib/irb/{cmd → command}/next.rb +3 -3
  33. data/lib/irb/command/pushws.rb +65 -0
  34. data/lib/irb/command/show_doc.rb +51 -0
  35. data/lib/irb/command/show_source.rb +74 -0
  36. data/lib/irb/{cmd → command}/step.rb +3 -3
  37. data/lib/irb/command/subirb.rb +123 -0
  38. data/lib/irb/{cmd → command}/whereami.rb +3 -5
  39. data/lib/irb/command.rb +23 -0
  40. data/lib/irb/completion.rb +133 -102
  41. data/lib/irb/context.rb +182 -66
  42. data/lib/irb/debug/ui.rb +103 -0
  43. data/lib/irb/{cmd/debug.rb → debug.rb} +53 -59
  44. data/lib/irb/default_commands.rb +265 -0
  45. data/lib/irb/easter-egg.rb +16 -6
  46. data/lib/irb/ext/change-ws.rb +6 -8
  47. data/lib/irb/ext/{history.rb → eval_history.rb} +7 -7
  48. data/lib/irb/ext/loader.rb +4 -4
  49. data/lib/irb/ext/multi-irb.rb +5 -5
  50. data/lib/irb/ext/tracer.rb +12 -51
  51. data/lib/irb/ext/use-loader.rb +6 -8
  52. data/lib/irb/ext/workspaces.rb +10 -34
  53. data/lib/irb/frame.rb +1 -1
  54. data/lib/irb/help.rb +3 -3
  55. data/lib/irb/helper_method/base.rb +16 -0
  56. data/lib/irb/helper_method/conf.rb +11 -0
  57. data/lib/irb/helper_method.rb +29 -0
  58. data/lib/irb/{ext/save-history.rb → history.rb} +20 -58
  59. data/lib/irb/init.rb +154 -58
  60. data/lib/irb/input-method.rb +238 -203
  61. data/lib/irb/inspector.rb +3 -3
  62. data/lib/irb/lc/error.rb +1 -11
  63. data/lib/irb/lc/help-message +4 -0
  64. data/lib/irb/lc/ja/error.rb +1 -11
  65. data/lib/irb/lc/ja/help-message +13 -0
  66. data/lib/irb/locale.rb +2 -2
  67. data/lib/irb/nesting_parser.rb +13 -3
  68. data/lib/irb/notifier.rb +1 -1
  69. data/lib/irb/output-method.rb +2 -8
  70. data/lib/irb/pager.rb +91 -0
  71. data/lib/irb/ruby-lex.rb +391 -471
  72. data/lib/irb/ruby_logo.aa +43 -0
  73. data/lib/irb/source_finder.rb +139 -0
  74. data/lib/irb/statement.rb +80 -0
  75. data/lib/irb/version.rb +3 -3
  76. data/lib/irb/workspace.rb +24 -4
  77. data/lib/irb/ws-for-case-2.rb +1 -1
  78. data/lib/irb/xmp.rb +3 -3
  79. data/lib/irb.rb +1232 -604
  80. data/man/irb.1 +7 -0
  81. metadata +60 -32
  82. data/lib/irb/cmd/backtrace.rb +0 -21
  83. data/lib/irb/cmd/break.rb +0 -21
  84. data/lib/irb/cmd/catch.rb +0 -21
  85. data/lib/irb/cmd/chws.rb +0 -36
  86. data/lib/irb/cmd/edit.rb +0 -61
  87. data/lib/irb/cmd/help.rb +0 -23
  88. data/lib/irb/cmd/info.rb +0 -21
  89. data/lib/irb/cmd/pushws.rb +0 -45
  90. data/lib/irb/cmd/show_cmds.rb +0 -39
  91. data/lib/irb/cmd/show_doc.rb +0 -48
  92. data/lib/irb/cmd/show_source.rb +0 -113
  93. data/lib/irb/cmd/subirb.rb +0 -66
  94. data/lib/irb/extend-command.rb +0 -356
  95. data/lib/irb/src_encoding.rb +0 -7
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # change-ws.rb -
4
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
5
+ #
6
+ require_relative "../ext/change-ws"
7
+
8
+ module IRB
9
+ # :stopdoc:
10
+
11
+ module Command
12
+
13
+ class CurrentWorkingWorkspace < Base
14
+ category "Workspace"
15
+ description "Show the current workspace."
16
+
17
+ def execute(_arg)
18
+ puts "Current workspace: #{irb_context.main}"
19
+ end
20
+ end
21
+
22
+ class ChangeWorkspace < Base
23
+ category "Workspace"
24
+ description "Change the current workspace to an object."
25
+
26
+ def execute(arg)
27
+ if arg.empty?
28
+ irb_context.change_workspace
29
+ else
30
+ obj = eval(arg, irb_context.workspace.binding)
31
+ irb_context.change_workspace(obj)
32
+ end
33
+
34
+ puts "Current workspace: #{irb_context.main}"
35
+ end
36
+ end
37
+ end
38
+
39
+ # :startdoc:
40
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRB
4
+ module Command
5
+ class Context < Base
6
+ category "IRB"
7
+ description "Displays current configuration."
8
+
9
+ def execute(_arg)
10
+ # This command just displays the configuration.
11
+ # Modifying the configuration is achieved by sending a message to IRB.conf.
12
+ Pager.page_content(IRB.CurrentContext.inspect)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -5,10 +5,10 @@ require_relative "debug"
5
5
  module IRB
6
6
  # :stopdoc:
7
7
 
8
- module ExtendCommand
8
+ module Command
9
9
  class Continue < DebugCommand
10
- def execute(*args)
11
- super(do_cmds: ["continue", *args].join(" "))
10
+ def execute(arg)
11
+ execute_debug_command(do_cmds: "continue #{arg}")
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,71 @@
1
+ require_relative "../debug"
2
+
3
+ module IRB
4
+ # :stopdoc:
5
+
6
+ module Command
7
+ class Debug < Base
8
+ category "Debugging"
9
+ description "Start the debugger of debug.gem."
10
+
11
+ def execute(_arg)
12
+ execute_debug_command
13
+ end
14
+
15
+ def execute_debug_command(pre_cmds: nil, do_cmds: nil)
16
+ pre_cmds = pre_cmds&.rstrip
17
+ do_cmds = do_cmds&.rstrip
18
+
19
+ if irb_context.with_debugger
20
+ # If IRB is already running with a debug session, throw the command and IRB.debug_readline will pass it to the debugger.
21
+ if cmd = pre_cmds || do_cmds
22
+ throw :IRB_EXIT, cmd
23
+ else
24
+ puts "IRB is already running with a debug session."
25
+ return
26
+ end
27
+ else
28
+ # If IRB is not running with a debug session yet, then:
29
+ # 1. Check if the debugging command is run from a `binding.irb` call.
30
+ # 2. If so, try setting up the debug gem.
31
+ # 3. Insert a debug breakpoint at `Irb#debug_break` with the intended command.
32
+ # 4. Exit the current Irb#run call via `throw :IRB_EXIT`.
33
+ # 5. `Irb#debug_break` will be called and trigger the breakpoint, which will run the intended command.
34
+ unless irb_context.from_binding?
35
+ puts "Debugging commands are only available when IRB is started with binding.irb"
36
+ return
37
+ end
38
+
39
+ if IRB.respond_to?(:JobManager)
40
+ warn "Can't start the debugger when IRB is running in a multi-IRB session."
41
+ return
42
+ end
43
+
44
+ unless IRB::Debug.setup(irb_context.irb)
45
+ puts <<~MSG
46
+ You need to install the debug gem before using this command.
47
+ If you use `bundle exec`, please add `gem "debug"` into your Gemfile.
48
+ MSG
49
+ return
50
+ end
51
+
52
+ IRB::Debug.insert_debug_break(pre_cmds: pre_cmds, do_cmds: do_cmds)
53
+
54
+ # exit current Irb#run call
55
+ throw :IRB_EXIT
56
+ end
57
+ end
58
+ end
59
+
60
+ class DebugCommand < Debug
61
+ def self.category
62
+ "Debugging"
63
+ end
64
+
65
+ def self.description
66
+ command_name = self.name.split("::").last.downcase
67
+ "Start the debugger of debug.gem and run its `#{command_name}` command."
68
+ end
69
+ end
70
+ end
71
+ end
@@ -5,10 +5,10 @@ require_relative "debug"
5
5
  module IRB
6
6
  # :stopdoc:
7
7
 
8
- module ExtendCommand
8
+ module Command
9
9
  class Delete < DebugCommand
10
- def execute(*args)
11
- super(pre_cmds: ["delete", *args].join(" "))
10
+ def execute(arg)
11
+ execute_debug_command(pre_cmds: "delete #{arg}")
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRB
4
+ # :stopdoc:
5
+
6
+ module Command
7
+ class DisableIrb < Base
8
+ category "IRB"
9
+ description "Disable binding.irb."
10
+
11
+ def execute(*)
12
+ ::Binding.define_method(:irb) {}
13
+ IRB.irb_exit
14
+ end
15
+ end
16
+ end
17
+
18
+ # :startdoc:
19
+ end
@@ -0,0 +1,63 @@
1
+ require 'shellwords'
2
+
3
+ require_relative "../color"
4
+ require_relative "../source_finder"
5
+
6
+ module IRB
7
+ # :stopdoc:
8
+
9
+ module Command
10
+ class Edit < Base
11
+ include RubyArgsExtractor
12
+
13
+ category "Misc"
14
+ description 'Open a file or source location.'
15
+ help_message <<~HELP_MESSAGE
16
+ Usage: edit [FILE or constant or method signature]
17
+
18
+ Open a file in the editor specified in #{highlight('ENV["VISUAL"]')} or #{highlight('ENV["EDITOR"]')}
19
+
20
+ - If no arguments are provided, IRB will attempt to open the file the current context was defined in.
21
+ - If FILE is provided, IRB will open the file.
22
+ - If a constant or method signature is provided, IRB will attempt to locate the source file and open it.
23
+
24
+ Examples:
25
+
26
+ edit
27
+ edit foo.rb
28
+ edit Foo
29
+ edit Foo#bar
30
+ HELP_MESSAGE
31
+
32
+ def execute(arg)
33
+ # Accept string literal for backward compatibility
34
+ path = unwrap_string_literal(arg)
35
+
36
+ if path.nil?
37
+ path = @irb_context.irb_path
38
+ elsif !File.exist?(path)
39
+ source = SourceFinder.new(@irb_context).find_source(path)
40
+
41
+ if source&.file_exist? && !source.binary_file?
42
+ path = source.file
43
+ end
44
+ end
45
+
46
+ unless File.exist?(path)
47
+ puts "Can not find file: #{path}"
48
+ return
49
+ end
50
+
51
+ if editor = (ENV['VISUAL'] || ENV['EDITOR'])
52
+ puts "command: '#{editor}'"
53
+ puts " path: #{path}"
54
+ system(*Shellwords.split(editor), path)
55
+ else
56
+ puts "Can not find editor setting: ENV['VISUAL'] or ENV['EDITOR']"
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ # :startdoc:
63
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRB
4
+ # :stopdoc:
5
+
6
+ module Command
7
+ class Exit < Base
8
+ category "IRB"
9
+ description "Exit the current irb session."
10
+
11
+ def execute(_arg)
12
+ IRB.irb_exit
13
+ end
14
+ end
15
+ end
16
+
17
+ # :startdoc:
18
+ end
@@ -5,10 +5,10 @@ require_relative "debug"
5
5
  module IRB
6
6
  # :stopdoc:
7
7
 
8
- module ExtendCommand
8
+ module Command
9
9
  class Finish < DebugCommand
10
- def execute(*args)
11
- super(do_cmds: ["finish", *args].join(" "))
10
+ def execute(arg)
11
+ execute_debug_command(do_cmds: "finish #{arg}")
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRB
4
+ # :stopdoc:
5
+
6
+ module Command
7
+ class ForceExit < Base
8
+ category "IRB"
9
+ description "Exit the current process."
10
+
11
+ def execute(_arg)
12
+ throw :IRB_EXIT, true
13
+ end
14
+ end
15
+ end
16
+
17
+ # :startdoc:
18
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRB
4
+ module Command
5
+ class Help < Base
6
+ category "Help"
7
+ description "List all available commands. Use `help <command>` to get information about a specific command."
8
+
9
+ def execute(command_name)
10
+ content =
11
+ if command_name.empty?
12
+ help_message
13
+ else
14
+ if command_class = Command.load_command(command_name)
15
+ command_class.help_message || command_class.description
16
+ else
17
+ "Can't find command `#{command_name}`. Please check the command name and try again.\n\n"
18
+ end
19
+ end
20
+ Pager.page_content(content)
21
+ end
22
+
23
+ private
24
+
25
+ def help_message
26
+ commands_info = IRB::Command.all_commands_info
27
+ helper_methods_info = IRB::HelperMethod.all_helper_methods_info
28
+ commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
29
+ commands_grouped_by_categories["Helper methods"] = helper_methods_info
30
+
31
+ if irb_context.with_debugger
32
+ # Remove the original "Debugging" category
33
+ commands_grouped_by_categories.delete("Debugging")
34
+ end
35
+
36
+ longest_cmd_name_length = commands_info.map { |c| c[:display_name].length }.max
37
+
38
+ output = StringIO.new
39
+
40
+ help_cmds = commands_grouped_by_categories.delete("Help")
41
+ no_category_cmds = commands_grouped_by_categories.delete("No category")
42
+ aliases = irb_context.instance_variable_get(:@user_aliases).map do |alias_name, target|
43
+ { display_name: alias_name, description: "Alias for `#{target}`" }
44
+ end
45
+
46
+ # Display help commands first
47
+ add_category_to_output("Help", help_cmds, output, longest_cmd_name_length)
48
+
49
+ # Display the rest of the commands grouped by categories
50
+ commands_grouped_by_categories.each do |category, cmds|
51
+ add_category_to_output(category, cmds, output, longest_cmd_name_length)
52
+ end
53
+
54
+ # Display commands without a category
55
+ if no_category_cmds
56
+ add_category_to_output("No category", no_category_cmds, output, longest_cmd_name_length)
57
+ end
58
+
59
+ # Display aliases
60
+ add_category_to_output("Aliases", aliases, output, longest_cmd_name_length)
61
+
62
+ # Append the debugger help at the end
63
+ if irb_context.with_debugger
64
+ # Add "Debugging (from debug.gem)" category as title
65
+ add_category_to_output("Debugging (from debug.gem)", [], output, longest_cmd_name_length)
66
+ output.puts DEBUGGER__.help
67
+ end
68
+
69
+ output.string
70
+ end
71
+
72
+ def add_category_to_output(category, cmds, output, longest_cmd_name_length)
73
+ output.puts Color.colorize(category, [:BOLD])
74
+
75
+ cmds.each do |cmd|
76
+ output.puts " #{cmd[:display_name].to_s.ljust(longest_cmd_name_length)} #{cmd[:description]}"
77
+ end
78
+
79
+ output.puts
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ require_relative "../pager"
6
+
7
+ module IRB
8
+ # :stopdoc:
9
+
10
+ module Command
11
+ class History < Base
12
+ category "IRB"
13
+ description "Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output."
14
+
15
+ def execute(arg)
16
+
17
+ if (match = arg&.match(/(-g|-G)\s+(?<grep>.+)\s*\n\z/))
18
+ grep = Regexp.new(match[:grep])
19
+ end
20
+
21
+ formatted_inputs = irb_context.io.class::HISTORY.each_with_index.reverse_each.filter_map do |input, index|
22
+ next if grep && !input.match?(grep)
23
+
24
+ header = "#{index}: "
25
+
26
+ first_line, *other_lines = input.split("\n")
27
+ first_line = "#{header}#{first_line}"
28
+
29
+ truncated_lines = other_lines.slice!(1..) # Show 1 additional line (2 total)
30
+ other_lines << "..." if truncated_lines&.any?
31
+
32
+ other_lines.map! do |line|
33
+ " " * header.length + line
34
+ end
35
+
36
+ [first_line, *other_lines].join("\n") + "\n"
37
+ end
38
+
39
+ Pager.page_content(formatted_inputs.join)
40
+ end
41
+ end
42
+ end
43
+
44
+ # :startdoc:
45
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "debug"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module Command
9
+ class Info < DebugCommand
10
+ def execute(arg)
11
+ execute_debug_command(pre_cmds: "info #{arg}")
12
+ end
13
+ end
14
+ end
15
+
16
+ # :startdoc:
17
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IRB
4
+ module Command
5
+ # Internal use only, for default command's backward compatibility.
6
+ module RubyArgsExtractor # :nodoc:
7
+ def unwrap_string_literal(str)
8
+ return if str.empty?
9
+
10
+ sexp = Ripper.sexp(str)
11
+ if sexp && sexp.size == 2 && sexp.last&.first&.first == :string_literal
12
+ @irb_context.workspace.binding.eval(str).to_s
13
+ else
14
+ str
15
+ end
16
+ end
17
+
18
+ def ruby_args(arg)
19
+ # Use throw and catch to handle arg that includes `;`
20
+ # For example: "1, kw: (2; 3); 4" will be parsed to [[1], { kw: 3 }]
21
+ catch(:EXTRACT_RUBY_ARGS) do
22
+ @irb_context.workspace.binding.eval "IRB::Command.extract_ruby_args #{arg}"
23
+ end || [[], {}]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,20 +1,20 @@
1
- # frozen_string_literal: false
2
-
3
- require_relative "nop"
1
+ # frozen_string_literal: true
4
2
 
5
3
  module IRB
6
4
  # :stopdoc:
7
5
 
8
- module ExtendCommand
9
- class IrbInfo < Nop
6
+ module Command
7
+ class IrbInfo < Base
10
8
  category "IRB"
11
9
  description "Show information about IRB."
12
10
 
13
- def execute
11
+ def execute(_arg)
14
12
  str = "Ruby version: #{RUBY_VERSION}\n"
15
13
  str += "IRB version: #{IRB.version}\n"
16
14
  str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
17
- str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
15
+ str += "Completion: #{IRB.CurrentContext.io.respond_to?(:completion_info) ? IRB.CurrentContext.io.completion_info : 'off'}\n"
16
+ rc_files = IRB.irbrc_files
17
+ str += ".irbrc paths: #{rc_files.join(", ")}\n" if rc_files.any?
18
18
  str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
19
19
  str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
20
20
  str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
@@ -1,17 +1,16 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  #
3
3
  # load.rb -
4
4
  # by Keiju ISHITSUKA(keiju@ruby-lang.org)
5
5
  #
6
-
7
- require_relative "nop"
8
6
  require_relative "../ext/loader"
9
7
 
10
8
  module IRB
11
9
  # :stopdoc:
12
10
 
13
- module ExtendCommand
14
- class LoaderCommand < Nop
11
+ module Command
12
+ class LoaderCommand < Base
13
+ include RubyArgsExtractor
15
14
  include IrbLoader
16
15
 
17
16
  def raise_cmd_argument_error
@@ -23,7 +22,12 @@ module IRB
23
22
  category "IRB"
24
23
  description "Load a Ruby file."
25
24
 
26
- def execute(file_name = nil, priv = nil)
25
+ def execute(arg)
26
+ args, kwargs = ruby_args(arg)
27
+ execute_internal(*args, **kwargs)
28
+ end
29
+
30
+ def execute_internal(file_name = nil, priv = nil)
27
31
  raise_cmd_argument_error unless file_name
28
32
  irb_load(file_name, priv)
29
33
  end
@@ -32,7 +36,13 @@ module IRB
32
36
  class Require < LoaderCommand
33
37
  category "IRB"
34
38
  description "Require a Ruby file."
35
- def execute(file_name = nil)
39
+
40
+ def execute(arg)
41
+ args, kwargs = ruby_args(arg)
42
+ execute_internal(*args, **kwargs)
43
+ end
44
+
45
+ def execute_internal(file_name = nil)
36
46
  raise_cmd_argument_error unless file_name
37
47
 
38
48
  rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
@@ -65,7 +75,12 @@ module IRB
65
75
  category "IRB"
66
76
  description "Loads a given file in the current session."
67
77
 
68
- def execute(file_name = nil)
78
+ def execute(arg)
79
+ args, kwargs = ruby_args(arg)
80
+ execute_internal(*args, **kwargs)
81
+ end
82
+
83
+ def execute_internal(file_name = nil)
69
84
  raise_cmd_argument_error unless file_name
70
85
 
71
86
  source_file(file_name)
@@ -1,39 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "reline"
4
- require_relative "nop"
4
+ require "stringio"
5
+
6
+ require_relative "../pager"
5
7
  require_relative "../color"
6
8
 
7
9
  module IRB
8
10
  # :stopdoc:
9
11
 
10
- module ExtendCommand
11
- class Ls < Nop
12
+ module Command
13
+ class Ls < Base
14
+ include RubyArgsExtractor
15
+
12
16
  category "Context"
13
- description "Show methods, constants, and variables. `-g [query]` or `-G [query]` allows you to filter out the output."
17
+ description "Show methods, constants, and variables."
18
+
19
+ help_message <<~HELP_MESSAGE
20
+ Usage: ls [obj] [-g [query]]
14
21
 
15
- def self.transform_args(args)
16
- if match = args&.match(/\A(?<args>.+\s|)(-g|-G)\s+(?<grep>[^\s]+)\s*\n\z/)
17
- args = match[:args]
18
- "#{args}#{',' unless args.chomp.empty?} grep: /#{match[:grep]}/"
22
+ -g [query] Filter the output with a query.
23
+ HELP_MESSAGE
24
+
25
+ def execute(arg)
26
+ if match = arg.match(/\A(?<target>.+\s|)(-g|-G)\s+(?<grep>.+)$/)
27
+ if match[:target].empty?
28
+ use_main = true
29
+ else
30
+ obj = @irb_context.workspace.binding.eval(match[:target])
31
+ end
32
+ grep = Regexp.new(match[:grep])
19
33
  else
20
- args
34
+ args, kwargs = ruby_args(arg)
35
+ use_main = args.empty?
36
+ obj = args.first
37
+ grep = kwargs[:grep]
38
+ end
39
+
40
+ if use_main
41
+ obj = irb_context.workspace.main
42
+ locals = irb_context.workspace.binding.local_variables
21
43
  end
22
- end
23
44
 
24
- def execute(*arg, grep: nil)
25
45
  o = Output.new(grep: grep)
26
46
 
27
- obj = arg.empty? ? irb_context.workspace.main : arg.first
28
- locals = arg.empty? ? irb_context.workspace.binding.local_variables : []
29
47
  klass = (obj.class == Class || obj.class == Module ? obj : obj.class)
30
48
 
31
49
  o.dump("constants", obj.constants) if obj.respond_to?(:constants)
32
50
  dump_methods(o, klass, obj)
33
51
  o.dump("instance variables", obj.instance_variables)
34
52
  o.dump("class variables", klass.class_variables)
35
- o.dump("locals", locals)
36
- nil
53
+ o.dump("locals", locals) if locals
54
+ o.print_result
37
55
  end
38
56
 
39
57
  def dump_methods(o, klass, obj)
@@ -77,6 +95,11 @@ module IRB
77
95
  def initialize(grep: nil)
78
96
  @grep = grep
79
97
  @line_width = screen_width - MARGIN.length # right padding
98
+ @io = StringIO.new
99
+ end
100
+
101
+ def print_result
102
+ Pager.page_content(@io.string)
80
103
  end
81
104
 
82
105
  def dump(name, strs)
@@ -85,12 +108,12 @@ module IRB
85
108
  return if strs.empty?
86
109
 
87
110
  # Attempt a single line
88
- print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
111
+ @io.print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
89
112
  if fits_on_line?(strs, cols: strs.size, offset: "#{name}: ".length)
90
- puts strs.join(MARGIN)
113
+ @io.puts strs.join(MARGIN)
91
114
  return
92
115
  end
93
- puts
116
+ @io.puts
94
117
 
95
118
  # Dump with the largest # of columns that fits on a line
96
119
  cols = strs.size
@@ -99,7 +122,7 @@ module IRB
99
122
  end
100
123
  widths = col_widths(strs, cols: cols)
101
124
  strs.each_slice(cols) do |ss|
102
- puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
125
+ @io.puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
103
126
  end
104
127
  end
105
128