irb 1.4.1 → 1.4.3

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.
@@ -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