irb 1.3.0 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: