irb 1.4.2 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +61 -0
- data/Rakefile +25 -0
- data/irb.gemspec +1 -1
- data/lib/irb/cmd/backtrace.rb +21 -0
- data/lib/irb/cmd/break.rb +21 -0
- data/lib/irb/cmd/catch.rb +21 -0
- data/lib/irb/cmd/chws.rb +6 -0
- data/lib/irb/cmd/continue.rb +17 -0
- data/lib/irb/cmd/debug.rb +135 -0
- data/lib/irb/cmd/delete.rb +17 -0
- data/lib/irb/cmd/edit.rb +61 -0
- data/lib/irb/cmd/finish.rb +17 -0
- data/lib/irb/cmd/help.rb +14 -0
- data/lib/irb/cmd/info.rb +9 -22
- data/lib/irb/cmd/irb_info.rb +37 -0
- data/lib/irb/cmd/load.rb +24 -10
- data/lib/irb/cmd/ls.rb +13 -0
- data/lib/irb/cmd/measure.rb +3 -0
- data/lib/irb/cmd/next.rb +17 -0
- data/lib/irb/cmd/nop.rb +24 -0
- data/lib/irb/cmd/pushws.rb +9 -0
- data/lib/irb/cmd/show_cmds.rb +39 -0
- data/lib/irb/cmd/show_source.rb +60 -43
- data/lib/irb/cmd/step.rb +17 -0
- data/lib/irb/cmd/subirb.rb +32 -6
- data/lib/irb/cmd/whereami.rb +3 -0
- data/lib/irb/color.rb +9 -2
- data/lib/irb/completion.rb +53 -40
- data/lib/irb/context.rb +40 -2
- data/lib/irb/ext/save-history.rb +2 -2
- data/lib/irb/extend-command.rb +100 -23
- data/lib/irb/init.rb +26 -6
- 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 +72 -13
- data/man/irb.1 +23 -2
- metadata +16 -4
data/lib/irb/cmd/next.rb
ADDED
@@ -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,41 @@ 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
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def string_literal?(args)
|
33
|
+
sexp = Ripper.sexp(args)
|
34
|
+
sexp && sexp.size == 2 && sexp.last&.first&.first == :string_literal
|
35
|
+
end
|
36
|
+
end
|
17
37
|
|
18
38
|
if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
|
19
39
|
def self.execute(conf, *opts, **kwargs, &block)
|
20
40
|
command = new(conf)
|
21
41
|
command.execute(*opts, **kwargs, &block)
|
42
|
+
rescue CommandArgumentError => e
|
43
|
+
puts e.message
|
22
44
|
end
|
23
45
|
else
|
24
46
|
def self.execute(conf, *opts, &block)
|
25
47
|
command = new(conf)
|
26
48
|
command.execute(*opts, &block)
|
49
|
+
rescue CommandArgumentError => e
|
50
|
+
puts e.message
|
27
51
|
end
|
28
52
|
end
|
29
53
|
|
data/lib/irb/cmd/pushws.rb
CHANGED
@@ -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
|
data/lib/irb/cmd/show_source.rb
CHANGED
@@ -9,12 +9,71 @@ 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
|
+
|
15
|
+
class << self
|
16
|
+
def transform_args(args)
|
17
|
+
# Return a string literal as is for backward compatibility
|
18
|
+
if args.empty? || string_literal?(args)
|
19
|
+
args
|
20
|
+
else # Otherwise, consider the input as a String for convenience
|
21
|
+
args.strip.dump
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_source(str, irb_context)
|
26
|
+
case str
|
27
|
+
when /\A[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
|
28
|
+
eval(str, irb_context.workspace.binding) # trigger autoload
|
29
|
+
base = irb_context.workspace.binding.receiver.yield_self { |r| r.is_a?(Module) ? r : Object }
|
30
|
+
file, line = base.const_source_location(str) if base.respond_to?(:const_source_location) # Ruby 2.7+
|
31
|
+
when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
|
32
|
+
owner = eval(Regexp.last_match[:owner], irb_context.workspace.binding)
|
33
|
+
method = Regexp.last_match[:method]
|
34
|
+
if owner.respond_to?(:instance_method) && owner.instance_methods.include?(method.to_sym)
|
35
|
+
file, line = owner.instance_method(method).source_location
|
36
|
+
end
|
37
|
+
when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
|
38
|
+
receiver = eval(Regexp.last_match[:receiver] || 'self', irb_context.workspace.binding)
|
39
|
+
method = Regexp.last_match[:method]
|
40
|
+
file, line = receiver.method(method).source_location if receiver.respond_to?(method)
|
41
|
+
end
|
42
|
+
if file && line
|
43
|
+
Source.new(file: file, first_line: line, last_line: find_end(file, line))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def find_end(file, first_line)
|
50
|
+
return first_line unless File.exist?(file)
|
51
|
+
lex = RubyLex.new
|
52
|
+
lines = File.read(file).lines[(first_line - 1)..-1]
|
53
|
+
tokens = RubyLex.ripper_lex_without_warning(lines.join)
|
54
|
+
prev_tokens = []
|
55
|
+
|
56
|
+
# chunk with line number
|
57
|
+
tokens.chunk { |tok| tok.pos[0] }.each do |lnum, chunk|
|
58
|
+
code = lines[0..lnum].join
|
59
|
+
prev_tokens.concat chunk
|
60
|
+
continue = lex.process_continue(prev_tokens)
|
61
|
+
code_block_open = lex.check_code_block(code, prev_tokens)
|
62
|
+
if !continue && !code_block_open
|
63
|
+
return first_line + lnum
|
64
|
+
end
|
65
|
+
end
|
66
|
+
first_line
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
12
70
|
def execute(str = nil)
|
13
71
|
unless str.is_a?(String)
|
14
72
|
puts "Error: Expected a string but got #{str.inspect}"
|
15
73
|
return
|
16
74
|
end
|
17
|
-
|
75
|
+
|
76
|
+
source = self.class.find_source(str, @irb_context)
|
18
77
|
if source && File.exist?(source.file)
|
19
78
|
show_source(source)
|
20
79
|
else
|
@@ -35,48 +94,6 @@ module IRB
|
|
35
94
|
puts
|
36
95
|
end
|
37
96
|
|
38
|
-
def find_source(str)
|
39
|
-
case str
|
40
|
-
when /\A[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
|
41
|
-
eval(str, irb_context.workspace.binding) # trigger autoload
|
42
|
-
base = irb_context.workspace.binding.receiver.yield_self { |r| r.is_a?(Module) ? r : Object }
|
43
|
-
file, line = base.const_source_location(str) if base.respond_to?(:const_source_location) # Ruby 2.7+
|
44
|
-
when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
|
45
|
-
owner = eval(Regexp.last_match[:owner], irb_context.workspace.binding)
|
46
|
-
method = Regexp.last_match[:method]
|
47
|
-
if owner.respond_to?(:instance_method) && owner.instance_methods.include?(method.to_sym)
|
48
|
-
file, line = owner.instance_method(method).source_location
|
49
|
-
end
|
50
|
-
when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
|
51
|
-
receiver = eval(Regexp.last_match[:receiver] || 'self', irb_context.workspace.binding)
|
52
|
-
method = Regexp.last_match[:method]
|
53
|
-
file, line = receiver.method(method).source_location if receiver.respond_to?(method)
|
54
|
-
end
|
55
|
-
if file && line
|
56
|
-
Source.new(file: file, first_line: line, last_line: find_end(file, line))
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def find_end(file, first_line)
|
61
|
-
return first_line unless File.exist?(file)
|
62
|
-
lex = RubyLex.new
|
63
|
-
lines = File.read(file).lines[(first_line - 1)..-1]
|
64
|
-
tokens = RubyLex.ripper_lex_without_warning(lines.join)
|
65
|
-
prev_tokens = []
|
66
|
-
|
67
|
-
# chunk with line number
|
68
|
-
tokens.chunk { |tok| tok.pos[0] }.each do |lnum, chunk|
|
69
|
-
code = lines[0..lnum].join
|
70
|
-
prev_tokens.concat chunk
|
71
|
-
continue = lex.process_continue(prev_tokens)
|
72
|
-
code_block_open = lex.check_code_block(code, prev_tokens)
|
73
|
-
if !continue && !code_block_open
|
74
|
-
return first_line + lnum
|
75
|
-
end
|
76
|
-
end
|
77
|
-
first_line
|
78
|
-
end
|
79
|
-
|
80
97
|
def bold(str)
|
81
98
|
Color.colorize(str, [:BOLD])
|
82
99
|
end
|
data/lib/irb/cmd/step.rb
ADDED
@@ -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 Step < DebugCommand
|
10
|
+
def execute(*args)
|
11
|
+
super(do_cmds: ["step", *args].join(" "))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# :startdoc:
|
17
|
+
end
|
data/lib/irb/cmd/subirb.rb
CHANGED
@@ -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
|
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 <
|
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 <
|
32
|
-
|
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 <
|
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
|
data/lib/irb/cmd/whereami.rb
CHANGED
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 (@, $) or keywords (next, break)
|
490
|
+
command, args = line.split(/\s/, 2)
|
491
|
+
if original = command_aliases[command.to_sym]
|
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,21 @@ 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 true 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.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)
|
558
|
+
end
|
521
559
|
end
|
522
560
|
end
|
data/lib/irb/ext/save-history.rb
CHANGED
@@ -70,10 +70,10 @@ 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
|
-
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
|