irb 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 33ff0b70fb3730f087bc24a7a8b63253ba1a4ad0416a0ffcd1e5395f26e5d0b2
4
- data.tar.gz: 9cd418e90733c4cb4658368b2a899b50490ad9dbd7352a1c1df0070c10d9669d
3
+ metadata.gz: 2df1f78bfd3e28e4102262fc4b9011d6c84c7690cba11f870e6e9f54e8718ebe
4
+ data.tar.gz: 20d55eba407c974060b73fc4ba741d534da8f933f65ec1bb03e85ba36129dc01
5
5
  SHA512:
6
- metadata.gz: ec6102a41d55404aa8e5585243cbe74fcdbe1e1d5bcd88ddae4240adff4281d14200b99c621324515a4e226eff5964644a7e8456d707af2ca7dcf8e5211a0b4b
7
- data.tar.gz: 0ed81d78ce49803706b36f36e173acb1e27f3e217bd3c6e00e46d4875b6be3c7958a2cb3db146703c3cbf7198094561a562e0fd244f6a61501f9ae5196df343a
6
+ metadata.gz: a829406c154fb4cb7d877ebe95bfb8ab20dd894e6adaaa4fd05ee198740f2deff0a449c469ff1c388075424b04ecd28db6bb3298c345c46b9c821ffb8f1d4ad4
7
+ data.tar.gz: 0fde56ad653b34522edcc1f9d5f8d2524ced3551b1f1f3ff1b99226b8263433b27c416b10121ae6fdeb2ed82541341fe6dfd8e8e1ff712d01e3c32d69b6707b6
data/Gemfile CHANGED
@@ -11,4 +11,5 @@ group :development do
11
11
  gem "stackprof" if is_unix && !is_truffleruby
12
12
  gem "test-unit"
13
13
  gem "reline", github: "ruby/reline" if ENV["WITH_LATEST_RELINE"] == "true"
14
+ gem "debug", github: "ruby/debug"
14
15
  end
data/README.md CHANGED
@@ -42,54 +42,57 @@ The Readline extension module can be used with irb. Use of Readline is default i
42
42
 
43
43
  ## Commands
44
44
 
45
- The following commands are available on IRB.
46
-
47
- * `cwws`
48
- * Show the current workspace.
49
- * `cb`, `cws`, `chws`
50
- * Change the current workspace to an object.
51
- * `bindings`, `workspaces`
52
- * Show workspaces.
53
- * `edit`
54
- * Open a file with the editor command defined with `ENV["EDITOR"]`
55
- * `edit` - opens the file the current context belongs to (if applicable)
56
- * `edit foo.rb` - opens `foo.rb`
57
- * `edit Foo` - opens the location of `Foo`
58
- * `edit Foo.bar` - opens the location of `Foo.bar`
59
- * `edit Foo#bar` - opens the location of `Foo#bar`
60
- * `pushb`, `pushws`
61
- * Push an object to the workspace stack.
62
- * `popb`, `popws`
63
- * Pop a workspace from the workspace stack.
64
- * `load`
65
- * Load a Ruby file.
66
- * `require`
67
- * Require a Ruby file.
68
- * `source`
69
- * Loads a given file in the current session.
70
- * `irb`
71
- * Start a child IRB.
72
- * `jobs`
73
- * List of current sessions.
74
- * `fg`
75
- * Switches to the session of the given number.
76
- * `kill`
77
- * Kills the session with the given number.
78
- * `help`
79
- * Enter the mode to look up RI documents.
80
- * `irb_info`
81
- * Show information about IRB.
82
- * `ls`
83
- * Show methods, constants, and variables.
84
- `-g [query]` or `-G [query]` allows you to filter out the output.
85
- * `measure`
86
- * `measure` enables the mode to measure processing time. `measure :off` disables it.
87
- * `$`, `show_source`
88
- * Show the source code of a given method or constant.
89
- * `@`, `whereami`
90
- * Show the source code around binding.irb again.
91
- * `debug`
92
- * Start the debugger of debug.gem.
45
+ The following commands are available on IRB. You can get the same output from the `show_cmds` command.
46
+
47
+
48
+ ```
49
+ IRB
50
+ cwws Show the current workspace.
51
+ chws Change the current workspace to an object.
52
+ workspaces Show workspaces.
53
+ pushws Push an object to the workspace stack.
54
+ popws Pop a workspace from the workspace stack.
55
+ irb_load Load a Ruby file.
56
+ irb_require Require a Ruby file.
57
+ source Loads a given file in the current session.
58
+ irb Start a child IRB.
59
+ jobs List of current sessions.
60
+ fg Switches to the session of the given number.
61
+ kill Kills the session with the given number.
62
+ irb_info Show information about IRB.
63
+ show_cmds List all available commands and their description.
64
+
65
+ Debugging
66
+ debug Start the debugger of debug.gem.
67
+ break Start the debugger of debug.gem and run its `break` command.
68
+ catch Start the debugger of debug.gem and run its `catch` command.
69
+ next Start the debugger of debug.gem and run its `next` command.
70
+ delete Start the debugger of debug.gem and run its `delete` command.
71
+ step Start the debugger of debug.gem and run its `step` command.
72
+ continue Start the debugger of debug.gem and run its `continue` command.
73
+ finish Start the debugger of debug.gem and run its `finish` command.
74
+ backtrace Start the debugger of debug.gem and run its `backtrace` command.
75
+ info Start the debugger of debug.gem and run its `info` command.
76
+
77
+ Misc
78
+ edit Open a file with the editor command defined with `ENV["EDITOR"]`.
79
+ measure `measure` enables the mode to measure processing time. `measure :off` disables it.
80
+
81
+ Context
82
+ show_doc Enter the mode to look up RI documents.
83
+ ls Show methods, constants, and variables. `-g [query]` or `-G [query]` allows you to filter out the output.
84
+ show_source Show the source code of a given method or constant.
85
+ whereami Show the source code around binding.irb again.
86
+ ```
87
+
88
+ ## Configuration
89
+
90
+ ### Environment Variables
91
+
92
+ - `NO_COLOR`: Assigning a value to it disables IRB's colorization.
93
+ - `IRB_USE_AUTOCOMPLETE`: Setting it to `false` disables IRB's autocompletion.
94
+ - `EDITOR`: Its value would be used to open files by the `edit` command.
95
+ - `IRBRC`: The file specified would be evaluated as IRB's rc-file.
93
96
 
94
97
  ## Documentation
95
98
 
@@ -105,6 +108,13 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
105
108
 
106
109
  Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/irb.
107
110
 
111
+ ## Releasing
112
+
113
+ ```
114
+ rake release
115
+ gh release create vX.Y.Z --generate-notes
116
+ ```
117
+
108
118
  ## License
109
119
 
110
120
  The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "debug"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module ExtendCommand
9
+ class Backtrace < DebugCommand
10
+ def self.transform_args(args)
11
+ args&.dump
12
+ end
13
+
14
+ def execute(*args)
15
+ super(pre_cmds: ["backtrace", *args].join(" "))
16
+ end
17
+ end
18
+ end
19
+
20
+ # :startdoc:
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "debug"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module ExtendCommand
9
+ class Break < DebugCommand
10
+ def self.transform_args(args)
11
+ args&.dump
12
+ end
13
+
14
+ def execute(args = nil)
15
+ super(pre_cmds: "break #{args}")
16
+ end
17
+ end
18
+ end
19
+
20
+ # :startdoc:
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "debug"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module ExtendCommand
9
+ class Catch < DebugCommand
10
+ def self.transform_args(args)
11
+ args&.dump
12
+ end
13
+
14
+ def execute(*args)
15
+ super(pre_cmds: ["catch", *args].join(" "))
16
+ end
17
+ end
18
+ end
19
+
20
+ # :startdoc:
21
+ end
data/lib/irb/cmd/chws.rb CHANGED
@@ -19,12 +19,18 @@ module IRB
19
19
  module ExtendCommand
20
20
 
21
21
  class CurrentWorkingWorkspace < Nop
22
+ category "IRB"
23
+ description "Show the current workspace."
24
+
22
25
  def execute(*obj)
23
26
  irb_context.main
24
27
  end
25
28
  end
26
29
 
27
30
  class ChangeWorkspace < Nop
31
+ category "IRB"
32
+ description "Change the current workspace to an object."
33
+
28
34
  def execute(*obj)
29
35
  irb_context.change_workspace(*obj)
30
36
  irb_context.main
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "debug"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module ExtendCommand
9
+ class Continue < DebugCommand
10
+ def execute(*args)
11
+ super(do_cmds: ["continue", *args].join(" "))
12
+ end
13
+ end
14
+ end
15
+
16
+ # :startdoc:
17
+ end
data/lib/irb/cmd/debug.rb CHANGED
@@ -5,13 +5,16 @@ module IRB
5
5
 
6
6
  module ExtendCommand
7
7
  class Debug < Nop
8
+ category "Debugging"
9
+ description "Start the debugger of debug.gem."
10
+
8
11
  BINDING_IRB_FRAME_REGEXPS = [
9
12
  '<internal:prelude>',
10
13
  binding.method(:irb).source_location.first,
11
14
  ].map { |file| /\A#{Regexp.escape(file)}:\d+:in `irb'\z/ }
12
15
  IRB_DIR = File.expand_path('..', __dir__)
13
16
 
14
- def execute(*args)
17
+ def execute(pre_cmds: nil, do_cmds: nil)
15
18
  unless binding_irb?
16
19
  puts "`debug` command is only available when IRB is started with binding.irb"
17
20
  return
@@ -25,11 +28,19 @@ module IRB
25
28
  return
26
29
  end
27
30
 
31
+ options = { oneshot: true, hook_call: false }
32
+ if pre_cmds || do_cmds
33
+ options[:command] = ['irb', pre_cmds, do_cmds]
34
+ end
35
+ if DEBUGGER__::LineBreakpoint.instance_method(:initialize).parameters.include?([:key, :skip_src])
36
+ options[:skip_src] = true
37
+ end
38
+
28
39
  # To make debugger commands like `next` or `continue` work without asking
29
40
  # the user to quit IRB after that, we need to exit IRB first and then hit
30
41
  # a TracePoint on #debug_break.
31
42
  file, lineno = IRB::Irb.instance_method(:debug_break).source_location
32
- DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, oneshot: true, hook_call: false)
43
+ DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, **options)
33
44
  # exit current Irb#run call
34
45
  throw :IRB_EXIT
35
46
  end
@@ -74,14 +85,22 @@ module IRB
74
85
  # it's a bundled gem. This method tries to activate and load that.
75
86
  def load_bundled_debug_gem
76
87
  # Discover latest debug.gem under GEM_PATH
77
- debug_gem = Gem.paths.path.map { |path| Dir.glob("#{path}/gems/debug-*") }.flatten.select do |path|
78
- File.basename(path).match?(/\Adebug-\d+\.\d+\.\d+\z/)
88
+ debug_gem = Gem.paths.path.flat_map { |path| Dir.glob("#{path}/gems/debug-*") }.select do |path|
89
+ File.basename(path).match?(/\Adebug-\d+\.\d+\.\d+(\w+)?\z/)
79
90
  end.sort_by do |path|
80
91
  Gem::Version.new(File.basename(path).delete_prefix('debug-'))
81
92
  end.last
82
93
  return false unless debug_gem
83
94
 
95
+ # Discover debug/debug.so under extensions for Ruby 3.2+
96
+ debug_so = Gem.paths.path.flat_map do |path|
97
+ Dir.glob("#{path}/extensions/**/#{File.basename(debug_gem)}/debug/debug.so")
98
+ end.first
99
+
84
100
  # Attempt to forcibly load the bundled gem
101
+ if debug_so
102
+ $LOAD_PATH << debug_so.delete_suffix('/debug/debug.so')
103
+ end
85
104
  $LOAD_PATH << "#{debug_gem}/lib"
86
105
  begin
87
106
  require "debug/session"
@@ -92,5 +111,16 @@ module IRB
92
111
  end
93
112
  end
94
113
  end
114
+
115
+ class DebugCommand < Debug
116
+ def self.category
117
+ "Debugging"
118
+ end
119
+
120
+ def self.description
121
+ command_name = self.name.split("::").last.downcase
122
+ "Start the debugger of debug.gem and run its `#{command_name}` command."
123
+ end
124
+ end
95
125
  end
96
126
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "debug"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module ExtendCommand
9
+ class Delete < DebugCommand
10
+ def execute(*args)
11
+ super(pre_cmds: ["delete", *args].join(" "))
12
+ end
13
+ end
14
+ end
15
+
16
+ # :startdoc:
17
+ end
data/lib/irb/cmd/edit.rb CHANGED
@@ -6,6 +6,9 @@ module IRB
6
6
 
7
7
  module ExtendCommand
8
8
  class Edit < Nop
9
+ category "Misc"
10
+ description 'Open a file with the editor command defined with `ENV["EDITOR"]`.'
11
+
9
12
  class << self
10
13
  def transform_args(args)
11
14
  # Return a string literal as is for backward compatibility
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "debug"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module ExtendCommand
9
+ class Finish < DebugCommand
10
+ def execute(*args)
11
+ super(do_cmds: ["finish", *args].join(" "))
12
+ end
13
+ end
14
+ end
15
+
16
+ # :startdoc:
17
+ end
data/lib/irb/cmd/help.rb CHANGED
@@ -16,6 +16,9 @@ module IRB
16
16
 
17
17
  module ExtendCommand
18
18
  class Help < Nop
19
+ category "Context"
20
+ description "Enter the mode to look up RI documents."
21
+
19
22
  def execute(*names)
20
23
  require 'rdoc/ri/driver'
21
24
  opts = RDoc::RI::Driver.process_args([])
data/lib/irb/cmd/info.rb CHANGED
@@ -1,31 +1,18 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
 
3
- require_relative "nop"
3
+ require_relative "debug"
4
4
 
5
5
  module IRB
6
6
  # :stopdoc:
7
7
 
8
8
  module ExtendCommand
9
- class Info < Nop
10
- def execute
11
- Class.new {
12
- def inspect
13
- str = "Ruby version: #{RUBY_VERSION}\n"
14
- str += "IRB version: #{IRB.version}\n"
15
- str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
16
- str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
17
- str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
18
- str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
19
- str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
20
- str += "East Asian Ambiguous Width: #{Reline.ambiguous_width.inspect}\n"
21
- if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
22
- codepage = `chcp`.b.sub(/.*: (\d+)\n/, '\1')
23
- str += "Code page: #{codepage}\n"
24
- end
25
- str
26
- end
27
- alias_method :to_s, :inspect
28
- }.new
9
+ class Info < DebugCommand
10
+ def self.transform_args(args)
11
+ args&.dump
12
+ end
13
+
14
+ def execute(*args)
15
+ super(pre_cmds: ["info", *args].join(" "))
29
16
  end
30
17
  end
31
18
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative "nop"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module ExtendCommand
9
+ class IrbInfo < Nop
10
+ category "IRB"
11
+ description "Show information about IRB."
12
+
13
+ def execute
14
+ Class.new {
15
+ def inspect
16
+ str = "Ruby version: #{RUBY_VERSION}\n"
17
+ str += "IRB version: #{IRB.version}\n"
18
+ str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
19
+ str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
20
+ str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
21
+ str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
22
+ str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
23
+ str += "East Asian Ambiguous Width: #{Reline.ambiguous_width.inspect}\n"
24
+ if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
25
+ codepage = `chcp`.b.sub(/.*: (\d+)\n/, '\1')
26
+ str += "Code page: #{codepage}\n"
27
+ end
28
+ str
29
+ end
30
+ alias_method :to_s, :inspect
31
+ }.new
32
+ end
33
+ end
34
+ end
35
+
36
+ # :startdoc:
37
+ end
data/lib/irb/cmd/load.rb CHANGED
@@ -17,18 +17,29 @@ module IRB
17
17
  # :stopdoc:
18
18
 
19
19
  module ExtendCommand
20
- class Load < Nop
20
+ class LoaderCommand < Nop
21
21
  include IrbLoader
22
22
 
23
- def execute(file_name, priv = nil)
24
- return irb_load(file_name, priv)
23
+ def raise_cmd_argument_error
24
+ raise CommandArgumentError.new("Please specify the file name.")
25
25
  end
26
26
  end
27
27
 
28
- class Require < Nop
29
- include IrbLoader
28
+ class Load < LoaderCommand
29
+ category "IRB"
30
+ description "Load a Ruby file."
31
+
32
+ def execute(file_name = nil, priv = nil)
33
+ raise_cmd_argument_error unless file_name
34
+ irb_load(file_name, priv)
35
+ end
36
+ end
30
37
 
31
- def execute(file_name)
38
+ class Require < LoaderCommand
39
+ category "IRB"
40
+ description "Require a Ruby file."
41
+ def execute(file_name = nil)
42
+ raise_cmd_argument_error unless file_name
32
43
 
33
44
  rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
34
45
  return false if $".find{|f| f =~ rex}
@@ -56,13 +67,16 @@ module IRB
56
67
  end
57
68
  end
58
69
 
59
- class Source < Nop
60
- include IrbLoader
61
- def execute(file_name)
70
+ class Source < LoaderCommand
71
+ category "IRB"
72
+ description "Loads a given file in the current session."
73
+
74
+ def execute(file_name = nil)
75
+ raise_cmd_argument_error unless file_name
76
+
62
77
  source_file(file_name)
63
78
  end
64
79
  end
65
80
  end
66
-
67
81
  # :startdoc:
68
82
  end
data/lib/irb/cmd/ls.rb CHANGED
@@ -9,6 +9,9 @@ module IRB
9
9
 
10
10
  module ExtendCommand
11
11
  class Ls < Nop
12
+ category "Context"
13
+ description "Show methods, constants, and variables. `-g [query]` or `-G [query]` allows you to filter out the output."
14
+
12
15
  def self.transform_args(args)
13
16
  if match = args&.match(/\A(?<args>.+\s|)(-g|-G)\s+(?<grep>[^\s]+)\s*\n\z/)
14
17
  args = match[:args]
@@ -30,6 +33,7 @@ module IRB
30
33
  o.dump("instance variables", obj.instance_variables)
31
34
  o.dump("class variables", klass.class_variables)
32
35
  o.dump("locals", locals)
36
+ nil
33
37
  end
34
38
 
35
39
  def dump_methods(o, klass, obj)
@@ -5,6 +5,9 @@ module IRB
5
5
 
6
6
  module ExtendCommand
7
7
  class Measure < Nop
8
+ category "Misc"
9
+ description "`measure` enables the mode to measure processing time. `measure :off` disables it."
10
+
8
11
  def initialize(*args)
9
12
  super(*args)
10
13
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "debug"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module ExtendCommand
9
+ class Next < DebugCommand
10
+ def execute(*args)
11
+ super(do_cmds: ["next", *args].join(" "))
12
+ end
13
+ end
14
+ end
15
+
16
+ # :startdoc:
17
+ end
data/lib/irb/cmd/nop.rb CHANGED
@@ -13,17 +13,34 @@ module IRB
13
13
  # :stopdoc:
14
14
 
15
15
  module ExtendCommand
16
+ class CommandArgumentError < StandardError; end
17
+
16
18
  class Nop
19
+ class << self
20
+ def category(category = nil)
21
+ @category = category if category
22
+ @category
23
+ end
24
+
25
+ def description(description = nil)
26
+ @description = description if description
27
+ @description
28
+ end
29
+ end
17
30
 
18
31
  if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
19
32
  def self.execute(conf, *opts, **kwargs, &block)
20
33
  command = new(conf)
21
34
  command.execute(*opts, **kwargs, &block)
35
+ rescue CommandArgumentError => e
36
+ puts e.message
22
37
  end
23
38
  else
24
39
  def self.execute(conf, *opts, &block)
25
40
  command = new(conf)
26
41
  command.execute(*opts, &block)
42
+ rescue CommandArgumentError => e
43
+ puts e.message
27
44
  end
28
45
  end
29
46
 
@@ -18,12 +18,18 @@ module IRB
18
18
 
19
19
  module ExtendCommand
20
20
  class Workspaces < Nop
21
+ category "IRB"
22
+ description "Show workspaces."
23
+
21
24
  def execute(*obj)
22
25
  irb_context.workspaces.collect{|ws| ws.main}
23
26
  end
24
27
  end
25
28
 
26
29
  class PushWorkspace < Workspaces
30
+ category "IRB"
31
+ description "Push an object to the workspace stack."
32
+
27
33
  def execute(*obj)
28
34
  irb_context.push_workspace(*obj)
29
35
  super
@@ -31,6 +37,9 @@ module IRB
31
37
  end
32
38
 
33
39
  class PopWorkspace < Workspaces
40
+ category "IRB"
41
+ description "Pop a workspace from the workspace stack."
42
+
34
43
  def execute(*obj)
35
44
  irb_context.pop_workspace(*obj)
36
45
  super
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require_relative "nop"
5
+
6
+ module IRB
7
+ # :stopdoc:
8
+
9
+ module ExtendCommand
10
+ class ShowCmds < Nop
11
+ category "IRB"
12
+ description "List all available commands and their description."
13
+
14
+ def execute(*args)
15
+ commands_info = IRB::ExtendCommandBundle.all_commands_info
16
+ commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
17
+ longest_cmd_name_length = commands_info.map { |c| c[:display_name] }.max { |a, b| a.length <=> b.length }.length
18
+
19
+ output = StringIO.new
20
+
21
+ commands_grouped_by_categories.each do |category, cmds|
22
+ output.puts Color.colorize(category, [:BOLD])
23
+
24
+ cmds.each do |cmd|
25
+ output.puts " #{cmd[:display_name].to_s.ljust(longest_cmd_name_length)} #{cmd[:description]}"
26
+ end
27
+
28
+ output.puts
29
+ end
30
+
31
+ puts output.string
32
+
33
+ nil
34
+ end
35
+ end
36
+ end
37
+
38
+ # :startdoc:
39
+ end
@@ -9,6 +9,9 @@ module IRB
9
9
 
10
10
  module ExtendCommand
11
11
  class ShowSource < Nop
12
+ category "Context"
13
+ description "Show the source code of a given method or constant."
14
+
12
15
  class << self
13
16
  def transform_args(args)
14
17
  # Return a string literal as is for backward compatibility
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "debug"
4
+
5
+ module IRB
6
+ # :stopdoc:
7
+
8
+ module ExtendCommand
9
+ class Step < DebugCommand
10
+ def execute(*args)
11
+ # Run `next` first to move out of binding.irb
12
+ super(pre_cmds: "next", do_cmds: ["step", *args].join(" "))
13
+ end
14
+ end
15
+ end
16
+
17
+ # :startdoc:
18
+ end
@@ -10,31 +10,57 @@
10
10
  #
11
11
 
12
12
  require_relative "nop"
13
- require_relative "../ext/multi-irb"
14
13
 
15
14
  module IRB
16
15
  # :stopdoc:
17
16
 
18
17
  module ExtendCommand
19
- class IrbCommand < Nop
18
+ class MultiIRBCommand < Nop
19
+ def initialize(conf)
20
+ super
21
+ extend_irb_context
22
+ end
23
+
24
+ private
25
+
26
+ def extend_irb_context
27
+ # this extension patches IRB context like IRB.CurrentContext
28
+ require_relative "../ext/multi-irb"
29
+ end
30
+ end
31
+
32
+ class IrbCommand < MultiIRBCommand
33
+ category "IRB"
34
+ description "Start a child IRB."
35
+
20
36
  def execute(*obj)
21
37
  IRB.irb(nil, *obj)
22
38
  end
23
39
  end
24
40
 
25
- class Jobs < Nop
41
+ class Jobs < MultiIRBCommand
42
+ category "IRB"
43
+ description "List of current sessions."
44
+
26
45
  def execute
27
46
  IRB.JobManager
28
47
  end
29
48
  end
30
49
 
31
- class Foreground < Nop
32
- def execute(key)
50
+ class Foreground < MultiIRBCommand
51
+ category "IRB"
52
+ description "Switches to the session of the given number."
53
+
54
+ def execute(key = nil)
55
+ raise CommandArgumentError.new("Please specify the id of target IRB job (listed in the `jobs` command).") unless key
33
56
  IRB.JobManager.switch(key)
34
57
  end
35
58
  end
36
59
 
37
- class Kill < Nop
60
+ class Kill < MultiIRBCommand
61
+ category "IRB"
62
+ description "Kills the session with the given number."
63
+
38
64
  def execute(*keys)
39
65
  IRB.JobManager.kill(*keys)
40
66
  end
@@ -7,6 +7,9 @@ module IRB
7
7
 
8
8
  module ExtendCommand
9
9
  class Whereami < Nop
10
+ category "Context"
11
+ description "Show the source code around binding.irb again."
12
+
10
13
  def execute(*)
11
14
  code = irb_context.workspace.code_around_binding
12
15
  if code
data/lib/irb/context.rb CHANGED
@@ -486,9 +486,9 @@ module IRB
486
486
  @workspace.local_variable_set(:_, exception)
487
487
  end
488
488
 
489
- # Transform a non-identifier alias (ex: @, $)
489
+ # Transform a non-identifier alias (@, $) or keywords (next, break)
490
490
  command, args = line.split(/\s/, 2)
491
- if original = symbol_alias(command)
491
+ if original = command_aliases[command.to_sym]
492
492
  line = line.gsub(/\A#{Regexp.escape(command)}/, original.to_s)
493
493
  command = original
494
494
  end
@@ -545,10 +545,16 @@ module IRB
545
545
  workspace.binding.local_variables
546
546
  end
547
547
 
548
- # Return a command name if it's aliased from the argument and it's not an identifier.
549
- def symbol_alias(command)
548
+ # Return true if it's aliased from the argument and it's not an identifier.
549
+ def symbol_alias?(command)
550
550
  return nil if command.match?(/\A\w+\z/)
551
- command_aliases[command.to_sym]
551
+ command_aliases.key?(command.to_sym)
552
+ end
553
+
554
+ # Return true if the command supports transforming args
555
+ def transform_args?(command)
556
+ command = command_aliases.fetch(command.to_sym, command)
557
+ ExtendCommandBundle.load_command(command)&.respond_to?(:transform_args)
552
558
  end
553
559
  end
554
560
  end
@@ -70,7 +70,7 @@ module IRB
70
70
  end
71
71
  history_file = IRB.rc_file("_history") unless history_file
72
72
  if File.exist?(history_file)
73
- open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f|
73
+ File.open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f|
74
74
  f.each { |l|
75
75
  l = l.chomp
76
76
  if self.class == RelineInputMethod and history.last&.end_with?("\\")
@@ -45,14 +45,15 @@ module IRB # :nodoc:
45
45
  [:quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
46
46
  ]
47
47
 
48
+
48
49
  @EXTEND_COMMANDS = [
49
50
  [
50
51
  :irb_current_working_workspace, :CurrentWorkingWorkspace, "cmd/chws",
52
+ [:cwws, NO_OVERRIDE],
53
+ [:pwws, NO_OVERRIDE],
51
54
  [:irb_print_working_workspace, OVERRIDE_ALL],
52
55
  [:irb_cwws, OVERRIDE_ALL],
53
56
  [:irb_pwws, OVERRIDE_ALL],
54
- [:cwws, NO_OVERRIDE],
55
- [:pwws, NO_OVERRIDE],
56
57
  [:irb_current_working_binding, OVERRIDE_ALL],
57
58
  [:irb_print_working_binding, OVERRIDE_ALL],
58
59
  [:irb_cwb, OVERRIDE_ALL],
@@ -60,10 +61,10 @@ module IRB # :nodoc:
60
61
  ],
61
62
  [
62
63
  :irb_change_workspace, :ChangeWorkspace, "cmd/chws",
63
- [:irb_chws, OVERRIDE_ALL],
64
- [:irb_cws, OVERRIDE_ALL],
65
64
  [:chws, NO_OVERRIDE],
66
65
  [:cws, NO_OVERRIDE],
66
+ [:irb_chws, OVERRIDE_ALL],
67
+ [:irb_cws, OVERRIDE_ALL],
67
68
  [:irb_change_binding, OVERRIDE_ALL],
68
69
  [:irb_cb, OVERRIDE_ALL],
69
70
  [:cb, NO_OVERRIDE],
@@ -77,16 +78,16 @@ module IRB # :nodoc:
77
78
  ],
78
79
  [
79
80
  :irb_push_workspace, :PushWorkspace, "cmd/pushws",
80
- [:irb_pushws, OVERRIDE_ALL],
81
81
  [:pushws, NO_OVERRIDE],
82
+ [:irb_pushws, OVERRIDE_ALL],
82
83
  [:irb_push_binding, OVERRIDE_ALL],
83
84
  [:irb_pushb, OVERRIDE_ALL],
84
85
  [:pushb, NO_OVERRIDE],
85
86
  ],
86
87
  [
87
88
  :irb_pop_workspace, :PopWorkspace, "cmd/pushws",
88
- [:irb_popws, OVERRIDE_ALL],
89
89
  [:popws, NO_OVERRIDE],
90
+ [:irb_popws, OVERRIDE_ALL],
90
91
  [:irb_pop_binding, OVERRIDE_ALL],
91
92
  [:irb_popb, OVERRIDE_ALL],
92
93
  [:popb, NO_OVERRIDE],
@@ -124,13 +125,49 @@ module IRB # :nodoc:
124
125
  :irb_edit, :Edit, "cmd/edit",
125
126
  [:edit, NO_OVERRIDE],
126
127
  ],
128
+ [
129
+ :irb_break, :Break, "cmd/break",
130
+ ],
131
+ [
132
+ :irb_catch, :Catch, "cmd/catch",
133
+ ],
134
+ [
135
+ :irb_next, :Next, "cmd/next"
136
+ ],
137
+ [
138
+ :irb_delete, :Delete, "cmd/delete",
139
+ [:delete, NO_OVERRIDE],
140
+ ],
141
+ [
142
+ :irb_step, :Step, "cmd/step",
143
+ [:step, NO_OVERRIDE],
144
+ ],
145
+ [
146
+ :irb_continue, :Continue, "cmd/continue",
147
+ [:continue, NO_OVERRIDE],
148
+ ],
149
+ [
150
+ :irb_finish, :Finish, "cmd/finish",
151
+ [:finish, NO_OVERRIDE],
152
+ ],
153
+ [
154
+ :irb_backtrace, :Backtrace, "cmd/backtrace",
155
+ [:backtrace, NO_OVERRIDE],
156
+ [:bt, NO_OVERRIDE],
157
+ ],
158
+ [
159
+ :irb_debug_info, :Info, "cmd/info",
160
+ [:info, NO_OVERRIDE],
161
+ ],
162
+
127
163
  [
128
164
  :irb_help, :Help, "cmd/help",
165
+ [:show_doc, NO_OVERRIDE],
129
166
  [:help, NO_OVERRIDE],
130
167
  ],
131
168
 
132
169
  [
133
- :irb_info, :Info, "cmd/info"
170
+ :irb_info, :IrbInfo, "cmd/irb_info"
134
171
  ],
135
172
 
136
173
  [
@@ -152,9 +189,41 @@ module IRB # :nodoc:
152
189
  :irb_whereami, :Whereami, "cmd/whereami",
153
190
  [:whereami, NO_OVERRIDE],
154
191
  ],
155
-
192
+ [
193
+ :irb_show_cmds, :ShowCmds, "cmd/show_cmds",
194
+ [:show_cmds, NO_OVERRIDE],
195
+ ]
156
196
  ]
157
197
 
198
+
199
+ @@commands = []
200
+
201
+ def self.all_commands_info
202
+ return @@commands unless @@commands.empty?
203
+ user_aliases = IRB.CurrentContext.command_aliases.each_with_object({}) do |(alias_name, target), result|
204
+ result[target] ||= []
205
+ result[target] << alias_name
206
+ end
207
+
208
+ @EXTEND_COMMANDS.each do |cmd_name, cmd_class, load_file, *aliases|
209
+ if !defined?(ExtendCommand) || !ExtendCommand.const_defined?(cmd_class, false)
210
+ require_relative load_file
211
+ end
212
+
213
+ klass = ExtendCommand.const_get(cmd_class, false)
214
+ aliases = aliases.map { |a| a.first }
215
+
216
+ if additional_aliases = user_aliases[cmd_name]
217
+ aliases += additional_aliases
218
+ end
219
+
220
+ display_name = aliases.shift || cmd_name
221
+ @@commands << { display_name: display_name, description: klass.description, category: klass.category }
222
+ end
223
+
224
+ @@commands
225
+ end
226
+
158
227
  # Convert a command name to its implementation class if such command exists
159
228
  def self.load_command(command)
160
229
  command = command.to_sym
data/lib/irb/init.rb CHANGED
@@ -45,7 +45,7 @@ module IRB # :nodoc:
45
45
 
46
46
  @CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod)
47
47
  @CONF[:USE_COLORIZE] = (nc = ENV['NO_COLOR']).nil? || nc.empty?
48
- @CONF[:USE_AUTOCOMPLETE] = true
48
+ @CONF[:USE_AUTOCOMPLETE] = ENV.fetch("IRB_USE_AUTOCOMPLETE", "true") != "false"
49
49
  @CONF[:INSPECT_MODE] = true
50
50
  @CONF[:USE_TRACER] = false
51
51
  @CONF[:USE_LOADER] = false
@@ -160,8 +160,13 @@ module IRB # :nodoc:
160
160
  @CONF[:AT_EXIT] = []
161
161
 
162
162
  @CONF[:COMMAND_ALIASES] = {
163
+ # Symbol aliases
163
164
  :'$' => :show_source,
164
165
  :'@' => :whereami,
166
+ # Keyword aliases
167
+ :break => :irb_break,
168
+ :catch => :irb_catch,
169
+ :next => :irb_next,
165
170
  }
166
171
  end
167
172
 
data/lib/irb/ruby-lex.rb CHANGED
@@ -65,9 +65,9 @@ class RubyLex
65
65
  false
66
66
  end
67
67
  else
68
- # Accept any single-line input starting with a non-identifier alias (ex: @, $)
68
+ # Accept any single-line input for symbol aliases or commands that transform args
69
69
  command = code.split(/\s/, 2).first
70
- if context.symbol_alias(command)
70
+ if context.symbol_alias?(command) || context.transform_args?(command)
71
71
  next true
72
72
  end
73
73
 
data/lib/irb/version.rb CHANGED
@@ -11,7 +11,7 @@
11
11
  #
12
12
 
13
13
  module IRB # :nodoc:
14
- VERSION = "1.5.0"
14
+ VERSION = "1.6.0"
15
15
  @RELEASE_VERSION = VERSION
16
- @LAST_UPDATE_DATE = "2022-11-20"
16
+ @LAST_UPDATE_DATE = "2022-11-28"
17
17
  end
data/lib/irb.rb CHANGED
@@ -96,6 +96,8 @@ require_relative "irb/easter-egg"
96
96
  # * Show the source code around binding.irb again.
97
97
  # * debug
98
98
  # * Start the debugger of debug.gem.
99
+ # * break, delete, next, step, continue, finish, backtrace, info, catch
100
+ # * Start the debugger of debug.gem and run the command on it.
99
101
  #
100
102
  # == Configuration
101
103
  #
@@ -470,10 +472,6 @@ module IRB
470
472
  def initialize(workspace = nil, input_method = nil)
471
473
  @context = Context.new(self, workspace, input_method)
472
474
  @context.main.extend ExtendCommandBundle
473
- @context.command_aliases.each do |alias_name, cmd_name|
474
- next if @context.symbol_alias(alias_name)
475
- @context.main.install_alias_method(alias_name, cmd_name)
476
- end
477
475
  @signal_status = :IN_IRB
478
476
  @scanner = RubyLex.new
479
477
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: irb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-11-21 00:00:00.000000000 Z
12
+ date: 2022-12-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: reline
@@ -46,18 +46,28 @@ files:
46
46
  - exe/irb
47
47
  - irb.gemspec
48
48
  - lib/irb.rb
49
+ - lib/irb/cmd/backtrace.rb
50
+ - lib/irb/cmd/break.rb
51
+ - lib/irb/cmd/catch.rb
49
52
  - lib/irb/cmd/chws.rb
53
+ - lib/irb/cmd/continue.rb
50
54
  - lib/irb/cmd/debug.rb
55
+ - lib/irb/cmd/delete.rb
51
56
  - lib/irb/cmd/edit.rb
57
+ - lib/irb/cmd/finish.rb
52
58
  - lib/irb/cmd/fork.rb
53
59
  - lib/irb/cmd/help.rb
54
60
  - lib/irb/cmd/info.rb
61
+ - lib/irb/cmd/irb_info.rb
55
62
  - lib/irb/cmd/load.rb
56
63
  - lib/irb/cmd/ls.rb
57
64
  - lib/irb/cmd/measure.rb
65
+ - lib/irb/cmd/next.rb
58
66
  - lib/irb/cmd/nop.rb
59
67
  - lib/irb/cmd/pushws.rb
68
+ - lib/irb/cmd/show_cmds.rb
60
69
  - lib/irb/cmd/show_source.rb
70
+ - lib/irb/cmd/step.rb
61
71
  - lib/irb/cmd/subirb.rb
62
72
  - lib/irb/cmd/whereami.rb
63
73
  - lib/irb/color.rb
@@ -116,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
126
  - !ruby/object:Gem::Version
117
127
  version: '0'
118
128
  requirements: []
119
- rubygems_version: 3.3.7
129
+ rubygems_version: 3.3.26
120
130
  signing_key:
121
131
  specification_version: 4
122
132
  summary: Interactive Ruby command-line tool for REPL (Read Eval Print Loop).