irb 1.4.1 → 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,7 +11,29 @@ require_relative 'ruby-lex'
11
11
 
12
12
  module IRB
13
13
  module InputCompletor # :nodoc:
14
+ using Module.new {
15
+ refine ::Binding do
16
+ def eval_methods
17
+ ::Kernel.instance_method(:methods).bind(eval("self")).call
18
+ end
19
+
20
+ def eval_private_methods
21
+ ::Kernel.instance_method(:private_methods).bind(eval("self")).call
22
+ end
14
23
 
24
+ def eval_instance_variables
25
+ ::Kernel.instance_method(:instance_variables).bind(eval("self")).call
26
+ end
27
+
28
+ def eval_global_variables
29
+ ::Kernel.instance_method(:global_variables).bind(eval("self")).call
30
+ end
31
+
32
+ def eval_class_constants
33
+ ::Module.instance_method(:constants).bind(eval("self.class")).call
34
+ end
35
+ end
36
+ }
15
37
 
16
38
  # Set of reserved words used by Ruby, you should not use these for
17
39
  # constants or variables
@@ -42,25 +64,34 @@ module IRB
42
64
  if File.respond_to?(:absolute_path?)
43
65
  File.absolute_path?(p)
44
66
  else
45
- if File.absolute_path(p) == p
46
- true
47
- else
48
- false
49
- end
67
+ File.absolute_path(p) == p
50
68
  end
51
69
  end
52
70
 
71
+ GEM_PATHS =
72
+ if defined?(Gem::Specification)
73
+ Gem::Specification.latest_specs(true).map { |s|
74
+ s.require_paths.map { |p|
75
+ if absolute_path?(p)
76
+ p
77
+ else
78
+ File.join(s.full_gem_path, p)
79
+ end
80
+ }
81
+ }.flatten
82
+ else
83
+ []
84
+ end.freeze
85
+
53
86
  def self.retrieve_gem_and_system_load_path
54
- gem_paths = Gem::Specification.latest_specs(true).map { |s|
55
- s.require_paths.map { |p|
56
- if absolute_path?(p)
57
- p
58
- else
59
- File.join(s.full_gem_path, p)
60
- end
61
- }
62
- }.flatten if defined?(Gem::Specification)
63
- (gem_paths.to_a | $LOAD_PATH).sort
87
+ candidates = (GEM_PATHS | $LOAD_PATH)
88
+ candidates.map do |p|
89
+ if p.respond_to?(:to_path)
90
+ p.to_path
91
+ else
92
+ String(p) rescue nil
93
+ end
94
+ end.compact.sort
64
95
  end
65
96
 
66
97
  def self.retrieve_files_to_require_from_load_path
@@ -142,10 +173,10 @@ module IRB
142
173
  receiver = $1
143
174
  message = $3
144
175
 
145
- candidates = String.instance_methods.collect{|m| m.to_s}
146
176
  if doc_namespace
147
177
  "String.#{message}"
148
178
  else
179
+ candidates = String.instance_methods.collect{|m| m.to_s}
149
180
  select_message(receiver, message, candidates)
150
181
  end
151
182
 
@@ -154,10 +185,10 @@ module IRB
154
185
  receiver = $1
155
186
  message = $2
156
187
 
157
- candidates = Regexp.instance_methods.collect{|m| m.to_s}
158
188
  if doc_namespace
159
189
  "Regexp.#{message}"
160
190
  else
191
+ candidates = Regexp.instance_methods.collect{|m| m.to_s}
161
192
  select_message(receiver, message, candidates)
162
193
  end
163
194
 
@@ -166,10 +197,10 @@ module IRB
166
197
  receiver = $1
167
198
  message = $2
168
199
 
169
- candidates = Array.instance_methods.collect{|m| m.to_s}
170
200
  if doc_namespace
171
201
  "Array.#{message}"
172
202
  else
203
+ candidates = Array.instance_methods.collect{|m| m.to_s}
173
204
  select_message(receiver, message, candidates)
174
205
  end
175
206
 
@@ -178,29 +209,33 @@ module IRB
178
209
  receiver = $1
179
210
  message = $2
180
211
 
181
- proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
182
- hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
183
212
  if doc_namespace
184
213
  ["Proc.#{message}", "Hash.#{message}"]
185
214
  else
215
+ proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
216
+ hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
186
217
  select_message(receiver, message, proc_candidates | hash_candidates)
187
218
  end
188
219
 
189
220
  when /^(:[^:.]*)$/
190
221
  # Symbol
191
- return nil if doc_namespace
192
- sym = $1
193
- candidates = Symbol.all_symbols.collect do |s|
194
- ":" + s.id2name.encode(Encoding.default_external)
195
- rescue EncodingError
196
- # ignore
222
+ if doc_namespace
223
+ nil
224
+ else
225
+ sym = $1
226
+ candidates = Symbol.all_symbols.collect do |s|
227
+ ":" + s.id2name.encode(Encoding.default_external)
228
+ rescue EncodingError
229
+ # ignore
230
+ end
231
+ candidates.grep(/^#{Regexp.quote(sym)}/)
197
232
  end
198
- candidates.grep(/^#{Regexp.quote(sym)}/)
199
-
200
233
  when /^::([A-Z][^:\.\(\)]*)$/
201
234
  # Absolute Constant or class methods
202
235
  receiver = $1
236
+
203
237
  candidates = Object.constants.collect{|m| m.to_s}
238
+
204
239
  if doc_namespace
205
240
  candidates.find { |i| i == receiver }
206
241
  else
@@ -211,16 +246,18 @@ module IRB
211
246
  # Constant or class methods
212
247
  receiver = $1
213
248
  message = $2
214
- begin
215
- candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
216
- candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
217
- rescue Exception
218
- candidates = []
219
- end
249
+
220
250
  if doc_namespace
221
251
  "#{receiver}::#{message}"
222
252
  else
223
- select_message(receiver, message, candidates, "::")
253
+ begin
254
+ candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
255
+ candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
256
+ rescue Exception
257
+ candidates = []
258
+ end
259
+
260
+ select_message(receiver, message, candidates.sort, "::")
224
261
  end
225
262
 
226
263
  when /^(:[^:.]+)(\.|::)([^.]*)$/
@@ -229,10 +266,10 @@ module IRB
229
266
  sep = $2
230
267
  message = $3
231
268
 
232
- candidates = Symbol.instance_methods.collect{|m| m.to_s}
233
269
  if doc_namespace
234
270
  "Symbol.#{message}"
235
271
  else
272
+ candidates = Symbol.instance_methods.collect{|m| m.to_s}
236
273
  select_message(receiver, message, candidates, sep)
237
274
  end
238
275
 
@@ -244,6 +281,7 @@ module IRB
244
281
 
245
282
  begin
246
283
  instance = eval(receiver, bind)
284
+
247
285
  if doc_namespace
248
286
  "#{instance.class.name}.#{message}"
249
287
  else
@@ -254,7 +292,7 @@ module IRB
254
292
  if doc_namespace
255
293
  nil
256
294
  else
257
- candidates = []
295
+ []
258
296
  end
259
297
  end
260
298
 
@@ -276,7 +314,7 @@ module IRB
276
314
  if doc_namespace
277
315
  nil
278
316
  else
279
- candidates = []
317
+ []
280
318
  end
281
319
  end
282
320
 
@@ -284,6 +322,7 @@ module IRB
284
322
  # global var
285
323
  gvar = $1
286
324
  all_gvars = global_variables.collect{|m| m.to_s}
325
+
287
326
  if doc_namespace
288
327
  all_gvars.find{ |i| i == gvar }
289
328
  else
@@ -296,10 +335,10 @@ module IRB
296
335
  sep = $2
297
336
  message = $3
298
337
 
299
- gv = eval("global_variables", bind).collect{|m| m.to_s}.push("true", "false", "nil")
300
- lv = eval("local_variables", bind).collect{|m| m.to_s}
301
- iv = eval("instance_variables", bind).collect{|m| m.to_s}
302
- cv = eval("self.class.constants", bind).collect{|m| m.to_s}
338
+ gv = bind.eval_global_variables.collect{|m| m.to_s}.push("true", "false", "nil")
339
+ lv = bind.local_variables.collect{|m| m.to_s}
340
+ iv = bind.eval_instance_variables.collect{|m| m.to_s}
341
+ cv = bind.eval_class_constants.collect{|m| m.to_s}
303
342
 
304
343
  if (gv | lv | iv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver
305
344
  # foo.func and foo is var. OR
@@ -322,11 +361,13 @@ module IRB
322
361
  to_ignore = ignored_modules
323
362
  ObjectSpace.each_object(Module){|m|
324
363
  next if (to_ignore.include?(m) rescue true)
364
+ next unless m.respond_to?(:instance_methods) # JRuby has modules that represent java packages. They don't include many common ruby methods
325
365
  candidates.concat m.instance_methods(false).collect{|x| x.to_s}
326
366
  }
327
367
  candidates.sort!
328
368
  candidates.uniq!
329
369
  end
370
+
330
371
  if doc_namespace
331
372
  rec_class = rec.is_a?(Module) ? rec : rec.class
332
373
  "#{rec_class.name}#{sep}#{candidates.find{ |i| i == message }}"
@@ -341,27 +382,28 @@ module IRB
341
382
  message = $1
342
383
 
343
384
  candidates = String.instance_methods(true).collect{|m| m.to_s}
385
+
344
386
  if doc_namespace
345
387
  "String.#{candidates.find{ |i| i == message }}"
346
388
  else
347
- select_message(receiver, message, candidates)
389
+ select_message(receiver, message, candidates.sort)
348
390
  end
349
391
 
350
392
  else
351
393
  if doc_namespace
352
- vars = eval("local_variables | instance_variables", bind).collect{|m| m.to_s}
394
+ vars = (bind.local_variables | bind.eval_instance_variables).collect{|m| m.to_s}
353
395
  perfect_match_var = vars.find{|m| m.to_s == input}
354
396
  if perfect_match_var
355
397
  eval("#{perfect_match_var}.class.name", bind)
356
398
  else
357
- candidates = eval("methods | private_methods | local_variables | instance_variables | self.class.constants", bind).collect{|m| m.to_s}
399
+ candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
358
400
  candidates |= ReservedWords
359
401
  candidates.find{ |i| i == input }
360
402
  end
361
403
  else
362
- candidates = eval("methods | private_methods | local_variables | instance_variables | self.class.constants", bind).collect{|m| m.to_s}
404
+ candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
363
405
  candidates |= ReservedWords
364
- candidates.grep(/^#{Regexp.quote(input)}/)
406
+ candidates.grep(/^#{Regexp.quote(input)}/).sort
365
407
  end
366
408
  end
367
409
  end
data/lib/irb/context.rb CHANGED
@@ -22,7 +22,7 @@ module IRB
22
22
  #
23
23
  # The optional +input_method+ argument:
24
24
  #
25
- # +nil+:: uses stdin or Reidline or Readline
25
+ # +nil+:: uses stdin or Reline or Readline
26
26
  # +String+:: uses a File
27
27
  # +other+:: uses this as InputMethod
28
28
  def initialize(irb, workspace = nil, input_method = nil)
@@ -32,7 +32,7 @@ module IRB
32
32
  else
33
33
  @workspace = WorkSpace.new
34
34
  end
35
- @thread = Thread.current if defined? Thread
35
+ @thread = Thread.current
36
36
 
37
37
  # copy of default configuration
38
38
  @ap_name = IRB.conf[:AP_NAME]
@@ -48,12 +48,19 @@ module IRB
48
48
  end
49
49
  if IRB.conf.has_key?(:USE_MULTILINE)
50
50
  @use_multiline = IRB.conf[:USE_MULTILINE]
51
- elsif IRB.conf.has_key?(:USE_REIDLINE) # backward compatibility
51
+ elsif IRB.conf.has_key?(:USE_RELINE) # backward compatibility
52
+ warn <<~MSG.strip
53
+ USE_RELINE is deprecated, please use USE_MULTILINE instead.
54
+ MSG
55
+ @use_multiline = IRB.conf[:USE_RELINE]
56
+ elsif IRB.conf.has_key?(:USE_REIDLINE)
57
+ warn <<~MSG.strip
58
+ USE_REIDLINE is deprecated, please use USE_MULTILINE instead.
59
+ MSG
52
60
  @use_multiline = IRB.conf[:USE_REIDLINE]
53
61
  else
54
62
  @use_multiline = nil
55
63
  end
56
- @use_colorize = IRB.conf[:USE_COLORIZE]
57
64
  @use_autocomplete = IRB.conf[:USE_AUTOCOMPLETE]
58
65
  @verbose = IRB.conf[:VERBOSE]
59
66
  @io = nil
@@ -84,14 +91,14 @@ module IRB
84
91
  when nil
85
92
  if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
86
93
  # Both of multiline mode and singleline mode aren't specified.
87
- @io = ReidlineInputMethod.new
94
+ @io = RelineInputMethod.new
88
95
  else
89
96
  @io = nil
90
97
  end
91
98
  when false
92
99
  @io = nil
93
100
  when true
94
- @io = ReidlineInputMethod.new
101
+ @io = RelineInputMethod.new
95
102
  end
96
103
  unless @io
97
104
  case use_singleline?
@@ -116,6 +123,10 @@ module IRB
116
123
  end
117
124
  @io = StdioInputMethod.new unless @io
118
125
 
126
+ when '-'
127
+ @io = FileInputMethod.new($stdin)
128
+ @irb_name = '-'
129
+ @irb_path = '-'
119
130
  when String
120
131
  @io = FileInputMethod.new(input_method)
121
132
  @irb_name = File.basename(input_method)
@@ -141,6 +152,8 @@ module IRB
141
152
  if @newline_before_multiline_output.nil?
142
153
  @newline_before_multiline_output = true
143
154
  end
155
+
156
+ @command_aliases = IRB.conf[:COMMAND_ALIASES]
144
157
  end
145
158
 
146
159
  # The top-level workspace, see WorkSpace#main
@@ -157,7 +170,7 @@ module IRB
157
170
  # The current input method.
158
171
  #
159
172
  # Can be either StdioInputMethod, ReadlineInputMethod,
160
- # ReidlineInputMethod, FileInputMethod or other specified when the
173
+ # RelineInputMethod, FileInputMethod or other specified when the
161
174
  # context is created. See ::new for more # information on +input_method+.
162
175
  attr_accessor :io
163
176
 
@@ -186,8 +199,6 @@ module IRB
186
199
  attr_reader :use_singleline
187
200
  # Whether colorization is enabled or not.
188
201
  #
189
- # A copy of the default <code>IRB.conf[:USE_COLORIZE]</code>
190
- attr_reader :use_colorize
191
202
  # A copy of the default <code>IRB.conf[:USE_AUTOCOMPLETE]</code>
192
203
  attr_reader :use_autocomplete
193
204
  # A copy of the default <code>IRB.conf[:INSPECT_MODE]</code>
@@ -320,20 +331,21 @@ module IRB
320
331
  # See IRB@Command+line+options for more command line options.
321
332
  attr_accessor :back_trace_limit
322
333
 
334
+ # User-defined IRB command aliases
335
+ attr_accessor :command_aliases
336
+
323
337
  # Alias for #use_multiline
324
338
  alias use_multiline? use_multiline
325
339
  # Alias for #use_singleline
326
340
  alias use_singleline? use_singleline
327
341
  # backward compatibility
328
- alias use_reidline use_multiline
342
+ alias use_reline use_multiline
329
343
  # backward compatibility
330
- alias use_reidline? use_multiline
344
+ alias use_reline? use_multiline
331
345
  # backward compatibility
332
346
  alias use_readline use_singleline
333
347
  # backward compatibility
334
348
  alias use_readline? use_singleline
335
- # Alias for #use_colorize
336
- alias use_colorize? use_colorize
337
349
  # Alias for #use_autocomplete
338
350
  alias use_autocomplete? use_autocomplete
339
351
  # Alias for #rc
@@ -347,7 +359,7 @@ module IRB
347
359
  # Returns whether messages are displayed or not.
348
360
  def verbose?
349
361
  if @verbose.nil?
350
- if @io.kind_of?(ReidlineInputMethod)
362
+ if @io.kind_of?(RelineInputMethod)
351
363
  false
352
364
  elsif defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod)
353
365
  false
@@ -362,11 +374,11 @@ module IRB
362
374
  end
363
375
 
364
376
  # Whether #verbose? is +true+, and +input_method+ is either
365
- # StdioInputMethod or ReidlineInputMethod or ReadlineInputMethod, see #io
377
+ # StdioInputMethod or RelineInputMethod or ReadlineInputMethod, see #io
366
378
  # for more information.
367
379
  def prompting?
368
380
  verbose? || (STDIN.tty? && @io.kind_of?(StdioInputMethod) ||
369
- @io.kind_of?(ReidlineInputMethod) ||
381
+ @io.kind_of?(RelineInputMethod) ||
370
382
  (defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod)))
371
383
  end
372
384
 
@@ -473,6 +485,20 @@ module IRB
473
485
  line = "begin ::Kernel.raise _; rescue _.class\n#{line}\n""end"
474
486
  @workspace.local_variable_set(:_, exception)
475
487
  end
488
+
489
+ # Transform a non-identifier alias (ex: @, $)
490
+ command, args = line.split(/\s/, 2)
491
+ if original = symbol_alias(command)
492
+ line = line.gsub(/\A#{Regexp.escape(command)}/, original.to_s)
493
+ command = original
494
+ end
495
+
496
+ # Hook command-specific transformation
497
+ command_class = ExtendCommandBundle.load_command(command)
498
+ if command_class&.respond_to?(:transform_args)
499
+ line = "#{command} #{command_class.transform_args(args)}"
500
+ end
501
+
476
502
  set_last_value(@workspace.evaluate(self, line, irb_path, line_no))
477
503
  end
478
504
 
@@ -514,5 +540,15 @@ module IRB
514
540
  end
515
541
  alias __to_s__ to_s
516
542
  alias to_s inspect
543
+
544
+ def local_variables # :nodoc:
545
+ workspace.binding.local_variables
546
+ end
547
+
548
+ # Return a command name if it's aliased from the argument and it's not an identifier.
549
+ def symbol_alias(command)
550
+ return nil if command.match?(/\A\w+\z/)
551
+ command_aliases[command.to_sym]
552
+ end
517
553
  end
518
554
  end
@@ -9,7 +9,6 @@
9
9
  #
10
10
  #
11
11
  #
12
- fail CantShiftToMultiIrbMode unless defined?(Thread)
13
12
 
14
13
  module IRB
15
14
  class JobManager
@@ -73,7 +73,7 @@ module IRB
73
73
  open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f|
74
74
  f.each { |l|
75
75
  l = l.chomp
76
- if self.class == ReidlineInputMethod and history.last&.end_with?("\\")
76
+ if self.class == RelineInputMethod and history.last&.end_with?("\\")
77
77
  history.last.delete_suffix!("\\")
78
78
  history.last << "\n" << l
79
79
  else
@@ -107,13 +107,13 @@ module IRB
107
107
  raise
108
108
  end
109
109
 
110
- if File.exist?(history_file) && @loaded_history_mtime &&
110
+ if File.exist?(history_file) &&
111
111
  File.mtime(history_file) != @loaded_history_mtime
112
- history = history[@loaded_history_lines..-1]
112
+ history = history[@loaded_history_lines..-1] if @loaded_history_lines
113
113
  append_history = true
114
114
  end
115
115
 
116
- open(history_file, "#{append_history ? 'a' : 'w'}:#{IRB.conf[:LC_MESSAGES].encoding}", 0600) do |f|
116
+ File.open(history_file, (append_history ? 'a' : 'w'), 0o600, encoding: IRB.conf[:LC_MESSAGES]&.encoding) do |f|
117
117
  hist = history.map{ |l| l.split("\n").join("\\\n") }
118
118
  unless append_history
119
119
  begin
@@ -47,7 +47,7 @@ module IRB # :nodoc:
47
47
 
48
48
  @EXTEND_COMMANDS = [
49
49
  [
50
- :irb_current_working_workspace, :CurrentWorkingWorkspace, "irb/cmd/chws",
50
+ :irb_current_working_workspace, :CurrentWorkingWorkspace, "cmd/chws",
51
51
  [:irb_print_working_workspace, OVERRIDE_ALL],
52
52
  [:irb_cwws, OVERRIDE_ALL],
53
53
  [:irb_pwws, OVERRIDE_ALL],
@@ -59,7 +59,7 @@ module IRB # :nodoc:
59
59
  [:irb_pwb, OVERRIDE_ALL],
60
60
  ],
61
61
  [
62
- :irb_change_workspace, :ChangeWorkspace, "irb/cmd/chws",
62
+ :irb_change_workspace, :ChangeWorkspace, "cmd/chws",
63
63
  [:irb_chws, OVERRIDE_ALL],
64
64
  [:irb_cws, OVERRIDE_ALL],
65
65
  [:chws, NO_OVERRIDE],
@@ -70,13 +70,13 @@ module IRB # :nodoc:
70
70
  ],
71
71
 
72
72
  [
73
- :irb_workspaces, :Workspaces, "irb/cmd/pushws",
73
+ :irb_workspaces, :Workspaces, "cmd/pushws",
74
74
  [:workspaces, NO_OVERRIDE],
75
75
  [:irb_bindings, OVERRIDE_ALL],
76
76
  [:bindings, NO_OVERRIDE],
77
77
  ],
78
78
  [
79
- :irb_push_workspace, :PushWorkspace, "irb/cmd/pushws",
79
+ :irb_push_workspace, :PushWorkspace, "cmd/pushws",
80
80
  [:irb_pushws, OVERRIDE_ALL],
81
81
  [:pushws, NO_OVERRIDE],
82
82
  [:irb_push_binding, OVERRIDE_ALL],
@@ -84,7 +84,7 @@ module IRB # :nodoc:
84
84
  [:pushb, NO_OVERRIDE],
85
85
  ],
86
86
  [
87
- :irb_pop_workspace, :PopWorkspace, "irb/cmd/pushws",
87
+ :irb_pop_workspace, :PopWorkspace, "cmd/pushws",
88
88
  [:irb_popws, OVERRIDE_ALL],
89
89
  [:popws, NO_OVERRIDE],
90
90
  [:irb_pop_binding, OVERRIDE_ALL],
@@ -93,60 +93,74 @@ module IRB # :nodoc:
93
93
  ],
94
94
 
95
95
  [
96
- :irb_load, :Load, "irb/cmd/load"],
96
+ :irb_load, :Load, "cmd/load"],
97
97
  [
98
- :irb_require, :Require, "irb/cmd/load"],
98
+ :irb_require, :Require, "cmd/load"],
99
99
  [
100
- :irb_source, :Source, "irb/cmd/load",
100
+ :irb_source, :Source, "cmd/load",
101
101
  [:source, NO_OVERRIDE],
102
102
  ],
103
103
 
104
104
  [
105
- :irb, :IrbCommand, "irb/cmd/subirb"],
105
+ :irb, :IrbCommand, "cmd/subirb"],
106
106
  [
107
- :irb_jobs, :Jobs, "irb/cmd/subirb",
107
+ :irb_jobs, :Jobs, "cmd/subirb",
108
108
  [:jobs, NO_OVERRIDE],
109
109
  ],
110
110
  [
111
- :irb_fg, :Foreground, "irb/cmd/subirb",
111
+ :irb_fg, :Foreground, "cmd/subirb",
112
112
  [:fg, NO_OVERRIDE],
113
113
  ],
114
114
  [
115
- :irb_kill, :Kill, "irb/cmd/subirb",
115
+ :irb_kill, :Kill, "cmd/subirb",
116
116
  [:kill, OVERRIDE_PRIVATE_ONLY],
117
117
  ],
118
118
 
119
119
  [
120
- :irb_help, :Help, "irb/cmd/help",
120
+ :irb_help, :Help, "cmd/help",
121
121
  [:help, NO_OVERRIDE],
122
122
  ],
123
123
 
124
124
  [
125
- :irb_info, :Info, "irb/cmd/info"
125
+ :irb_info, :Info, "cmd/info"
126
126
  ],
127
127
 
128
128
  [
129
- :irb_ls, :Ls, "irb/cmd/ls",
129
+ :irb_ls, :Ls, "cmd/ls",
130
130
  [:ls, NO_OVERRIDE],
131
131
  ],
132
132
 
133
133
  [
134
- :irb_measure, :Measure, "irb/cmd/measure",
134
+ :irb_measure, :Measure, "cmd/measure",
135
135
  [:measure, NO_OVERRIDE],
136
136
  ],
137
137
 
138
138
  [
139
- :irb_show_source, :ShowSource, "irb/cmd/show_source",
139
+ :irb_show_source, :ShowSource, "cmd/show_source",
140
140
  [:show_source, NO_OVERRIDE],
141
141
  ],
142
142
 
143
143
  [
144
- :irb_whereami, :Whereami, "irb/cmd/whereami",
144
+ :irb_whereami, :Whereami, "cmd/whereami",
145
145
  [:whereami, NO_OVERRIDE],
146
146
  ],
147
147
 
148
148
  ]
149
149
 
150
+ # Convert a command name to its implementation class if such command exists
151
+ def self.load_command(command)
152
+ command = command.to_sym
153
+ @EXTEND_COMMANDS.each do |cmd_name, cmd_class, load_file, *aliases|
154
+ next if cmd_name != command && aliases.all? { |alias_name, _| alias_name != command }
155
+
156
+ if !defined?(ExtendCommand) || !ExtendCommand.const_defined?(cmd_class, false)
157
+ require_relative load_file
158
+ end
159
+ return ExtendCommand.const_get(cmd_class, false)
160
+ end
161
+ nil
162
+ end
163
+
150
164
  # Installs the default irb commands:
151
165
  #
152
166
  # +irb_current_working_workspace+:: Context#main
@@ -162,6 +176,11 @@ module IRB # :nodoc:
162
176
  # +irb_fg+:: JobManager#switch
163
177
  # +irb_kill+:: JobManager#kill
164
178
  # +irb_help+:: IRB@Command+line+options
179
+ # +irb_info+:: #inspect
180
+ # +irb_ls+:: Output#dump
181
+ # +irb_measure+:: IRB::unset_measure_callback
182
+ # +irb_show_source+:: #find_source, #show_source
183
+ # +irb_whereami+:: Workspace#code_around_binding
165
184
  def self.install_extend_commands
166
185
  for args in @EXTEND_COMMANDS
167
186
  def_extend_command(*args)
@@ -187,7 +206,7 @@ module IRB # :nodoc:
187
206
  kwargs = ", **kwargs" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
188
207
  line = __LINE__; eval %[
189
208
  def #{cmd_name}(*opts#{kwargs}, &b)
190
- require "#{load_file}"
209
+ require_relative "#{load_file}"
191
210
  arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity
192
211
  args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s }
193
212
  args << "*opts#{kwargs}" if arity < 0
@@ -235,7 +254,7 @@ module IRB # :nodoc:
235
254
  alias_method to, from
236
255
  }
237
256
  else
238
- print "irb: warn: can't alias #{to} from #{from}.\n"
257
+ Kernel.print "irb: warn: can't alias #{to} from #{from}.\n"
239
258
  end
240
259
  end
241
260
 
@@ -262,10 +281,10 @@ module IRB # :nodoc:
262
281
  CE = ContextExtender # :nodoc:
263
282
 
264
283
  @EXTEND_COMMANDS = [
265
- [:eval_history=, "irb/ext/history.rb"],
266
- [:use_tracer=, "irb/ext/tracer.rb"],
267
- [:use_loader=, "irb/ext/use-loader.rb"],
268
- [:save_history=, "irb/ext/save-history.rb"],
284
+ [:eval_history=, "ext/history.rb"],
285
+ [:use_tracer=, "ext/tracer.rb"],
286
+ [:use_loader=, "ext/use-loader.rb"],
287
+ [:save_history=, "ext/save-history.rb"],
269
288
  ]
270
289
 
271
290
  # Installs the default context extensions as irb commands:
@@ -288,7 +307,7 @@ module IRB # :nodoc:
288
307
  line = __LINE__; Context.module_eval %[
289
308
  def #{cmd_name}(*opts, &b)
290
309
  Context.module_eval {remove_method(:#{cmd_name})}
291
- require "#{load_file}"
310
+ require_relative "#{load_file}"
292
311
  __send__ :#{cmd_name}, *opts, &b
293
312
  end
294
313
  for ali in aliases