class RuboCop::Cop::Lint::ImplicitStringConcatenation

Checks for implicit string concatenation of string literals which are on the same line.

@example

# bad
array = ['Item 1' 'Item 2']

# good
array = ['Item 1Item 2']
array = ['Item 1' + 'Item 2']
array = [
  'Item 1' \
  'Item 2'
]

Constants

FOR_ARRAY
FOR_METHOD
MSG

Public Instance Methods

on_dstr(node) click to toggle source

rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity

# File lib/rubocop/cop/lint/implicit_string_concatenation.rb, line 32
def on_dstr(node)
  each_bad_cons(node) do |lhs_node, rhs_node|
    range = lhs_node.source_range.join(rhs_node.source_range)
    message = format(MSG, lhs: display_str(lhs_node), rhs: display_str(rhs_node))
    if node.parent&.array_type?
      message << FOR_ARRAY
    elsif node.parent&.send_type?
      message << FOR_METHOD
    end

    add_offense(range, message: message) do |corrector|
      if lhs_node.value == ''
        corrector.remove(lhs_node)
      elsif rhs_node.value == ''
        corrector.remove(rhs_node)
      else
        range = lhs_node.source_range.end.join(rhs_node.source_range.begin)

        corrector.replace(range, ' + ')
      end
    end
  end
end

Private Instance Methods

display_str(node) click to toggle source
# File lib/rubocop/cop/lint/implicit_string_concatenation.rb, line 92
def display_str(node)
  if node.source.include?("\n")
    str_content(node).inspect
  else
    node.source
  end
end
each_bad_cons(node) { |child_node1, child_node2| ... } click to toggle source

rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity

# File lib/rubocop/cop/lint/implicit_string_concatenation.rb, line 59
def each_bad_cons(node)
  node.children.each_cons(2) do |child_node1, child_node2|
    # `'abc' 'def'` -> (dstr (str "abc") (str "def"))
    next unless string_literals?(child_node1, child_node2)
    next unless child_node1.last_line == child_node2.first_line

    # Make sure we don't flag a string literal which simply has
    # embedded newlines
    # `"abc\ndef"` also -> (dstr (str "abc") (str "def"))
    next unless child_node1.source[-1] == ending_delimiter(child_node1)

    yield child_node1, child_node2
  end
end
ending_delimiter(str) click to toggle source
# File lib/rubocop/cop/lint/implicit_string_concatenation.rb, line 74
def ending_delimiter(str)
  # implicit string concatenation does not work with %{}, etc.
  case str.source[0]
  when "'"
    "'"
  when '"'
    '"'
  end
end
str_content(node) click to toggle source
# File lib/rubocop/cop/lint/implicit_string_concatenation.rb, line 100
def str_content(node)
  return unless node.respond_to?(:str_type?)

  if node.str_type?
    node.children[0]
  else
    node.children.map { |c| str_content(c) }.join
  end
end
string_literal?(node) click to toggle source
# File lib/rubocop/cop/lint/implicit_string_concatenation.rb, line 84
def string_literal?(node)
  node.str_type? || node.dstr_type?
end
string_literals?(node1, node2) click to toggle source
# File lib/rubocop/cop/lint/implicit_string_concatenation.rb, line 88
def string_literals?(node1, node2)
  string_literal?(node1) && string_literal?(node2)
end