irb 1.4.2 → 1.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +25 -0
- data/irb.gemspec +1 -1
- data/lib/irb/cmd/ls.rb +9 -0
- data/lib/irb/cmd/show_source.rb +18 -0
- data/lib/irb/color.rb +9 -2
- data/lib/irb/completion.rb +53 -40
- data/lib/irb/context.rb +34 -2
- data/lib/irb/ext/save-history.rb +1 -1
- data/lib/irb/extend-command.rb +19 -0
- data/lib/irb/init.rb +20 -5
- data/lib/irb/input-method.rb +9 -8
- data/lib/irb/ruby-lex.rb +40 -23
- data/lib/irb/version.rb +2 -2
- data/lib/irb.rb +14 -9
- data/man/irb.1 +23 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 025d4dccc426fe09dc77b79d7efb8157abc559b89a7455249e5d7e9b2ff1562c
|
4
|
+
data.tar.gz: fd2cffe5c013c56a5d454ce81331ac1c24b6826c81db6ae6f2240e6e2d5f8c06
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 582d9176beb3f3b9a016f6d44b90b9d781066230f4c64dec93ba5d645ae54df8f7f6f1a5dcaab20899390cd048050eaed6db9b45fdcf44c55a57098013855aa9
|
7
|
+
data.tar.gz: ab9b30b770c677778cc4871b249a0967177805e543bd8576077099be7d3a5d93e2ef33c35362326cd7f889cd1f855d956c2cb9bd992560029e152c6293720a94
|
data/Rakefile
CHANGED
@@ -8,6 +8,31 @@ Rake::TestTask.new(:test) do |t|
|
|
8
8
|
t.test_files = FileList["test/irb/test_*.rb"]
|
9
9
|
end
|
10
10
|
|
11
|
+
# To make sure they have been correctly setup for Ruby CI.
|
12
|
+
desc "Run each irb test file in isolation."
|
13
|
+
task :test_in_isolation do
|
14
|
+
failed = false
|
15
|
+
|
16
|
+
FileList["test/irb/test_*.rb"].each do |test_file|
|
17
|
+
ENV["TEST"] = test_file
|
18
|
+
begin
|
19
|
+
Rake::Task["test"].execute
|
20
|
+
rescue => e
|
21
|
+
failed = true
|
22
|
+
msg = "Test '#{test_file}' failed when being executed in isolation. Please make sure 'rake test TEST=#{test_file}' passes."
|
23
|
+
separation_line = '=' * msg.length
|
24
|
+
|
25
|
+
puts <<~MSG
|
26
|
+
#{separation_line}
|
27
|
+
#{msg}
|
28
|
+
#{separation_line}
|
29
|
+
MSG
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
fail "Some tests failed when being executed in isolation" if failed
|
34
|
+
end
|
35
|
+
|
11
36
|
Rake::TestTask.new(:test_yamatanooroti) do |t|
|
12
37
|
t.libs << 'test' << "test/lib"
|
13
38
|
t.libs << 'lib'
|
data/irb.gemspec
CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
35
35
|
spec.require_paths = ["lib"]
|
36
36
|
|
37
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
37
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.6")
|
38
38
|
|
39
39
|
spec.add_dependency "reline", ">= 0.3.0"
|
40
40
|
end
|
data/lib/irb/cmd/ls.rb
CHANGED
@@ -9,6 +9,15 @@ module IRB
|
|
9
9
|
|
10
10
|
module ExtendCommand
|
11
11
|
class Ls < Nop
|
12
|
+
def self.transform_args(args)
|
13
|
+
if match = args&.match(/\A(?<args>.+\s|)(-g|-G)\s+(?<grep>[^\s]+)\s*\n\z/)
|
14
|
+
args = match[:args]
|
15
|
+
"#{args}#{',' unless args.chomp.empty?} grep: /#{match[:grep]}/"
|
16
|
+
else
|
17
|
+
args
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
12
21
|
def execute(*arg, grep: nil)
|
13
22
|
o = Output.new(grep: grep)
|
14
23
|
|
data/lib/irb/cmd/show_source.rb
CHANGED
@@ -9,6 +9,24 @@ module IRB
|
|
9
9
|
|
10
10
|
module ExtendCommand
|
11
11
|
class ShowSource < Nop
|
12
|
+
class << self
|
13
|
+
def transform_args(args)
|
14
|
+
# Return a string literal as is for backward compatibility
|
15
|
+
if args.empty? || string_literal?(args)
|
16
|
+
args
|
17
|
+
else # Otherwise, consider the input as a String for convenience
|
18
|
+
args.strip.dump
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def string_literal?(args)
|
25
|
+
sexp = Ripper.sexp(args)
|
26
|
+
sexp && sexp.size == 2 && sexp.last&.first&.first == :string_literal
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
12
30
|
def execute(str = nil)
|
13
31
|
unless str.is_a?(String)
|
14
32
|
puts "Error: Expected a string but got #{str.inspect}"
|
data/lib/irb/color.rb
CHANGED
@@ -123,13 +123,15 @@ module IRB # :nodoc:
|
|
123
123
|
# If `complete` is false (code is incomplete), this does not warn compile_error.
|
124
124
|
# This option is needed to avoid warning a user when the compile_error is happening
|
125
125
|
# because the input is not wrong but just incomplete.
|
126
|
-
def colorize_code(code, complete: true, ignore_error: false, colorable: colorable
|
126
|
+
def colorize_code(code, complete: true, ignore_error: false, colorable: colorable?, local_variables: [])
|
127
127
|
return code unless colorable
|
128
128
|
|
129
129
|
symbol_state = SymbolState.new
|
130
130
|
colored = +''
|
131
|
+
lvars_code = RubyLex.generate_local_variables_assign_code(local_variables)
|
132
|
+
code_with_lvars = lvars_code ? "#{lvars_code}\n#{code}" : code
|
131
133
|
|
132
|
-
scan(
|
134
|
+
scan(code_with_lvars, allow_last_error: !complete) do |token, str, expr|
|
133
135
|
# handle uncolorable code
|
134
136
|
if token.nil?
|
135
137
|
colored << Reline::Unicode.escape_for_print(str)
|
@@ -152,6 +154,11 @@ module IRB # :nodoc:
|
|
152
154
|
end
|
153
155
|
end
|
154
156
|
end
|
157
|
+
|
158
|
+
if lvars_code
|
159
|
+
raise "#{lvars_code.dump} should have no \\n" if lvars_code.include?("\n")
|
160
|
+
colored.sub!(/\A.+\n/, '') # delete_prefix lvars_code with colors
|
161
|
+
end
|
155
162
|
colored
|
156
163
|
end
|
157
164
|
|
data/lib/irb/completion.rb
CHANGED
@@ -64,25 +64,27 @@ module IRB
|
|
64
64
|
if File.respond_to?(:absolute_path?)
|
65
65
|
File.absolute_path?(p)
|
66
66
|
else
|
67
|
-
|
68
|
-
true
|
69
|
-
else
|
70
|
-
false
|
71
|
-
end
|
67
|
+
File.absolute_path(p) == p
|
72
68
|
end
|
73
69
|
end
|
74
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
|
+
|
75
86
|
def self.retrieve_gem_and_system_load_path
|
76
|
-
|
77
|
-
s.require_paths.map { |p|
|
78
|
-
if absolute_path?(p)
|
79
|
-
p
|
80
|
-
else
|
81
|
-
File.join(s.full_gem_path, p)
|
82
|
-
end
|
83
|
-
}
|
84
|
-
}.flatten if defined?(Gem::Specification)
|
85
|
-
candidates = (gem_paths.to_a | $LOAD_PATH)
|
87
|
+
candidates = (GEM_PATHS | $LOAD_PATH)
|
86
88
|
candidates.map do |p|
|
87
89
|
if p.respond_to?(:to_path)
|
88
90
|
p.to_path
|
@@ -171,10 +173,10 @@ module IRB
|
|
171
173
|
receiver = $1
|
172
174
|
message = $3
|
173
175
|
|
174
|
-
candidates = String.instance_methods.collect{|m| m.to_s}
|
175
176
|
if doc_namespace
|
176
177
|
"String.#{message}"
|
177
178
|
else
|
179
|
+
candidates = String.instance_methods.collect{|m| m.to_s}
|
178
180
|
select_message(receiver, message, candidates)
|
179
181
|
end
|
180
182
|
|
@@ -183,10 +185,10 @@ module IRB
|
|
183
185
|
receiver = $1
|
184
186
|
message = $2
|
185
187
|
|
186
|
-
candidates = Regexp.instance_methods.collect{|m| m.to_s}
|
187
188
|
if doc_namespace
|
188
189
|
"Regexp.#{message}"
|
189
190
|
else
|
191
|
+
candidates = Regexp.instance_methods.collect{|m| m.to_s}
|
190
192
|
select_message(receiver, message, candidates)
|
191
193
|
end
|
192
194
|
|
@@ -195,10 +197,10 @@ module IRB
|
|
195
197
|
receiver = $1
|
196
198
|
message = $2
|
197
199
|
|
198
|
-
candidates = Array.instance_methods.collect{|m| m.to_s}
|
199
200
|
if doc_namespace
|
200
201
|
"Array.#{message}"
|
201
202
|
else
|
203
|
+
candidates = Array.instance_methods.collect{|m| m.to_s}
|
202
204
|
select_message(receiver, message, candidates)
|
203
205
|
end
|
204
206
|
|
@@ -207,29 +209,33 @@ module IRB
|
|
207
209
|
receiver = $1
|
208
210
|
message = $2
|
209
211
|
|
210
|
-
proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
|
211
|
-
hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
|
212
212
|
if doc_namespace
|
213
213
|
["Proc.#{message}", "Hash.#{message}"]
|
214
214
|
else
|
215
|
+
proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
|
216
|
+
hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
|
215
217
|
select_message(receiver, message, proc_candidates | hash_candidates)
|
216
218
|
end
|
217
219
|
|
218
220
|
when /^(:[^:.]*)$/
|
219
221
|
# Symbol
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
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)}/)
|
226
232
|
end
|
227
|
-
candidates.grep(/^#{Regexp.quote(sym)}/)
|
228
|
-
|
229
233
|
when /^::([A-Z][^:\.\(\)]*)$/
|
230
234
|
# Absolute Constant or class methods
|
231
235
|
receiver = $1
|
236
|
+
|
232
237
|
candidates = Object.constants.collect{|m| m.to_s}
|
238
|
+
|
233
239
|
if doc_namespace
|
234
240
|
candidates.find { |i| i == receiver }
|
235
241
|
else
|
@@ -240,16 +246,18 @@ module IRB
|
|
240
246
|
# Constant or class methods
|
241
247
|
receiver = $1
|
242
248
|
message = $2
|
243
|
-
|
244
|
-
candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
|
245
|
-
candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
|
246
|
-
rescue Exception
|
247
|
-
candidates = []
|
248
|
-
end
|
249
|
+
|
249
250
|
if doc_namespace
|
250
251
|
"#{receiver}::#{message}"
|
251
252
|
else
|
252
|
-
|
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, "::")
|
253
261
|
end
|
254
262
|
|
255
263
|
when /^(:[^:.]+)(\.|::)([^.]*)$/
|
@@ -258,10 +266,10 @@ module IRB
|
|
258
266
|
sep = $2
|
259
267
|
message = $3
|
260
268
|
|
261
|
-
candidates = Symbol.instance_methods.collect{|m| m.to_s}
|
262
269
|
if doc_namespace
|
263
270
|
"Symbol.#{message}"
|
264
271
|
else
|
272
|
+
candidates = Symbol.instance_methods.collect{|m| m.to_s}
|
265
273
|
select_message(receiver, message, candidates, sep)
|
266
274
|
end
|
267
275
|
|
@@ -273,6 +281,7 @@ module IRB
|
|
273
281
|
|
274
282
|
begin
|
275
283
|
instance = eval(receiver, bind)
|
284
|
+
|
276
285
|
if doc_namespace
|
277
286
|
"#{instance.class.name}.#{message}"
|
278
287
|
else
|
@@ -283,7 +292,7 @@ module IRB
|
|
283
292
|
if doc_namespace
|
284
293
|
nil
|
285
294
|
else
|
286
|
-
|
295
|
+
[]
|
287
296
|
end
|
288
297
|
end
|
289
298
|
|
@@ -305,7 +314,7 @@ module IRB
|
|
305
314
|
if doc_namespace
|
306
315
|
nil
|
307
316
|
else
|
308
|
-
|
317
|
+
[]
|
309
318
|
end
|
310
319
|
end
|
311
320
|
|
@@ -313,6 +322,7 @@ module IRB
|
|
313
322
|
# global var
|
314
323
|
gvar = $1
|
315
324
|
all_gvars = global_variables.collect{|m| m.to_s}
|
325
|
+
|
316
326
|
if doc_namespace
|
317
327
|
all_gvars.find{ |i| i == gvar }
|
318
328
|
else
|
@@ -351,11 +361,13 @@ module IRB
|
|
351
361
|
to_ignore = ignored_modules
|
352
362
|
ObjectSpace.each_object(Module){|m|
|
353
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
|
354
365
|
candidates.concat m.instance_methods(false).collect{|x| x.to_s}
|
355
366
|
}
|
356
367
|
candidates.sort!
|
357
368
|
candidates.uniq!
|
358
369
|
end
|
370
|
+
|
359
371
|
if doc_namespace
|
360
372
|
rec_class = rec.is_a?(Module) ? rec : rec.class
|
361
373
|
"#{rec_class.name}#{sep}#{candidates.find{ |i| i == message }}"
|
@@ -370,10 +382,11 @@ module IRB
|
|
370
382
|
message = $1
|
371
383
|
|
372
384
|
candidates = String.instance_methods(true).collect{|m| m.to_s}
|
385
|
+
|
373
386
|
if doc_namespace
|
374
387
|
"String.#{candidates.find{ |i| i == message }}"
|
375
388
|
else
|
376
|
-
select_message(receiver, message, candidates)
|
389
|
+
select_message(receiver, message, candidates.sort)
|
377
390
|
end
|
378
391
|
|
379
392
|
else
|
@@ -390,7 +403,7 @@ module IRB
|
|
390
403
|
else
|
391
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}
|
392
405
|
candidates |= ReservedWords
|
393
|
-
candidates.grep(/^#{Regexp.quote(input)}/)
|
406
|
+
candidates.grep(/^#{Regexp.quote(input)}/).sort
|
394
407
|
end
|
395
408
|
end
|
396
409
|
end
|
data/lib/irb/context.rb
CHANGED
@@ -49,12 +49,15 @@ module IRB
|
|
49
49
|
if IRB.conf.has_key?(:USE_MULTILINE)
|
50
50
|
@use_multiline = IRB.conf[:USE_MULTILINE]
|
51
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
|
52
55
|
@use_multiline = IRB.conf[:USE_RELINE]
|
53
56
|
elsif IRB.conf.has_key?(:USE_REIDLINE)
|
54
57
|
warn <<~MSG.strip
|
55
|
-
USE_REIDLINE is deprecated, please use
|
58
|
+
USE_REIDLINE is deprecated, please use USE_MULTILINE instead.
|
56
59
|
MSG
|
57
|
-
@use_multiline = IRB.conf[:
|
60
|
+
@use_multiline = IRB.conf[:USE_REIDLINE]
|
58
61
|
else
|
59
62
|
@use_multiline = nil
|
60
63
|
end
|
@@ -149,6 +152,8 @@ module IRB
|
|
149
152
|
if @newline_before_multiline_output.nil?
|
150
153
|
@newline_before_multiline_output = true
|
151
154
|
end
|
155
|
+
|
156
|
+
@command_aliases = IRB.conf[:COMMAND_ALIASES]
|
152
157
|
end
|
153
158
|
|
154
159
|
# The top-level workspace, see WorkSpace#main
|
@@ -326,6 +331,9 @@ module IRB
|
|
326
331
|
# See IRB@Command+line+options for more command line options.
|
327
332
|
attr_accessor :back_trace_limit
|
328
333
|
|
334
|
+
# User-defined IRB command aliases
|
335
|
+
attr_accessor :command_aliases
|
336
|
+
|
329
337
|
# Alias for #use_multiline
|
330
338
|
alias use_multiline? use_multiline
|
331
339
|
# Alias for #use_singleline
|
@@ -477,6 +485,20 @@ module IRB
|
|
477
485
|
line = "begin ::Kernel.raise _; rescue _.class\n#{line}\n""end"
|
478
486
|
@workspace.local_variable_set(:_, exception)
|
479
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
|
+
|
480
502
|
set_last_value(@workspace.evaluate(self, line, irb_path, line_no))
|
481
503
|
end
|
482
504
|
|
@@ -518,5 +540,15 @@ module IRB
|
|
518
540
|
end
|
519
541
|
alias __to_s__ to_s
|
520
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
|
521
553
|
end
|
522
554
|
end
|
data/lib/irb/ext/save-history.rb
CHANGED
@@ -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 ==
|
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
|
data/lib/irb/extend-command.rb
CHANGED
@@ -147,6 +147,20 @@ module IRB # :nodoc:
|
|
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)
|
data/lib/irb/init.rb
CHANGED
@@ -44,7 +44,7 @@ module IRB # :nodoc:
|
|
44
44
|
@CONF[:IRB_RC] = nil
|
45
45
|
|
46
46
|
@CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod)
|
47
|
-
@CONF[:USE_COLORIZE] =
|
47
|
+
@CONF[:USE_COLORIZE] = (nc = ENV['NO_COLOR']).nil? || nc.empty?
|
48
48
|
@CONF[:USE_AUTOCOMPLETE] = true
|
49
49
|
@CONF[:INSPECT_MODE] = true
|
50
50
|
@CONF[:USE_TRACER] = false
|
@@ -158,6 +158,11 @@ module IRB # :nodoc:
|
|
158
158
|
@CONF[:LC_MESSAGES] = Locale.new
|
159
159
|
|
160
160
|
@CONF[:AT_EXIT] = []
|
161
|
+
|
162
|
+
@CONF[:COMMAND_ALIASES] = {
|
163
|
+
:'$' => :show_source,
|
164
|
+
:'@' => :whereami,
|
165
|
+
}
|
161
166
|
end
|
162
167
|
|
163
168
|
def IRB.set_measure_callback(type = nil, arg = nil, &block)
|
@@ -255,8 +260,20 @@ module IRB # :nodoc:
|
|
255
260
|
when "--nosingleline", "--noreadline"
|
256
261
|
@CONF[:USE_SINGLELINE] = false
|
257
262
|
when "--multiline", "--reidline"
|
263
|
+
if opt == "--reidline"
|
264
|
+
warn <<~MSG.strip
|
265
|
+
--reidline is deprecated, please use --multiline instead.
|
266
|
+
MSG
|
267
|
+
end
|
268
|
+
|
258
269
|
@CONF[:USE_MULTILINE] = true
|
259
270
|
when "--nomultiline", "--noreidline"
|
271
|
+
if opt == "--noreidline"
|
272
|
+
warn <<~MSG.strip
|
273
|
+
--noreidline is deprecated, please use --nomultiline instead.
|
274
|
+
MSG
|
275
|
+
end
|
276
|
+
|
260
277
|
@CONF[:USE_MULTILINE] = false
|
261
278
|
when /^--extra-doc-dir(?:=(.+))?/
|
262
279
|
opt = $1 || argv.shift
|
@@ -379,11 +396,9 @@ module IRB # :nodoc:
|
|
379
396
|
end
|
380
397
|
if xdg_config_home = ENV["XDG_CONFIG_HOME"]
|
381
398
|
irb_home = File.join(xdg_config_home, "irb")
|
382
|
-
|
383
|
-
|
384
|
-
FileUtils.mkdir_p irb_home
|
399
|
+
if File.directory?(irb_home)
|
400
|
+
yield proc{|rc| irb_home + "/irb#{rc}"}
|
385
401
|
end
|
386
|
-
yield proc{|rc| irb_home + "/irb#{rc}"}
|
387
402
|
end
|
388
403
|
if home = ENV["HOME"]
|
389
404
|
yield proc{|rc| home+"/.irb#{rc}"}
|
data/lib/irb/input-method.rb
CHANGED
@@ -286,7 +286,8 @@ module IRB
|
|
286
286
|
if IRB.conf[:USE_COLORIZE]
|
287
287
|
proc do |output, complete: |
|
288
288
|
next unless IRB::Color.colorable?
|
289
|
-
IRB
|
289
|
+
lvars = IRB.CurrentContext&.local_variables || []
|
290
|
+
IRB::Color.colorize_code(output, complete: complete, local_variables: lvars)
|
290
291
|
end
|
291
292
|
else
|
292
293
|
proc do |output|
|
@@ -295,8 +296,13 @@ module IRB
|
|
295
296
|
end
|
296
297
|
Reline.dig_perfect_match_proc = IRB::InputCompletor::PerfectMatchedProc
|
297
298
|
Reline.autocompletion = IRB.conf[:USE_AUTOCOMPLETE]
|
299
|
+
|
298
300
|
if IRB.conf[:USE_AUTOCOMPLETE]
|
299
|
-
|
301
|
+
begin
|
302
|
+
require 'rdoc'
|
303
|
+
Reline.add_dialog_proc(:show_doc, SHOW_DOC_DIALOG, Reline::DEFAULT_DIALOG_CONTEXT)
|
304
|
+
rescue LoadError
|
305
|
+
end
|
300
306
|
end
|
301
307
|
end
|
302
308
|
|
@@ -320,11 +326,6 @@ module IRB
|
|
320
326
|
[195, 164], # The "ä" that appears when Alt+d is pressed on xterm.
|
321
327
|
[226, 136, 130] # The "∂" that appears when Alt+d in pressed on iTerm2.
|
322
328
|
]
|
323
|
-
begin
|
324
|
-
require 'rdoc'
|
325
|
-
rescue LoadError
|
326
|
-
return nil
|
327
|
-
end
|
328
329
|
|
329
330
|
if just_cursor_moving and completion_journey_data.nil?
|
330
331
|
return nil
|
@@ -460,7 +461,7 @@ module IRB
|
|
460
461
|
# For debug message
|
461
462
|
def inspect
|
462
463
|
config = Reline::Config.new
|
463
|
-
str = "
|
464
|
+
str = "RelineInputMethod with Reline #{Reline::VERSION}"
|
464
465
|
if config.respond_to?(:inputrc_path)
|
465
466
|
inputrc_path = File.expand_path(config.inputrc_path)
|
466
467
|
else
|
data/lib/irb/ruby-lex.rb
CHANGED
@@ -48,7 +48,7 @@ class RubyLex
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# io functions
|
51
|
-
def set_input(io, p = nil, context
|
51
|
+
def set_input(io, p = nil, context:, &block)
|
52
52
|
@io = io
|
53
53
|
if @io.respond_to?(:check_termination)
|
54
54
|
@io.check_termination do |code|
|
@@ -65,6 +65,12 @@ class RubyLex
|
|
65
65
|
false
|
66
66
|
end
|
67
67
|
else
|
68
|
+
# Accept any single-line input starting with a non-identifier alias (ex: @, $)
|
69
|
+
command = code.split(/\s/, 2).first
|
70
|
+
if context.symbol_alias(command)
|
71
|
+
next true
|
72
|
+
end
|
73
|
+
|
68
74
|
code.gsub!(/\s*\z/, '').concat("\n")
|
69
75
|
ltype, indent, continue, code_block_open = check_state(code, context: context)
|
70
76
|
if ltype or indent > 0 or continue or code_block_open
|
@@ -136,16 +142,18 @@ class RubyLex
|
|
136
142
|
:on_param_error
|
137
143
|
]
|
138
144
|
|
145
|
+
def self.generate_local_variables_assign_code(local_variables)
|
146
|
+
"#{local_variables.join('=')}=nil;" unless local_variables.empty?
|
147
|
+
end
|
148
|
+
|
139
149
|
def self.ripper_lex_without_warning(code, context: nil)
|
140
150
|
verbose, $VERBOSE = $VERBOSE, nil
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
line_no = 1
|
148
|
-
end
|
151
|
+
lvars_code = generate_local_variables_assign_code(context&.local_variables || [])
|
152
|
+
if lvars_code
|
153
|
+
code = "#{lvars_code}\n#{code}"
|
154
|
+
line_no = 0
|
155
|
+
else
|
156
|
+
line_no = 1
|
149
157
|
end
|
150
158
|
|
151
159
|
compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
|
@@ -162,7 +170,7 @@ class RubyLex
|
|
162
170
|
end
|
163
171
|
end
|
164
172
|
else
|
165
|
-
lexer.parse.reject { |it| it.pos.first == 0 }
|
173
|
+
lexer.parse.reject { |it| it.pos.first == 0 }.sort_by(&:pos)
|
166
174
|
end
|
167
175
|
end
|
168
176
|
ensure
|
@@ -214,6 +222,8 @@ class RubyLex
|
|
214
222
|
ltype = process_literal_type(tokens)
|
215
223
|
indent = process_nesting_level(tokens)
|
216
224
|
continue = process_continue(tokens)
|
225
|
+
lvars_code = self.class.generate_local_variables_assign_code(context.local_variables)
|
226
|
+
code = "#{lvars_code}\n#{code}" if lvars_code
|
217
227
|
code_block_open = check_code_block(code, tokens)
|
218
228
|
[ltype, indent, continue, code_block_open]
|
219
229
|
end
|
@@ -233,13 +243,13 @@ class RubyLex
|
|
233
243
|
@code_block_open = false
|
234
244
|
end
|
235
245
|
|
236
|
-
def each_top_level_statement
|
246
|
+
def each_top_level_statement(context)
|
237
247
|
initialize_input
|
238
248
|
catch(:TERM_INPUT) do
|
239
249
|
loop do
|
240
250
|
begin
|
241
251
|
prompt
|
242
|
-
unless l = lex
|
252
|
+
unless l = lex(context)
|
243
253
|
throw :TERM_INPUT if @line == ''
|
244
254
|
else
|
245
255
|
@line_no += l.count("\n")
|
@@ -269,18 +279,15 @@ class RubyLex
|
|
269
279
|
end
|
270
280
|
end
|
271
281
|
|
272
|
-
def lex
|
282
|
+
def lex(context)
|
273
283
|
line = @input.call
|
274
284
|
if @io.respond_to?(:check_termination)
|
275
285
|
return line # multiline
|
276
286
|
end
|
277
287
|
code = @line + (line.nil? ? '' : line)
|
278
288
|
code.gsub!(/\s*\z/, '').concat("\n")
|
279
|
-
@tokens = self.class.ripper_lex_without_warning(code)
|
280
|
-
@continue =
|
281
|
-
@code_block_open = check_code_block(code)
|
282
|
-
@indent = process_nesting_level
|
283
|
-
@ltype = process_literal_type
|
289
|
+
@tokens = self.class.ripper_lex_without_warning(code, context: context)
|
290
|
+
@ltype, @indent, @continue, @code_block_open = check_state(code, @tokens, context: context)
|
284
291
|
line
|
285
292
|
end
|
286
293
|
|
@@ -706,6 +713,7 @@ class RubyLex
|
|
706
713
|
i = 0
|
707
714
|
start_token = []
|
708
715
|
end_type = []
|
716
|
+
pending_heredocs = []
|
709
717
|
while i < tokens.size
|
710
718
|
t = tokens[i]
|
711
719
|
case t.event
|
@@ -729,18 +737,27 @@ class RubyLex
|
|
729
737
|
end
|
730
738
|
end
|
731
739
|
when :on_backtick
|
732
|
-
|
733
|
-
|
740
|
+
if t.state.allbits?(Ripper::EXPR_BEG)
|
741
|
+
start_token << t
|
742
|
+
end_type << :on_tstring_end
|
743
|
+
end
|
734
744
|
when :on_qwords_beg, :on_words_beg, :on_qsymbols_beg, :on_symbols_beg
|
735
745
|
start_token << t
|
736
746
|
end_type << :on_tstring_end
|
737
747
|
when :on_heredoc_beg
|
738
|
-
|
739
|
-
|
748
|
+
pending_heredocs << t
|
749
|
+
end
|
750
|
+
|
751
|
+
if pending_heredocs.any? && t.tok.include?("\n")
|
752
|
+
pending_heredocs.reverse_each do |t|
|
753
|
+
start_token << t
|
754
|
+
end_type << :on_heredoc_end
|
755
|
+
end
|
756
|
+
pending_heredocs = []
|
740
757
|
end
|
741
758
|
i += 1
|
742
759
|
end
|
743
|
-
|
760
|
+
pending_heredocs.first || start_token.last
|
744
761
|
end
|
745
762
|
|
746
763
|
def process_literal_type(tokens = @tokens)
|
data/lib/irb/version.rb
CHANGED
data/lib/irb.rb
CHANGED
@@ -426,6 +426,10 @@ module IRB
|
|
426
426
|
def initialize(workspace = nil, input_method = nil)
|
427
427
|
@context = Context.new(self, workspace, input_method)
|
428
428
|
@context.main.extend ExtendCommandBundle
|
429
|
+
@context.command_aliases.each do |alias_name, cmd_name|
|
430
|
+
next if @context.symbol_alias(alias_name)
|
431
|
+
@context.main.install_alias_method(alias_name, cmd_name)
|
432
|
+
end
|
429
433
|
@signal_status = :IN_IRB
|
430
434
|
@scanner = RubyLex.new
|
431
435
|
end
|
@@ -506,13 +510,15 @@ module IRB
|
|
506
510
|
|
507
511
|
@scanner.set_auto_indent(@context) if @context.auto_indent_mode
|
508
512
|
|
509
|
-
@scanner.each_top_level_statement do |line, line_no|
|
513
|
+
@scanner.each_top_level_statement(@context) do |line, line_no|
|
510
514
|
signal_status(:IN_EVAL) do
|
511
515
|
begin
|
512
516
|
line.untaint if RUBY_VERSION < '2.7'
|
513
517
|
if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
|
514
518
|
IRB.set_measure_callback
|
515
519
|
end
|
520
|
+
# Assignment expression check should be done before @context.evaluate to handle code like `a /2#/ if false; a = 1`
|
521
|
+
is_assignment = assignment_expression?(line)
|
516
522
|
if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
|
517
523
|
result = nil
|
518
524
|
last_proc = proc{ result = @context.evaluate(line, line_no, exception: exc) }
|
@@ -529,7 +535,7 @@ module IRB
|
|
529
535
|
@context.evaluate(line, line_no, exception: exc)
|
530
536
|
end
|
531
537
|
if @context.echo?
|
532
|
-
if
|
538
|
+
if is_assignment
|
533
539
|
if @context.echo_on_assignment?
|
534
540
|
output_value(@context.echo_on_assignment? == :truncate)
|
535
541
|
end
|
@@ -592,11 +598,7 @@ module IRB
|
|
592
598
|
|
593
599
|
if exc.backtrace
|
594
600
|
order = nil
|
595
|
-
if '
|
596
|
-
# Exception#full_message doesn't have keyword arguments.
|
597
|
-
message = exc.full_message # the same of (highlight: true, order: bottom)
|
598
|
-
order = :bottom
|
599
|
-
elsif '2.5.1' <= RUBY_VERSION && RUBY_VERSION < '3.0.0'
|
601
|
+
if RUBY_VERSION < '3.0.0'
|
600
602
|
if STDOUT.tty?
|
601
603
|
message = exc.full_message(order: :bottom)
|
602
604
|
order = :bottom
|
@@ -827,9 +829,12 @@ module IRB
|
|
827
829
|
# array of parsed expressions. The first element of each expression is the
|
828
830
|
# expression's type.
|
829
831
|
verbose, $VERBOSE = $VERBOSE, nil
|
830
|
-
|
832
|
+
code = "#{RubyLex.generate_local_variables_assign_code(@context.local_variables) || 'nil;'}\n#{line}"
|
833
|
+
# Get the last node_type of the line. drop(1) is to ignore the local_variables_assign_code part.
|
834
|
+
node_type = Ripper.sexp(code)&.dig(1)&.drop(1)&.dig(-1, 0)
|
835
|
+
ASSIGNMENT_NODE_TYPES.include?(node_type)
|
836
|
+
ensure
|
831
837
|
$VERBOSE = verbose
|
832
|
-
result
|
833
838
|
end
|
834
839
|
|
835
840
|
ATTR_TTY = "\e[%sm"
|
data/man/irb.1
CHANGED
@@ -173,8 +173,19 @@ The default value is 16.
|
|
173
173
|
.El
|
174
174
|
.Pp
|
175
175
|
.Sh ENVIRONMENT
|
176
|
-
.Bl -tag -compact
|
176
|
+
.Bl -tag -compact -width "XDG_CONFIG_HOME"
|
177
|
+
.It Ev IRB_LANG
|
178
|
+
The locale used for
|
179
|
+
.Nm .
|
180
|
+
.Pp
|
177
181
|
.It Ev IRBRC
|
182
|
+
The path to the personal initialization file.
|
183
|
+
.Pp
|
184
|
+
.It Ev XDG_CONFIG_HOME
|
185
|
+
.Nm
|
186
|
+
respects XDG_CONFIG_HOME. If this is set, load
|
187
|
+
.Pa $XDG_CONFIG_HOME/irb/irbrc
|
188
|
+
as a personal initialization file.
|
178
189
|
.Pp
|
179
190
|
.El
|
180
191
|
.Pp
|
@@ -186,7 +197,17 @@ depends on same variables as
|
|
186
197
|
.Sh FILES
|
187
198
|
.Bl -tag -compact
|
188
199
|
.It Pa ~/.irbrc
|
189
|
-
Personal irb initialization.
|
200
|
+
Personal irb initialization. If
|
201
|
+
.Ev IRBRC
|
202
|
+
is set, read
|
203
|
+
.Pa $IRBRC
|
204
|
+
instead. If
|
205
|
+
.Ev IRBRC
|
206
|
+
is not set and
|
207
|
+
.Ev XDG_CONFIG_HOME
|
208
|
+
is set,
|
209
|
+
.Pa $XDG_CONFIG_HOME/irb/irbrc
|
210
|
+
is loaded.
|
190
211
|
.Pp
|
191
212
|
.El
|
192
213
|
.Pp
|
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.4.
|
4
|
+
version: 1.4.3
|
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-
|
12
|
+
date: 2022-11-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: reline
|
@@ -107,7 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '2.
|
110
|
+
version: '2.6'
|
111
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
113
|
- - ">="
|