irb 1.3.0 → 1.3.5

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.
@@ -126,7 +126,23 @@ module IRB # :nodoc:
126
126
  ],
127
127
 
128
128
  [
129
- :measure, :Measure, "irb/cmd/measure"
129
+ :irb_ls, :Ls, "irb/cmd/ls",
130
+ [:ls, NO_OVERRIDE],
131
+ ],
132
+
133
+ [
134
+ :irb_measure, :Measure, "irb/cmd/measure",
135
+ [:measure, NO_OVERRIDE],
136
+ ],
137
+
138
+ [
139
+ :irb_show_source, :ShowSource, "irb/cmd/show_source",
140
+ [:show_source, NO_OVERRIDE],
141
+ ],
142
+
143
+ [
144
+ :irb_whereami, :Whereami, "irb/cmd/whereami",
145
+ [:whereami, NO_OVERRIDE],
130
146
  ],
131
147
 
132
148
  ]
@@ -168,12 +184,13 @@ module IRB # :nodoc:
168
184
  end
169
185
 
170
186
  if load_file
187
+ kwargs = ", **kwargs" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
171
188
  line = __LINE__; eval %[
172
- def #{cmd_name}(*opts, &b)
189
+ def #{cmd_name}(*opts#{kwargs}, &b)
173
190
  require "#{load_file}"
174
191
  arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity
175
192
  args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s }
176
- args << "*opts" if arity < 0
193
+ args << "*opts#{kwargs}" if arity < 0
177
194
  args << "&block"
178
195
  args = args.join(", ")
179
196
  line = __LINE__; eval %[
@@ -184,7 +201,7 @@ module IRB # :nodoc:
184
201
  end
185
202
  end
186
203
  ], nil, __FILE__, line
187
- __send__ :#{cmd_name}_, *opts, &b
204
+ __send__ :#{cmd_name}_, *opts#{kwargs}, &b
188
205
  end
189
206
  ], nil, __FILE__, line
190
207
  else
data/lib/irb/init.rb CHANGED
@@ -146,7 +146,7 @@ module IRB # :nodoc:
146
146
  @CONF[:AT_EXIT] = []
147
147
  end
148
148
 
149
- def IRB.set_measure_callback(type = nil, arg = nil)
149
+ def IRB.set_measure_callback(type = nil, arg = nil, &block)
150
150
  added = nil
151
151
  if type
152
152
  type_sym = type.upcase.to_sym
@@ -155,6 +155,16 @@ module IRB # :nodoc:
155
155
  end
156
156
  elsif IRB.conf[:MEASURE_PROC][:CUSTOM]
157
157
  added = [:CUSTOM, IRB.conf[:MEASURE_PROC][:CUSTOM], arg]
158
+ elsif block_given?
159
+ added = [:BLOCK, block, arg]
160
+ found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] }
161
+ if found
162
+ found[1] = block
163
+ return added
164
+ else
165
+ IRB.conf[:MEASURE_CALLBACKS] << added
166
+ return added
167
+ end
158
168
  else
159
169
  added = [:TIME, IRB.conf[:MEASURE_PROC][:TIME], arg]
160
170
  end
@@ -124,10 +124,22 @@ module IRB
124
124
 
125
125
  # Use a File for IO with irb, see InputMethod
126
126
  class FileInputMethod < InputMethod
127
+ class << self
128
+ def open(file, &block)
129
+ begin
130
+ io = new(file)
131
+ block.call(io)
132
+ ensure
133
+ io&.close
134
+ end
135
+ end
136
+ end
137
+
127
138
  # Creates a new input method object
128
139
  def initialize(file)
129
140
  super
130
141
  @io = IRB::MagicFile.open(file)
142
+ @external_encoding = @io.external_encoding
131
143
  end
132
144
  # The file name of this input method, usually given during initialization.
133
145
  attr_reader :file_name
@@ -137,7 +149,7 @@ module IRB
137
149
  #
138
150
  # See IO#eof? for more information.
139
151
  def eof?
140
- @io.eof?
152
+ @io.closed? || @io.eof?
141
153
  end
142
154
 
143
155
  # Reads the next line from this input method.
@@ -150,13 +162,17 @@ module IRB
150
162
 
151
163
  # The external encoding for standard input.
152
164
  def encoding
153
- @io.external_encoding
165
+ @external_encoding
154
166
  end
155
167
 
156
168
  # For debug message
157
169
  def inspect
158
170
  'FileInputMethod'
159
171
  end
172
+
173
+ def close
174
+ @io.close
175
+ end
160
176
  end
161
177
 
162
178
  begin
@@ -264,6 +280,7 @@ module IRB
264
280
  Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
265
281
  end
266
282
  Reline.completion_append_character = nil
283
+ Reline.completer_quote_characters = ''
267
284
  Reline.completion_proc = IRB::InputCompletor::CompletionProc
268
285
  Reline.output_modifier_proc =
269
286
  if IRB.conf[:USE_COLORIZE]
data/lib/irb/inspector.rb CHANGED
@@ -100,29 +100,27 @@ module IRB # :nodoc:
100
100
  # Proc to call when the input is evaluated and output in irb.
101
101
  def inspect_value(v)
102
102
  @inspect.call(v)
103
+ rescue
104
+ puts "(Object doesn't support #inspect)"
105
+ ''
103
106
  end
104
107
  end
105
108
 
106
109
  Inspector.def_inspector([false, :to_s, :raw]){|v| v.to_s}
107
- Inspector.def_inspector([true, :p, :inspect]){|v|
108
- begin
109
- result = v.inspect
110
- if IRB.conf[:MAIN_CONTEXT]&.use_colorize? && Color.inspect_colorable?(v)
111
- result = Color.colorize_code(result)
112
- end
113
- result
114
- rescue NoMethodError
115
- puts "(Object doesn't support #inspect)"
116
- ''
117
- end
118
- }
119
- Inspector.def_inspector([:pp, :pretty_inspect], proc{require "pp"}){|v|
120
- result = v.pretty_inspect.chomp
110
+ Inspector.def_inspector([:p, :inspect]){|v|
111
+ result = v.inspect
121
112
  if IRB.conf[:MAIN_CONTEXT]&.use_colorize? && Color.inspect_colorable?(v)
122
113
  result = Color.colorize_code(result)
123
114
  end
124
115
  result
125
116
  }
117
+ Inspector.def_inspector([true, :pp, :pretty_inspect], proc{require "irb/color_printer"}){|v|
118
+ if IRB.conf[:MAIN_CONTEXT]&.use_colorize?
119
+ IRB::ColorPrinter.pp(v, '').chomp
120
+ else
121
+ v.pretty_inspect.chomp
122
+ end
123
+ }
126
124
  Inspector.def_inspector([:yaml, :YAML], proc{require "yaml"}){|v|
127
125
  begin
128
126
  YAML.dump(v)
@@ -10,7 +10,7 @@
10
10
  #
11
11
  #
12
12
  Usage: irb.rb [options] [programfile] [arguments]
13
- -f Suppress read of ~/.irbrc
13
+ -f Suppress read of ~/.irbrc
14
14
  -d Set $DEBUG to true (same as `ruby -d')
15
15
  -r load-module Same as `ruby -r'
16
16
  -I path Specify $LOAD_PATH directory
@@ -18,7 +18,7 @@ Usage: irb.rb [options] [programfile] [arguments]
18
18
  -E enc Same as `ruby -E`
19
19
  -w Same as `ruby -w`
20
20
  -W[level=2] Same as `ruby -W`
21
- --context-mode n Set n[0-3] to method to create Binding Object,
21
+ --context-mode n Set n[0-4] to method to create Binding Object,
22
22
  when new workspace was created
23
23
  --echo Show result(default)
24
24
  --noecho Don't show result
@@ -31,8 +31,8 @@ Usage: irb.rb [options] [programfile] [arguments]
31
31
  --colorize Use colorization
32
32
  --nocolorize Don't use colorization
33
33
  --prompt prompt-mode/--prompt-mode prompt-mode
34
- Switch prompt mode. Pre-defined prompt modes are
35
- `default', `simple', `xmp' and `inf-ruby'
34
+ Switch prompt mode. Pre-defined prompt modes are
35
+ `default', `simple', `xmp' and `inf-ruby'
36
36
  --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs.
37
37
  Suppresses --multiline and --singleline.
38
38
  --sample-book-mode/--simple-prompt
@@ -41,8 +41,8 @@ Usage: irb.rb [options] [programfile] [arguments]
41
41
  --single-irb Share self with sub-irb.
42
42
  --tracer Display trace for each execution of commands.
43
43
  --back-trace-limit n
44
- Display backtrace top n and tail n. The default
45
- value is 16.
44
+ Display backtrace top n and tail n. The default
45
+ value is 16.
46
46
  --verbose Show details
47
47
  --noverbose Don't show details
48
48
  -v, --version Print the version of irb
data/lib/irb/ruby-lex.rb CHANGED
@@ -47,12 +47,26 @@ class RubyLex
47
47
  @io = io
48
48
  if @io.respond_to?(:check_termination)
49
49
  @io.check_termination do |code|
50
- code.gsub!(/\s*\z/, '').concat("\n")
51
- ltype, indent, continue, code_block_open = check_state(code)
52
- if ltype or indent > 0 or continue or code_block_open
53
- false
50
+ if Reline::IOGate.in_pasting?
51
+ lex = RubyLex.new
52
+ rest = lex.check_termination_in_prev_line(code)
53
+ if rest
54
+ Reline.delete_text
55
+ rest.bytes.reverse_each do |c|
56
+ Reline.ungetc(c)
57
+ end
58
+ true
59
+ else
60
+ false
61
+ end
54
62
  else
55
- true
63
+ code.gsub!(/\s*\z/, '').concat("\n")
64
+ ltype, indent, continue, code_block_open = check_state(code)
65
+ if ltype or indent > 0 or continue or code_block_open
66
+ false
67
+ else
68
+ true
69
+ end
56
70
  end
57
71
  end
58
72
  end
@@ -60,7 +74,7 @@ class RubyLex
60
74
  @io.dynamic_prompt do |lines|
61
75
  lines << '' if lines.empty?
62
76
  result = []
63
- tokens = ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join)
77
+ tokens = self.class.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join)
64
78
  code = String.new
65
79
  partial_tokens = []
66
80
  unprocessed_tokens = []
@@ -106,30 +120,78 @@ class RubyLex
106
120
  end
107
121
  end
108
122
 
109
- def ripper_lex_without_warning(code)
123
+ ERROR_TOKENS = [
124
+ :on_parse_error,
125
+ :compile_error,
126
+ :on_assign_error,
127
+ :on_alias_error,
128
+ :on_class_name_error,
129
+ :on_param_error
130
+ ]
131
+
132
+ def self.ripper_lex_without_warning(code)
110
133
  verbose, $VERBOSE = $VERBOSE, nil
111
134
  tokens = nil
112
- self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
113
- tokens = Ripper.lex(inner_code, '-', line_no)
135
+ compile_with_errors_suppressed(code) do |inner_code, line_no|
136
+ lexer = Ripper::Lexer.new(inner_code, '-', line_no)
137
+ if lexer.respond_to?(:scan) # Ruby 2.7+
138
+ tokens = []
139
+ pos_to_index = {}
140
+ lexer.scan.each do |t|
141
+ if pos_to_index.has_key?(t[0])
142
+ index = pos_to_index[t[0]]
143
+ found_tk = tokens[index]
144
+ if ERROR_TOKENS.include?(found_tk[1]) && !ERROR_TOKENS.include?(t[1])
145
+ tokens[index] = t
146
+ end
147
+ else
148
+ pos_to_index[t[0]] = tokens.size
149
+ tokens << t
150
+ end
151
+ end
152
+ else
153
+ tokens = lexer.parse
154
+ end
114
155
  end
115
- $VERBOSE = verbose
116
156
  tokens
157
+ ensure
158
+ $VERBOSE = verbose
159
+ end
160
+
161
+ def find_prev_spaces(line_index)
162
+ return 0 if @tokens.size == 0
163
+ md = @tokens[0][2].match(/(\A +)/)
164
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
165
+ line_count = 0
166
+ @tokens.each_with_index do |t, i|
167
+ if t[2].include?("\n")
168
+ line_count += t[2].count("\n")
169
+ if line_count >= line_index
170
+ return prev_spaces
171
+ end
172
+ if (@tokens.size - 1) > i
173
+ md = @tokens[i + 1][2].match(/(\A +)/)
174
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
175
+ end
176
+ end
177
+ end
178
+ prev_spaces
117
179
  end
118
180
 
119
181
  def set_auto_indent(context)
120
182
  if @io.respond_to?(:auto_indent) and context.auto_indent_mode
121
183
  @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
122
184
  if is_newline
123
- md = lines[line_index - 1].match(/(\A +)/)
124
- prev_spaces = md.nil? ? 0 : md[1].count(' ')
125
- @tokens = ripper_lex_without_warning(lines[0..line_index].join("\n"))
185
+ @tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"))
186
+ prev_spaces = find_prev_spaces(line_index)
126
187
  depth_difference = check_newline_depth_difference
188
+ depth_difference = 0 if depth_difference < 0
127
189
  prev_spaces + depth_difference * 2
128
190
  else
129
191
  code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
130
192
  last_line = lines[line_index]&.byteslice(0, byte_pointer)
131
193
  code += last_line if last_line
132
- @tokens = ripper_lex_without_warning(code)
194
+ @tokens = self.class.ripper_lex_without_warning(code)
133
195
  corresponding_token_depth = check_corresponding_token_depth
134
196
  if corresponding_token_depth
135
197
  corresponding_token_depth
@@ -142,7 +204,7 @@ class RubyLex
142
204
  end
143
205
 
144
206
  def check_state(code, tokens = nil)
145
- tokens = ripper_lex_without_warning(code) unless tokens
207
+ tokens = self.class.ripper_lex_without_warning(code) unless tokens
146
208
  ltype = process_literal_type(tokens)
147
209
  indent = process_nesting_level(tokens)
148
210
  continue = process_continue(tokens)
@@ -175,7 +237,10 @@ class RubyLex
175
237
  throw :TERM_INPUT if @line == ''
176
238
  else
177
239
  @line_no += l.count("\n")
178
- next if l == "\n"
240
+ if l == "\n"
241
+ @exp_line_no += 1
242
+ next
243
+ end
179
244
  @line.concat l
180
245
  if @code_block_open or @ltype or @continue or @indent > 0
181
246
  next
@@ -185,7 +250,7 @@ class RubyLex
185
250
  @line.force_encoding(@io.encoding)
186
251
  yield @line, @exp_line_no
187
252
  end
188
- break if @io.eof?
253
+ raise TerminateLineInput if @io.eof?
189
254
  @line = ''
190
255
  @exp_line_no = @line_no
191
256
 
@@ -205,7 +270,7 @@ class RubyLex
205
270
  end
206
271
  code = @line + (line.nil? ? '' : line)
207
272
  code.gsub!(/\s*\z/, '').concat("\n")
208
- @tokens = ripper_lex_without_warning(code)
273
+ @tokens = self.class.ripper_lex_without_warning(code)
209
274
  @continue = process_continue
210
275
  @code_block_open = check_code_block(code)
211
276
  @indent = process_nesting_level
@@ -226,8 +291,9 @@ class RubyLex
226
291
  return true
227
292
  elsif tokens.size >= 1 and tokens[-1][1] == :on_heredoc_end # "EOH\n"
228
293
  return false
229
- elsif tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME)
294
+ elsif tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME) and tokens[-2][2] !~ /\A\.\.\.?\z/
230
295
  # end of literal except for regexp
296
+ # endless range at end of line is not a continue
231
297
  return true
232
298
  end
233
299
  false
@@ -360,14 +426,8 @@ class RubyLex
360
426
  next if index > 0 and tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
361
427
  case t[2]
362
428
  when 'do'
363
- if index > 0 and tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG)
364
- # method_with_block do; end
365
- indent += 1
366
- else
367
- # while cond do; end # also "until" or "for"
368
- # This "do" doesn't increment indent because "while" already
369
- # incremented.
370
- end
429
+ syntax_of_do = take_corresponding_syntax_to_kw_do(tokens, index)
430
+ indent += 1 if syntax_of_do == :method_calling
371
431
  when 'def', 'case', 'for', 'begin', 'class', 'module'
372
432
  indent += 1
373
433
  when 'if', 'unless', 'while', 'until'
@@ -382,6 +442,83 @@ class RubyLex
382
442
  indent
383
443
  end
384
444
 
445
+ def is_method_calling?(tokens, index)
446
+ tk = tokens[index]
447
+ if tk[3].anybits?(Ripper::EXPR_CMDARG) and tk[1] == :on_ident
448
+ # The target method call to pass the block with "do".
449
+ return true
450
+ elsif tk[3].anybits?(Ripper::EXPR_ARG) and tk[1] == :on_ident
451
+ non_sp_index = tokens[0..(index - 1)].rindex{ |t| t[1] != :on_sp }
452
+ if non_sp_index
453
+ prev_tk = tokens[non_sp_index]
454
+ if prev_tk[3].anybits?(Ripper::EXPR_DOT) and prev_tk[1] == :on_period
455
+ # The target method call with receiver to pass the block with "do".
456
+ return true
457
+ end
458
+ end
459
+ end
460
+ false
461
+ end
462
+
463
+ def take_corresponding_syntax_to_kw_do(tokens, index)
464
+ syntax_of_do = nil
465
+ # Finding a syntax correnponding to "do".
466
+ index.downto(0) do |i|
467
+ tk = tokens[i]
468
+ # In "continue", the token isn't the corresponding syntax to "do".
469
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t[1] != :on_sp }
470
+ first_in_fomula = false
471
+ if non_sp_index.nil?
472
+ first_in_fomula = true
473
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index][1])
474
+ first_in_fomula = true
475
+ end
476
+ if is_method_calling?(tokens, i)
477
+ syntax_of_do = :method_calling
478
+ break if first_in_fomula
479
+ elsif tk[1] == :on_kw && %w{while until for}.include?(tk[2])
480
+ # A loop syntax in front of "do" found.
481
+ #
482
+ # while cond do # also "until" or "for"
483
+ # end
484
+ #
485
+ # This "do" doesn't increment indent because the loop syntax already
486
+ # incremented.
487
+ syntax_of_do = :loop_syntax
488
+ break if first_in_fomula
489
+ end
490
+ end
491
+ syntax_of_do
492
+ end
493
+
494
+ def is_the_in_correspond_to_a_for(tokens, index)
495
+ syntax_of_in = nil
496
+ # Finding a syntax correnponding to "do".
497
+ index.downto(0) do |i|
498
+ tk = tokens[i]
499
+ # In "continue", the token isn't the corresponding syntax to "do".
500
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t[1] != :on_sp }
501
+ first_in_fomula = false
502
+ if non_sp_index.nil?
503
+ first_in_fomula = true
504
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index][1])
505
+ first_in_fomula = true
506
+ end
507
+ if tk[1] == :on_kw && tk[2] == 'for'
508
+ # A loop syntax in front of "do" found.
509
+ #
510
+ # while cond do # also "until" or "for"
511
+ # end
512
+ #
513
+ # This "do" doesn't increment indent because the loop syntax already
514
+ # incremented.
515
+ syntax_of_in = :for
516
+ end
517
+ break if first_in_fomula
518
+ end
519
+ syntax_of_in
520
+ end
521
+
385
522
  def check_newline_depth_difference
386
523
  depth_difference = 0
387
524
  open_brace_on_line = 0
@@ -410,7 +547,7 @@ class RubyLex
410
547
 
411
548
  case t[1]
412
549
  when :on_ignored_nl, :on_nl, :on_comment
413
- if index != (@tokens.size - 1)
550
+ if index != (@tokens.size - 1) and in_oneliner_def != :BODY
414
551
  depth_difference = 0
415
552
  open_brace_on_line = 0
416
553
  end
@@ -428,14 +565,8 @@ class RubyLex
428
565
  next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
429
566
  case t[2]
430
567
  when 'do'
431
- if index > 0 and @tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG)
432
- # method_with_block do; end
433
- depth_difference += 1
434
- else
435
- # while cond do; end # also "until" or "for"
436
- # This "do" doesn't increment indent because "while" already
437
- # incremented.
438
- end
568
+ syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
569
+ depth_difference += 1 if syntax_of_do == :method_calling
439
570
  when 'def', 'case', 'for', 'begin', 'class', 'module'
440
571
  depth_difference += 1
441
572
  when 'if', 'unless', 'while', 'until', 'rescue'
@@ -443,8 +574,14 @@ class RubyLex
443
574
  unless t[3].allbits?(Ripper::EXPR_LABEL)
444
575
  depth_difference += 1
445
576
  end
446
- when 'else', 'elsif', 'ensure', 'when', 'in'
577
+ when 'else', 'elsif', 'ensure', 'when'
447
578
  depth_difference += 1
579
+ when 'in'
580
+ unless is_the_in_correspond_to_a_for(@tokens, index)
581
+ depth_difference += 1
582
+ end
583
+ when 'end'
584
+ depth_difference -= 1
448
585
  end
449
586
  end
450
587
  end
@@ -488,11 +625,13 @@ class RubyLex
488
625
 
489
626
  case t[1]
490
627
  when :on_ignored_nl, :on_nl, :on_comment
491
- corresponding_token_depth = nil
492
- spaces_at_line_head = 0
493
- is_first_spaces_of_line = true
494
- is_first_printable_of_line = true
495
- open_brace_on_line = 0
628
+ if in_oneliner_def != :BODY
629
+ corresponding_token_depth = nil
630
+ spaces_at_line_head = 0
631
+ is_first_spaces_of_line = true
632
+ is_first_printable_of_line = true
633
+ open_brace_on_line = 0
634
+ end
496
635
  next
497
636
  when :on_sp
498
637
  spaces_at_line_head = t[2].count(' ') if is_first_spaces_of_line
@@ -514,7 +653,12 @@ class RubyLex
514
653
  when :on_kw
515
654
  next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
516
655
  case t[2]
517
- when 'def', 'do', 'case', 'for', 'begin', 'class', 'module'
656
+ when 'do'
657
+ syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
658
+ if syntax_of_do == :method_calling
659
+ spaces_of_nest.push(spaces_at_line_head)
660
+ end
661
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
518
662
  spaces_of_nest.push(spaces_at_line_head)
519
663
  when 'rescue'
520
664
  unless t[3].allbits?(Ripper::EXPR_LABEL)
@@ -609,5 +753,50 @@ class RubyLex
609
753
  nil
610
754
  end
611
755
  end
756
+
757
+ def check_termination_in_prev_line(code)
758
+ tokens = self.class.ripper_lex_without_warning(code)
759
+ past_first_newline = false
760
+ index = tokens.rindex do |t|
761
+ # traverse first token before last line
762
+ if past_first_newline
763
+ if t.tok.include?("\n")
764
+ true
765
+ end
766
+ elsif t.tok.include?("\n")
767
+ past_first_newline = true
768
+ false
769
+ else
770
+ false
771
+ end
772
+ end
773
+ if index
774
+ first_token = nil
775
+ last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
776
+ last_line_tokens.each do |t|
777
+ unless [:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
778
+ first_token = t
779
+ break
780
+ end
781
+ end
782
+ if first_token.nil?
783
+ return false
784
+ elsif first_token && first_token.state == Ripper::EXPR_DOT
785
+ return false
786
+ else
787
+ tokens_without_last_line = tokens[0..index]
788
+ ltype = process_literal_type(tokens_without_last_line)
789
+ indent = process_nesting_level(tokens_without_last_line)
790
+ continue = process_continue(tokens_without_last_line)
791
+ code_block_open = check_code_block(tokens_without_last_line.map(&:tok).join(''), tokens_without_last_line)
792
+ if ltype or indent > 0 or continue or code_block_open
793
+ return false
794
+ else
795
+ return last_line_tokens.map(&:tok).join('')
796
+ end
797
+ end
798
+ end
799
+ false
800
+ end
612
801
  end
613
802
  # :startdoc: