irb 1.9.0 → 1.10.0
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.
- checksums.yaml +4 -4
- data/Gemfile +3 -5
- data/README.md +11 -9
- data/Rakefile +2 -2
- data/lib/irb/cmd/history.rb +47 -0
- data/lib/irb/cmd/show_cmds.rb +6 -0
- data/lib/irb/cmd/show_source.rb +9 -2
- data/lib/irb/completion.rb +25 -4
- data/lib/irb/context.rb +22 -14
- data/lib/irb/debug.rb +18 -0
- data/lib/irb/extend-command.rb +6 -0
- data/lib/irb/history.rb +1 -1
- data/lib/irb/init.rb +4 -5
- data/lib/irb/input-method.rb +3 -0
- data/lib/irb/lc/help-message +1 -0
- data/lib/irb/pager.rb +12 -11
- data/lib/irb/source_finder.rb +26 -6
- data/lib/irb/version.rb +2 -2
- data/lib/irb.rb +48 -40
- metadata +4 -8
- data/lib/irb/type_completion/completor.rb +0 -235
- data/lib/irb/type_completion/methods.rb +0 -13
- data/lib/irb/type_completion/scope.rb +0 -412
- data/lib/irb/type_completion/type_analyzer.rb +0 -1169
- data/lib/irb/type_completion/types.rb +0 -426
data/lib/irb.rb
CHANGED
@@ -20,6 +20,7 @@ require_relative "irb/color"
|
|
20
20
|
require_relative "irb/version"
|
21
21
|
require_relative "irb/easter-egg"
|
22
22
|
require_relative "irb/debug"
|
23
|
+
require_relative "irb/pager"
|
23
24
|
|
24
25
|
# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
|
25
26
|
# expressions read from the standard input.
|
@@ -697,7 +698,7 @@ module IRB
|
|
697
698
|
end
|
698
699
|
|
699
700
|
def handle_exception(exc)
|
700
|
-
if exc.backtrace
|
701
|
+
if exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
|
701
702
|
!(SyntaxError === exc) && !(EncodingError === exc)
|
702
703
|
# The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno.
|
703
704
|
irb_bug = true
|
@@ -705,45 +706,49 @@ module IRB
|
|
705
706
|
irb_bug = false
|
706
707
|
end
|
707
708
|
|
708
|
-
if
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
order = :bottom
|
714
|
-
else
|
715
|
-
message = exc.full_message(order: :top)
|
716
|
-
order = :top
|
717
|
-
end
|
718
|
-
else # '3.0.0' <= RUBY_VERSION
|
709
|
+
if RUBY_VERSION < '3.0.0'
|
710
|
+
if STDOUT.tty?
|
711
|
+
message = exc.full_message(order: :bottom)
|
712
|
+
order = :bottom
|
713
|
+
else
|
719
714
|
message = exc.full_message(order: :top)
|
720
715
|
order = :top
|
721
716
|
end
|
722
|
-
|
723
|
-
message =
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
717
|
+
else # '3.0.0' <= RUBY_VERSION
|
718
|
+
message = exc.full_message(order: :top)
|
719
|
+
order = :top
|
720
|
+
end
|
721
|
+
message = convert_invalid_byte_sequence(message, exc.message.encoding)
|
722
|
+
message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
|
723
|
+
message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
|
724
|
+
case order
|
725
|
+
when :top
|
726
|
+
lines = m.split("\n")
|
727
|
+
when :bottom
|
728
|
+
lines = m.split("\n").reverse
|
729
|
+
end
|
730
|
+
unless irb_bug
|
731
|
+
lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact
|
732
|
+
if lines.size > @context.back_trace_limit
|
733
|
+
omit = lines.size - @context.back_trace_limit
|
734
|
+
lines = lines[0..(@context.back_trace_limit - 1)]
|
735
|
+
lines << "\t... %d levels..." % omit
|
738
736
|
end
|
739
|
-
|
740
|
-
|
741
|
-
}
|
742
|
-
|
743
|
-
|
744
|
-
|
737
|
+
end
|
738
|
+
lines = lines.reverse if order == :bottom
|
739
|
+
lines.map{ |l| l + "\n" }.join
|
740
|
+
}
|
741
|
+
# The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object.
|
742
|
+
message = message.gsub(/\(irb\):(?<num>\d+):in `<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in `<main>'" }
|
743
|
+
puts message
|
744
|
+
puts 'Maybe IRB bug!' if irb_bug
|
745
|
+
rescue Exception => handler_exc
|
746
|
+
begin
|
747
|
+
puts exc.inspect
|
748
|
+
puts "backtraces are hidden because #{handler_exc} was raised when processing them"
|
749
|
+
rescue Exception
|
750
|
+
puts 'Uninspectable exception occurred'
|
745
751
|
end
|
746
|
-
print "Maybe IRB bug!\n" if irb_bug
|
747
752
|
end
|
748
753
|
|
749
754
|
# Evaluates the given block using the given +path+ as the Context#irb_path
|
@@ -855,11 +860,12 @@ module IRB
|
|
855
860
|
end
|
856
861
|
end
|
857
862
|
end
|
863
|
+
|
858
864
|
if multiline_p && @context.newline_before_multiline_output?
|
859
|
-
|
860
|
-
else
|
861
|
-
printf @context.return_format, str
|
865
|
+
str = "\n" + str
|
862
866
|
end
|
867
|
+
|
868
|
+
Pager.page_content(format(@context.return_format, str), retain_content: true)
|
863
869
|
end
|
864
870
|
|
865
871
|
# Outputs the local variables to this current session, including
|
@@ -926,9 +932,11 @@ module IRB
|
|
926
932
|
when "N"
|
927
933
|
@context.irb_name
|
928
934
|
when "m"
|
929
|
-
|
935
|
+
main_str = @context.main.to_s rescue "!#{$!.class}"
|
936
|
+
truncate_prompt_main(main_str)
|
930
937
|
when "M"
|
931
|
-
|
938
|
+
main_str = @context.main.inspect rescue "!#{$!.class}"
|
939
|
+
truncate_prompt_main(main_str)
|
932
940
|
when "l"
|
933
941
|
ltype
|
934
942
|
when "i"
|
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
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-12-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: reline
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- lib/irb/cmd/edit.rb
|
71
71
|
- lib/irb/cmd/finish.rb
|
72
72
|
- lib/irb/cmd/help.rb
|
73
|
+
- lib/irb/cmd/history.rb
|
73
74
|
- lib/irb/cmd/info.rb
|
74
75
|
- lib/irb/cmd/irb_info.rb
|
75
76
|
- lib/irb/cmd/load.rb
|
@@ -118,11 +119,6 @@ files:
|
|
118
119
|
- lib/irb/ruby_logo.aa
|
119
120
|
- lib/irb/source_finder.rb
|
120
121
|
- lib/irb/statement.rb
|
121
|
-
- lib/irb/type_completion/completor.rb
|
122
|
-
- lib/irb/type_completion/methods.rb
|
123
|
-
- lib/irb/type_completion/scope.rb
|
124
|
-
- lib/irb/type_completion/type_analyzer.rb
|
125
|
-
- lib/irb/type_completion/types.rb
|
126
122
|
- lib/irb/version.rb
|
127
123
|
- lib/irb/workspace.rb
|
128
124
|
- lib/irb/ws-for-case-2.rb
|
@@ -152,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
148
|
- !ruby/object:Gem::Version
|
153
149
|
version: '0'
|
154
150
|
requirements: []
|
155
|
-
rubygems_version: 3.
|
151
|
+
rubygems_version: 3.4.10
|
156
152
|
signing_key:
|
157
153
|
specification_version: 4
|
158
154
|
summary: Interactive Ruby command-line tool for REPL (Read Eval Print Loop).
|
@@ -1,235 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'prism'
|
4
|
-
require 'irb/completion'
|
5
|
-
require_relative 'type_analyzer'
|
6
|
-
|
7
|
-
module IRB
|
8
|
-
module TypeCompletion
|
9
|
-
class Completor < BaseCompletor # :nodoc:
|
10
|
-
HIDDEN_METHODS = %w[Namespace TypeName] # defined by rbs, should be hidden
|
11
|
-
|
12
|
-
class << self
|
13
|
-
attr_accessor :last_completion_error
|
14
|
-
end
|
15
|
-
|
16
|
-
def inspect
|
17
|
-
name = 'TypeCompletion::Completor'
|
18
|
-
prism_info = "Prism: #{Prism::VERSION}"
|
19
|
-
if Types.rbs_builder
|
20
|
-
"#{name}(#{prism_info}, RBS: #{RBS::VERSION})"
|
21
|
-
elsif Types.rbs_load_error
|
22
|
-
"#{name}(#{prism_info}, RBS: #{Types.rbs_load_error.inspect})"
|
23
|
-
else
|
24
|
-
"#{name}(#{prism_info}, RBS: loading)"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def completion_candidates(preposing, target, _postposing, bind:)
|
29
|
-
@preposing = preposing
|
30
|
-
verbose, $VERBOSE = $VERBOSE, nil
|
31
|
-
code = "#{preposing}#{target}"
|
32
|
-
@result = analyze code, bind
|
33
|
-
name, candidates = candidates_from_result(@result)
|
34
|
-
|
35
|
-
all_symbols_pattern = /\A[ -\/:-@\[-`\{-~]*\z/
|
36
|
-
candidates.map(&:to_s).select { !_1.match?(all_symbols_pattern) && _1.start_with?(name) }.uniq.sort.map do
|
37
|
-
target + _1[name.size..]
|
38
|
-
end
|
39
|
-
rescue SyntaxError, StandardError => e
|
40
|
-
Completor.last_completion_error = e
|
41
|
-
handle_error(e)
|
42
|
-
[]
|
43
|
-
ensure
|
44
|
-
$VERBOSE = verbose
|
45
|
-
end
|
46
|
-
|
47
|
-
def doc_namespace(preposing, matched, postposing, bind:)
|
48
|
-
name = matched[/[a-zA-Z_0-9]*[!?=]?\z/]
|
49
|
-
method_doc = -> type do
|
50
|
-
type = type.types.find { _1.all_methods.include? name.to_sym }
|
51
|
-
case type
|
52
|
-
when Types::SingletonType
|
53
|
-
"#{Types.class_name_of(type.module_or_class)}.#{name}"
|
54
|
-
when Types::InstanceType
|
55
|
-
"#{Types.class_name_of(type.klass)}##{name}"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
call_or_const_doc = -> type do
|
59
|
-
if name =~ /\A[A-Z]/
|
60
|
-
type = type.types.grep(Types::SingletonType).find { _1.module_or_class.const_defined?(name) }
|
61
|
-
type.module_or_class == Object ? name : "#{Types.class_name_of(type.module_or_class)}::#{name}" if type
|
62
|
-
else
|
63
|
-
method_doc.call(type)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
value_doc = -> type do
|
68
|
-
return unless type
|
69
|
-
type.types.each do |t|
|
70
|
-
case t
|
71
|
-
when Types::SingletonType
|
72
|
-
return Types.class_name_of(t.module_or_class)
|
73
|
-
when Types::InstanceType
|
74
|
-
return Types.class_name_of(t.klass)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
nil
|
78
|
-
end
|
79
|
-
|
80
|
-
case @result
|
81
|
-
in [:call_or_const, type, _name, _self_call]
|
82
|
-
call_or_const_doc.call type
|
83
|
-
in [:const, type, _name, scope]
|
84
|
-
if type
|
85
|
-
call_or_const_doc.call type
|
86
|
-
else
|
87
|
-
value_doc.call scope[name]
|
88
|
-
end
|
89
|
-
in [:gvar, _name, scope]
|
90
|
-
value_doc.call scope["$#{name}"]
|
91
|
-
in [:ivar, _name, scope]
|
92
|
-
value_doc.call scope["@#{name}"]
|
93
|
-
in [:cvar, _name, scope]
|
94
|
-
value_doc.call scope["@@#{name}"]
|
95
|
-
in [:call, type, _name, _self_call]
|
96
|
-
method_doc.call type
|
97
|
-
in [:lvar_or_method, _name, scope]
|
98
|
-
if scope.local_variables.include?(name)
|
99
|
-
value_doc.call scope[name]
|
100
|
-
else
|
101
|
-
method_doc.call scope.self_type
|
102
|
-
end
|
103
|
-
else
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def candidates_from_result(result)
|
108
|
-
candidates = case result
|
109
|
-
in [:require, name]
|
110
|
-
retrieve_files_to_require_from_load_path
|
111
|
-
in [:require_relative, name]
|
112
|
-
retrieve_files_to_require_relative_from_current_dir
|
113
|
-
in [:call_or_const, type, name, self_call]
|
114
|
-
((self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS) | type.constants
|
115
|
-
in [:const, type, name, scope]
|
116
|
-
if type
|
117
|
-
scope_constants = type.types.flat_map do |t|
|
118
|
-
scope.table_module_constants(t.module_or_class) if t.is_a?(Types::SingletonType)
|
119
|
-
end
|
120
|
-
(scope_constants.compact | type.constants.map(&:to_s)).sort
|
121
|
-
else
|
122
|
-
scope.constants.sort | ReservedWords
|
123
|
-
end
|
124
|
-
in [:ivar, name, scope]
|
125
|
-
ivars = scope.instance_variables.sort
|
126
|
-
name == '@' ? ivars + scope.class_variables.sort : ivars
|
127
|
-
in [:cvar, name, scope]
|
128
|
-
scope.class_variables
|
129
|
-
in [:gvar, name, scope]
|
130
|
-
scope.global_variables
|
131
|
-
in [:symbol, name]
|
132
|
-
Symbol.all_symbols.map { _1.inspect[1..] }
|
133
|
-
in [:call, type, name, self_call]
|
134
|
-
(self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS
|
135
|
-
in [:lvar_or_method, name, scope]
|
136
|
-
scope.self_type.all_methods.map(&:to_s) | scope.local_variables | ReservedWords
|
137
|
-
else
|
138
|
-
[]
|
139
|
-
end
|
140
|
-
[name || '', candidates]
|
141
|
-
end
|
142
|
-
|
143
|
-
def analyze(code, binding = Object::TOPLEVEL_BINDING)
|
144
|
-
# Workaround for https://github.com/ruby/prism/issues/1592
|
145
|
-
return if code.match?(/%[qQ]\z/)
|
146
|
-
|
147
|
-
ast = Prism.parse(code, scopes: [binding.local_variables]).value
|
148
|
-
name = code[/(@@|@|\$)?\w*[!?=]?\z/]
|
149
|
-
*parents, target_node = find_target ast, code.bytesize - name.bytesize
|
150
|
-
return unless target_node
|
151
|
-
|
152
|
-
calculate_scope = -> { TypeAnalyzer.calculate_target_type_scope(binding, parents, target_node).last }
|
153
|
-
calculate_type_scope = ->(node) { TypeAnalyzer.calculate_target_type_scope binding, [*parents, target_node], node }
|
154
|
-
|
155
|
-
case target_node
|
156
|
-
when Prism::StringNode, Prism::InterpolatedStringNode
|
157
|
-
call_node, args_node = parents.last(2)
|
158
|
-
return unless call_node.is_a?(Prism::CallNode) && call_node.receiver.nil?
|
159
|
-
return unless args_node.is_a?(Prism::ArgumentsNode) && args_node.arguments.size == 1
|
160
|
-
|
161
|
-
case call_node.name
|
162
|
-
when :require
|
163
|
-
[:require, name.rstrip]
|
164
|
-
when :require_relative
|
165
|
-
[:require_relative, name.rstrip]
|
166
|
-
end
|
167
|
-
when Prism::SymbolNode
|
168
|
-
if parents.last.is_a? Prism::BlockArgumentNode # method(&:target)
|
169
|
-
receiver_type, _scope = calculate_type_scope.call target_node
|
170
|
-
[:call, receiver_type, name, false]
|
171
|
-
else
|
172
|
-
[:symbol, name] unless name.empty?
|
173
|
-
end
|
174
|
-
when Prism::CallNode
|
175
|
-
return [:lvar_or_method, name, calculate_scope.call] if target_node.receiver.nil?
|
176
|
-
|
177
|
-
self_call = target_node.receiver.is_a? Prism::SelfNode
|
178
|
-
op = target_node.call_operator
|
179
|
-
receiver_type, _scope = calculate_type_scope.call target_node.receiver
|
180
|
-
receiver_type = receiver_type.nonnillable if op == '&.'
|
181
|
-
[op == '::' ? :call_or_const : :call, receiver_type, name, self_call]
|
182
|
-
when Prism::LocalVariableReadNode, Prism::LocalVariableTargetNode
|
183
|
-
[:lvar_or_method, name, calculate_scope.call]
|
184
|
-
when Prism::ConstantReadNode, Prism::ConstantTargetNode
|
185
|
-
if parents.last.is_a? Prism::ConstantPathNode
|
186
|
-
path_node = parents.last
|
187
|
-
if path_node.parent # A::B
|
188
|
-
receiver, scope = calculate_type_scope.call(path_node.parent)
|
189
|
-
[:const, receiver, name, scope]
|
190
|
-
else # ::A
|
191
|
-
scope = calculate_scope.call
|
192
|
-
[:const, Types::SingletonType.new(Object), name, scope]
|
193
|
-
end
|
194
|
-
else
|
195
|
-
[:const, nil, name, calculate_scope.call]
|
196
|
-
end
|
197
|
-
when Prism::GlobalVariableReadNode, Prism::GlobalVariableTargetNode
|
198
|
-
[:gvar, name, calculate_scope.call]
|
199
|
-
when Prism::InstanceVariableReadNode, Prism::InstanceVariableTargetNode
|
200
|
-
[:ivar, name, calculate_scope.call]
|
201
|
-
when Prism::ClassVariableReadNode, Prism::ClassVariableTargetNode
|
202
|
-
[:cvar, name, calculate_scope.call]
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
def find_target(node, position)
|
207
|
-
location = (
|
208
|
-
case node
|
209
|
-
when Prism::CallNode
|
210
|
-
node.message_loc
|
211
|
-
when Prism::SymbolNode
|
212
|
-
node.value_loc
|
213
|
-
when Prism::StringNode
|
214
|
-
node.content_loc
|
215
|
-
when Prism::InterpolatedStringNode
|
216
|
-
node.closing_loc if node.parts.empty?
|
217
|
-
end
|
218
|
-
)
|
219
|
-
return [node] if location&.start_offset == position
|
220
|
-
|
221
|
-
node.compact_child_nodes.each do |n|
|
222
|
-
match = find_target(n, position)
|
223
|
-
next unless match
|
224
|
-
match.unshift node
|
225
|
-
return match
|
226
|
-
end
|
227
|
-
|
228
|
-
[node] if node.location.start_offset == position
|
229
|
-
end
|
230
|
-
|
231
|
-
def handle_error(e)
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module IRB
|
4
|
-
module TypeCompletion
|
5
|
-
module Methods
|
6
|
-
OBJECT_SINGLETON_CLASS_METHOD = Object.instance_method(:singleton_class)
|
7
|
-
OBJECT_INSTANCE_VARIABLES_METHOD = Object.instance_method(:instance_variables)
|
8
|
-
OBJECT_INSTANCE_VARIABLE_GET_METHOD = Object.instance_method(:instance_variable_get)
|
9
|
-
OBJECT_CLASS_METHOD = Object.instance_method(:class)
|
10
|
-
MODULE_NAME_METHOD = Module.instance_method(:name)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|