irb 1.6.2 → 1.6.4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/irb/ruby-lex.rb CHANGED
@@ -1,14 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
  #
3
3
  # irb/ruby-lex.rb - ruby lexcal analyzer
4
- # $Release Version: 0.9.6$
5
- # $Revision$
6
4
  # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
5
  #
8
- # --
9
- #
10
- #
11
- #
12
6
 
13
7
  require "ripper"
14
8
  require "jruby" if RUBY_ENGINE == "jruby"
@@ -22,7 +16,8 @@ class RubyLex
22
16
  end
23
17
  end
24
18
 
25
- def initialize
19
+ def initialize(context)
20
+ @context = context
26
21
  @exp_line_no = @line_no = 1
27
22
  @indent = 0
28
23
  @continue = false
@@ -48,13 +43,13 @@ class RubyLex
48
43
  end
49
44
 
50
45
  # io functions
51
- def set_input(io, p = nil, context:, &block)
46
+ def set_input(io, &block)
52
47
  @io = io
53
48
  if @io.respond_to?(:check_termination)
54
49
  @io.check_termination do |code|
55
50
  if Reline::IOGate.in_pasting?
56
- lex = RubyLex.new
57
- rest = lex.check_termination_in_prev_line(code, context: context)
51
+ lex = RubyLex.new(@context)
52
+ rest = lex.check_termination_in_prev_line(code)
58
53
  if rest
59
54
  Reline.delete_text
60
55
  rest.bytes.reverse_each do |c|
@@ -67,12 +62,13 @@ class RubyLex
67
62
  else
68
63
  # Accept any single-line input for symbol aliases or commands that transform args
69
64
  command = code.split(/\s/, 2).first
70
- if context.symbol_alias?(command) || context.transform_args?(command)
65
+ if @context.symbol_alias?(command) || @context.transform_args?(command)
71
66
  next true
72
67
  end
73
68
 
74
69
  code.gsub!(/\s*\z/, '').concat("\n")
75
- ltype, indent, continue, code_block_open = check_state(code, context: context)
70
+ tokens = self.class.ripper_lex_without_warning(code, context: @context)
71
+ ltype, indent, continue, code_block_open = check_state(code, tokens)
76
72
  if ltype or indent > 0 or continue or code_block_open
77
73
  false
78
74
  else
@@ -85,7 +81,7 @@ class RubyLex
85
81
  @io.dynamic_prompt do |lines|
86
82
  lines << '' if lines.empty?
87
83
  result = []
88
- tokens = self.class.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, context: context)
84
+ tokens = self.class.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, context: @context)
89
85
  code = String.new
90
86
  partial_tokens = []
91
87
  unprocessed_tokens = []
@@ -96,8 +92,9 @@ class RubyLex
96
92
  if t.tok.include?("\n")
97
93
  t_str = t.tok
98
94
  t_str.each_line("\n") do |s|
99
- code << s << "\n"
100
- ltype, indent, continue, code_block_open = check_state(code, partial_tokens, context: context)
95
+ code << s
96
+ next unless s.include?("\n")
97
+ ltype, indent, continue, code_block_open = check_state(code, partial_tokens)
101
98
  result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
102
99
  line_num_offset += 1
103
100
  end
@@ -108,29 +105,22 @@ class RubyLex
108
105
  end
109
106
 
110
107
  unless unprocessed_tokens.empty?
111
- ltype, indent, continue, code_block_open = check_state(code, unprocessed_tokens, context: context)
108
+ ltype, indent, continue, code_block_open = check_state(code, unprocessed_tokens)
112
109
  result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
113
110
  end
114
111
  result
115
112
  end
116
113
  end
117
114
 
118
- if p.respond_to?(:call)
119
- @input = p
120
- elsif block_given?
115
+ if block_given?
121
116
  @input = block
122
117
  else
123
118
  @input = Proc.new{@io.gets}
124
119
  end
125
120
  end
126
121
 
127
- def set_prompt(p = nil, &block)
128
- p = block if block_given?
129
- if p.respond_to?(:call)
130
- @prompt = p
131
- else
132
- @prompt = Proc.new{print p}
133
- end
122
+ def set_prompt(&block)
123
+ @prompt = block
134
124
  end
135
125
 
136
126
  ERROR_TOKENS = [
@@ -158,19 +148,15 @@ class RubyLex
158
148
 
159
149
  compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
160
150
  lexer = Ripper::Lexer.new(inner_code, '-', line_no)
161
- if lexer.respond_to?(:scan) # Ruby 2.7+
162
- lexer.scan.each_with_object([]) do |t, tokens|
163
- next if t.pos.first == 0
164
- prev_tk = tokens.last
165
- position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
166
- if position_overlapped
167
- tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
168
- else
169
- tokens << t
170
- end
151
+ lexer.scan.each_with_object([]) do |t, tokens|
152
+ next if t.pos.first == 0
153
+ prev_tk = tokens.last
154
+ position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
155
+ if position_overlapped
156
+ tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
157
+ else
158
+ tokens << t
171
159
  end
172
- else
173
- lexer.parse.reject { |it| it.pos.first == 0 }.sort_by(&:pos)
174
160
  end
175
161
  end
176
162
  ensure
@@ -188,6 +174,7 @@ class RubyLex
188
174
  if line_count >= line_index
189
175
  return prev_spaces
190
176
  end
177
+ next if t.event == :on_tstring_content || t.event == :on_words_sep
191
178
  if (@tokens.size - 1) > i
192
179
  md = @tokens[i + 1].tok.match(/(\A +)/)
193
180
  prev_spaces = md.nil? ? 0 : md[1].count(' ')
@@ -197,11 +184,11 @@ class RubyLex
197
184
  prev_spaces
198
185
  end
199
186
 
200
- def set_auto_indent(context)
201
- if @io.respond_to?(:auto_indent) and context.auto_indent_mode
187
+ def set_auto_indent
188
+ if @io.respond_to?(:auto_indent) and @context.auto_indent_mode
202
189
  @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
203
190
  if is_newline
204
- @tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"), context: context)
191
+ @tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"), context: @context)
205
192
  prev_spaces = find_prev_spaces(line_index)
206
193
  depth_difference = check_newline_depth_difference
207
194
  depth_difference = 0 if depth_difference < 0
@@ -210,19 +197,18 @@ class RubyLex
210
197
  code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
211
198
  last_line = lines[line_index]&.byteslice(0, byte_pointer)
212
199
  code += last_line if last_line
213
- @tokens = self.class.ripper_lex_without_warning(code, context: context)
200
+ @tokens = self.class.ripper_lex_without_warning(code, context: @context)
214
201
  check_corresponding_token_depth(lines, line_index)
215
202
  end
216
203
  end
217
204
  end
218
205
  end
219
206
 
220
- def check_state(code, tokens = nil, context: nil)
221
- tokens = self.class.ripper_lex_without_warning(code, context: context) unless tokens
207
+ def check_state(code, tokens)
222
208
  ltype = process_literal_type(tokens)
223
209
  indent = process_nesting_level(tokens)
224
210
  continue = process_continue(tokens)
225
- lvars_code = self.class.generate_local_variables_assign_code(context.local_variables)
211
+ lvars_code = self.class.generate_local_variables_assign_code(@context.local_variables)
226
212
  code = "#{lvars_code}\n#{code}" if lvars_code
227
213
  code_block_open = check_code_block(code, tokens)
228
214
  [ltype, indent, continue, code_block_open]
@@ -243,13 +229,13 @@ class RubyLex
243
229
  @code_block_open = false
244
230
  end
245
231
 
246
- def each_top_level_statement(context)
232
+ def each_top_level_statement
247
233
  initialize_input
248
234
  catch(:TERM_INPUT) do
249
235
  loop do
250
236
  begin
251
237
  prompt
252
- unless l = lex(context)
238
+ unless l = lex
253
239
  throw :TERM_INPUT if @line == ''
254
240
  else
255
241
  @line_no += l.count("\n")
@@ -279,19 +265,19 @@ class RubyLex
279
265
  end
280
266
  end
281
267
 
282
- def lex(context)
268
+ def lex
283
269
  line = @input.call
284
270
  if @io.respond_to?(:check_termination)
285
271
  return line # multiline
286
272
  end
287
273
  code = @line + (line.nil? ? '' : line)
288
274
  code.gsub!(/\s*\z/, '').concat("\n")
289
- @tokens = self.class.ripper_lex_without_warning(code, context: context)
290
- @ltype, @indent, @continue, @code_block_open = check_state(code, @tokens, context: context)
275
+ @tokens = self.class.ripper_lex_without_warning(code, context: @context)
276
+ @ltype, @indent, @continue, @code_block_open = check_state(code, @tokens)
291
277
  line
292
278
  end
293
279
 
294
- def process_continue(tokens = @tokens)
280
+ def process_continue(tokens)
295
281
  # last token is always newline
296
282
  if tokens.size >= 2 and tokens[-2].event == :on_regexp_end
297
283
  # end of regexp literal
@@ -312,7 +298,7 @@ class RubyLex
312
298
  false
313
299
  end
314
300
 
315
- def check_code_block(code, tokens = @tokens)
301
+ def check_code_block(code, tokens)
316
302
  return true if tokens.empty?
317
303
  if tokens.last.event == :on_heredoc_beg
318
304
  return true
@@ -404,7 +390,7 @@ class RubyLex
404
390
  false
405
391
  end
406
392
 
407
- def process_nesting_level(tokens = @tokens)
393
+ def process_nesting_level(tokens)
408
394
  indent = 0
409
395
  in_oneliner_def = nil
410
396
  tokens.each_with_index { |t, index|
@@ -642,7 +628,7 @@ class RubyLex
642
628
  end
643
629
 
644
630
  case t.event
645
- when :on_ignored_nl, :on_nl, :on_comment
631
+ when :on_ignored_nl, :on_nl, :on_comment, :on_heredoc_end, :on_embdoc_end
646
632
  if in_oneliner_def != :BODY
647
633
  corresponding_token_depth = nil
648
634
  spaces_at_line_head = 0
@@ -760,7 +746,7 @@ class RubyLex
760
746
  pending_heredocs.first || start_token.last
761
747
  end
762
748
 
763
- def process_literal_type(tokens = @tokens)
749
+ def process_literal_type(tokens)
764
750
  start_token = check_string_literal(tokens)
765
751
  return nil if start_token == ""
766
752
 
@@ -781,20 +767,15 @@ class RubyLex
781
767
  when :on_qsymbols_beg then ?]
782
768
  when :on_symbols_beg then ?]
783
769
  when :on_heredoc_beg
784
- start_token&.tok =~ /<<[-~]?(['"`])[_a-zA-Z0-9]+\1/
785
- case $1
786
- when ?" then ?"
787
- when ?' then ?'
788
- when ?` then ?`
789
- else ?"
790
- end
770
+ start_token&.tok =~ /<<[-~]?(['"`])\w+\1/
771
+ $1 || ?"
791
772
  else
792
773
  nil
793
774
  end
794
775
  end
795
776
 
796
- def check_termination_in_prev_line(code, context: nil)
797
- tokens = self.class.ripper_lex_without_warning(code, context: context)
777
+ def check_termination_in_prev_line(code)
778
+ tokens = self.class.ripper_lex_without_warning(code, context: @context)
798
779
  past_first_newline = false
799
780
  index = tokens.rindex do |t|
800
781
  # traverse first token before last line
data/lib/irb/version.rb CHANGED
@@ -1,17 +1,11 @@
1
1
  # frozen_string_literal: false
2
2
  #
3
3
  # irb/version.rb - irb version definition file
4
- # $Release Version: 0.9.6$
5
- # $Revision$
6
4
  # by Keiju ISHITSUKA(keiju@ishitsuka.com)
7
5
  #
8
- # --
9
- #
10
- #
11
- #
12
6
 
13
7
  module IRB # :nodoc:
14
- VERSION = "1.6.2"
8
+ VERSION = "1.6.4"
15
9
  @RELEASE_VERSION = VERSION
16
- @LAST_UPDATE_DATE = "2022-12-13"
10
+ @LAST_UPDATE_DATE = "2023-04-07"
17
11
  end
data/lib/irb/workspace.rb CHANGED
@@ -1,14 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
  #
3
3
  # irb/workspace-binding.rb -
4
- # $Release Version: 0.9.6$
5
- # $Revision$
6
4
  # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
5
  #
8
- # --
9
- #
10
- #
11
- #
12
6
 
13
7
  require "delegate"
14
8
 
@@ -115,7 +109,7 @@ EOF
115
109
  attr_reader :main
116
110
 
117
111
  # Evaluate the given +statements+ within the context of this workspace.
118
- def evaluate(context, statements, file = __FILE__, line = __LINE__)
112
+ def evaluate(statements, file = __FILE__, line = __LINE__)
119
113
  eval(statements, @binding, file, line)
120
114
  end
121
115
 
@@ -128,6 +122,8 @@ EOF
128
122
  end
129
123
 
130
124
  # error message manipulator
125
+ # WARN: Rails patches this method to filter its own backtrace. Be cautious when changing it.
126
+ # See: https://github.com/rails/rails/blob/main/railties/lib/rails/commands/console/console_command.rb#L8:~:text=def,filter_backtrace
131
127
  def filter_backtrace(bt)
132
128
  return nil if bt =~ /\/irb\/.*\.rb/
133
129
  return nil if bt =~ /\/irb\.rb/
@@ -142,11 +138,7 @@ EOF
142
138
  end
143
139
 
144
140
  def code_around_binding
145
- if @binding.respond_to?(:source_location)
146
- file, pos = @binding.source_location
147
- else
148
- file, pos = @binding.eval('[__FILE__, __LINE__]')
149
- end
141
+ file, pos = @binding.source_location
150
142
 
151
143
  if defined?(::SCRIPT_LINES__[file]) && lines = ::SCRIPT_LINES__[file]
152
144
  code = ::SCRIPT_LINES__[file].join('')
@@ -173,8 +165,5 @@ EOF
173
165
 
174
166
  "\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n"
175
167
  end
176
-
177
- def IRB.delete_caller
178
- end
179
168
  end
180
169
  end
@@ -1,14 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
  #
3
3
  # irb/ws-for-case-2.rb -
4
- # $Release Version: 0.9.6$
5
- # $Revision$
6
4
  # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
5
  #
8
- # --
9
- #
10
- #
11
- #
12
6
 
13
7
  while true
14
8
  IRB::BINDING_QUEUE.push _ = binding
data/lib/irb/xmp.rb CHANGED
@@ -1,14 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
  #
3
3
  # xmp.rb - irb version of gotoken xmp
4
- # $Release Version: 0.9$
5
- # $Revision$
6
4
  # by Keiju ISHITSUKA(Nippon Rational Inc.)
7
5
  #
8
- # --
9
- #
10
- #
11
- #
12
6
 
13
7
  require_relative "../irb"
14
8
  require_relative "frame"
data/lib/irb.rb CHANGED
@@ -1,14 +1,9 @@
1
1
  # frozen_string_literal: false
2
2
  #
3
3
  # irb.rb - irb main module
4
- # $Release Version: 0.9.6 $
5
- # $Revision$
6
4
  # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
5
  #
8
- # --
9
- #
10
- #
11
- #
6
+
12
7
  require "ripper"
13
8
  require "reline"
14
9
 
@@ -421,11 +416,6 @@ module IRB
421
416
  irb.run(@CONF)
422
417
  end
423
418
 
424
- # Calls each event hook of <code>IRB.conf[:AT_EXIT]</code> when the current session quits.
425
- def IRB.irb_at_exit
426
- @CONF[:AT_EXIT].each{|hook| hook.call}
427
- end
428
-
429
419
  # Quits irb
430
420
  def IRB.irb_exit(irb, ret)
431
421
  throw :IRB_EXIT, ret
@@ -468,12 +458,16 @@ module IRB
468
458
  # be parsed as :assign and echo will be suppressed, but the latter is
469
459
  # parsed as a :method_add_arg and the output won't be suppressed
470
460
 
461
+ PROMPT_MAIN_TRUNCATE_LENGTH = 32
462
+ PROMPT_MAIN_TRUNCATE_OMISSION = '...'.freeze
463
+ CONTROL_CHARACTERS_PATTERN = "\x00-\x1F".freeze
464
+
471
465
  # Creates a new irb session
472
466
  def initialize(workspace = nil, input_method = nil)
473
467
  @context = Context.new(self, workspace, input_method)
474
468
  @context.main.extend ExtendCommandBundle
475
469
  @signal_status = :IN_IRB
476
- @scanner = RubyLex.new
470
+ @scanner = RubyLex.new(@context)
477
471
  end
478
472
 
479
473
  # A hook point for `debug` command's TracePoint after :IRB_EXIT as well as its clean-up
@@ -543,7 +537,7 @@ module IRB
543
537
  @context.io.prompt
544
538
  end
545
539
 
546
- @scanner.set_input(@context.io, context: @context) do
540
+ @scanner.set_input(@context.io) do
547
541
  signal_status(:IN_INPUT) do
548
542
  if l = @context.io.gets
549
543
  print l if @context.verbose?
@@ -561,12 +555,11 @@ module IRB
561
555
  end
562
556
  end
563
557
 
564
- @scanner.set_auto_indent(@context) if @context.auto_indent_mode
558
+ @scanner.set_auto_indent
565
559
 
566
- @scanner.each_top_level_statement(@context) do |line, line_no|
560
+ @scanner.each_top_level_statement do |line, line_no|
567
561
  signal_status(:IN_EVAL) do
568
562
  begin
569
- line.untaint if RUBY_VERSION < '2.7'
570
563
  if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
571
564
  IRB.set_measure_callback
572
565
  end
@@ -780,6 +773,15 @@ module IRB
780
773
  end
781
774
  end
782
775
 
776
+ def truncate_prompt_main(str) # :nodoc:
777
+ str = str.tr(CONTROL_CHARACTERS_PATTERN, ' ')
778
+ if str.size <= PROMPT_MAIN_TRUNCATE_LENGTH
779
+ str
780
+ else
781
+ str[0, PROMPT_MAIN_TRUNCATE_LENGTH - PROMPT_MAIN_TRUNCATE_OMISSION.size] + PROMPT_MAIN_TRUNCATE_OMISSION
782
+ end
783
+ end
784
+
783
785
  def prompt(prompt, ltype, indent, line_no) # :nodoc:
784
786
  p = prompt.dup
785
787
  p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
@@ -787,9 +789,9 @@ module IRB
787
789
  when "N"
788
790
  @context.irb_name
789
791
  when "m"
790
- @context.main.to_s
792
+ truncate_prompt_main(@context.main.to_s)
791
793
  when "M"
792
- @context.main.inspect
794
+ truncate_prompt_main(@context.main.inspect)
793
795
  when "l"
794
796
  ltype
795
797
  when "i"
@@ -889,11 +891,6 @@ module IRB
889
891
  ensure
890
892
  $VERBOSE = verbose
891
893
  end
892
-
893
- ATTR_TTY = "\e[%sm"
894
- def ATTR_TTY.[](*a) self % a.join(";"); end
895
- ATTR_PLAIN = ""
896
- def ATTR_PLAIN.[](*) self; end
897
894
  end
898
895
 
899
896
  def @CONF.inspect
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.6.2
4
+ version: 1.6.4
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-20 00:00:00.000000000 Z
12
+ date: 2023-04-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: reline
@@ -110,7 +110,11 @@ homepage: https://github.com/ruby/irb
110
110
  licenses:
111
111
  - Ruby
112
112
  - BSD-2-Clause
113
- metadata: {}
113
+ metadata:
114
+ homepage_uri: https://github.com/ruby/irb
115
+ source_code_uri: https://github.com/ruby/irb
116
+ documentation_uri: https://github.com/ruby/irb
117
+ changelog_uri: https://github.com/ruby/irb/releases
114
118
  post_install_message:
115
119
  rdoc_options: []
116
120
  require_paths:
@@ -119,14 +123,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
123
  requirements:
120
124
  - - ">="
121
125
  - !ruby/object:Gem::Version
122
- version: '2.6'
126
+ version: '2.7'
123
127
  required_rubygems_version: !ruby/object:Gem::Requirement
124
128
  requirements:
125
129
  - - ">="
126
130
  - !ruby/object:Gem::Version
127
131
  version: '0'
128
132
  requirements: []
129
- rubygems_version: 3.3.7
133
+ rubygems_version: 3.4.8
130
134
  signing_key:
131
135
  specification_version: 4
132
136
  summary: Interactive Ruby command-line tool for REPL (Read Eval Print Loop).