irb 1.9.0 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
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 && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
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 exc.backtrace
709
- order = nil
710
- if RUBY_VERSION < '3.0.0'
711
- if STDOUT.tty?
712
- message = exc.full_message(order: :bottom)
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
- message = convert_invalid_byte_sequence(message, exc.message.encoding)
723
- 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)
724
- message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
725
- case order
726
- when :top
727
- lines = m.split("\n")
728
- when :bottom
729
- lines = m.split("\n").reverse
730
- end
731
- unless irb_bug
732
- lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact
733
- if lines.size > @context.back_trace_limit
734
- omit = lines.size - @context.back_trace_limit
735
- lines = lines[0..(@context.back_trace_limit - 1)]
736
- lines << "\t... %d levels..." % omit
737
- end
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
- lines = lines.reverse if order == :bottom
740
- lines.map{ |l| l + "\n" }.join
741
- }
742
- # The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object.
743
- message = message.gsub(/\(irb\):(?<num>\d+):in `<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in `<main>'" }
744
- puts message
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
- printf @context.return_format, "\n#{str}"
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
- truncate_prompt_main(@context.main.to_s)
935
+ main_str = @context.main.to_s rescue "!#{$!.class}"
936
+ truncate_prompt_main(main_str)
930
937
  when "M"
931
- truncate_prompt_main(@context.main.inspect)
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.9.0
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-11-10 00:00:00.000000000 Z
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.5.0.dev
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