class RuboCop::Cop::Layout::LineContinuationSpacing

Checks that the backslash of a line continuation is separated from preceding text by exactly one space (default) or zero spaces.

@example EnforcedStyle: space (default)

# bad
'a'\
'b'  \
'c'

# good
'a' \
'b' \
'c'

@example EnforcedStyle: no_space

# bad
'a' \
'b'  \
'c'

# good
'a'\
'b'\
'c'

Public Instance Methods

on_new_investigation() click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 34
def on_new_investigation
  last_line = last_line(processed_source)

  @ignored_ranges = string_literal_ranges(processed_source.ast) +
                    comment_ranges(processed_source.comments)

  processed_source.raw_source.lines.each_with_index do |line, index|
    break if index >= last_line

    line_number = index + 1
    investigate(line, line_number)
  end
end

Private Instance Methods

autocorrect(corrector, range) click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 82
def autocorrect(corrector, range)
  correction = if no_space_style?
                 '\\'
               elsif space_style?
                 ' \\'
               end
  corrector.replace(range, correction)
end
comment_ranges(comments) click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 106
def comment_ranges(comments)
  comments.map(&:loc).map(&:expression)
end
find_offensive_spacing(line) click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 66
def find_offensive_spacing(line)
  if no_space_style?
    line[/\s+\\$/, 0]
  elsif space_style?
    line[/((?<!\s)|\s{2,})\\$/, 0]
  end
end
ignore_range?(backtick_range) click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 116
def ignore_range?(backtick_range)
  @ignored_ranges.any? { |range| range.contains?(backtick_range) }
end
investigate(line, line_number) click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 50
def investigate(line, line_number)
  offensive_spacing = find_offensive_spacing(line)
  return unless offensive_spacing

  range = source_range(
    processed_source.buffer,
    line_number,
    line.length - offensive_spacing.length - 1,
    offensive_spacing.length
  )

  return if ignore_range?(range)

  add_offense(range) { |corrector| autocorrect(corrector, range) }
end
last_line(processed_source) click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 110
def last_line(processed_source)
  last_token = processed_source.tokens.last

  last_token ? last_token.line : processed_source.lines.length
end
message(_range) click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 74
def message(_range)
  if no_space_style?
    'Use zero spaces in front of backslash.'
  elsif space_style?
    'Use one space in front of backslash.'
  end
end
no_space_style?() click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 120
def no_space_style?
  cop_config['EnforcedStyle'] == 'no_space'
end
space_style?() click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 124
def space_style?
  cop_config['EnforcedStyle'] == 'space'
end
string_literal_ranges(ast) click to toggle source
# File lib/rubocop/cop/layout/line_continuation_spacing.rb, line 91
def string_literal_ranges(ast)
  # which lines start inside a string literal?
  return [] if ast.nil?

  ast.each_node(:str, :dstr).each_with_object(Set.new) do |str, ranges|
    loc = str.location

    if str.heredoc?
      ranges << loc.heredoc_body
    elsif loc.respond_to?(:begin) && loc.begin
      ranges << loc.expression
    end
  end
end