class RuboCop::Cop::Lint::ArrayLiteralInRegexp


/#{[foo, bar]}/
# bad - construct a regexp rather than interpolate an array of identifiers
/(?:foo|bar|baz)/
# good
/#{%w[foo bar baz]}/
# bad<br><br>//
# good
/#{%w[a b c]}/
# bad
@example
removing the additional quotes, spaces and commas from the character class.
Autocorrection is unsafe because it will change the regexp pattern, by
@safety
or regexp alternation.
integers, and floats. Any other type is not easily convertible to a character class
NOTE: This only considers interpolated arrays that contain only strings, symbols,
single character) or alternation (if the array contains longer items).
The cop can autocorrect to a character class (if all items in the array are a
repeated characters).
‘/#{%w[a b c]}/` parses as `/[“a”, “b”, “c”]/` (or `/[“a, bc]/` without
quotes, spaces and commas that are likely not intended. For example,
that when inside a regexp, it acts as a character class but with additional
When interpolating an array literal, it is converted to a string. This means
Checks for an array literal interpolated inside a regexp.

def alternation_for(values)

def alternation_for(values)
  "(?:#{escape_values(values).join('|')})"
end

def array_of_literal_values?(node)

def array_of_literal_values?(node)
  node.each_value.all? { |value| value.type?(*LITERAL_TYPES) }
end

def array_values(node)

def array_values(node)
  node.each_value.map do |value|
    value.respond_to?(:value) ? value.value : value.source
  end
end

def character_class?(values)

def character_class?(values)
  values.all? { |v| v.to_s.length == 1 }
end

def character_class_for(values)

def character_class_for(values)
  "[#{escape_values(values).join}]"
end

def escape_values(values)

def escape_values(values)
  # This may add extraneous escape characters, but they can be cleaned up
  # by `Style/RedundantRegexpEscape`.
  values.map { |value| Regexp.escape(value.to_s) }
end

def on_interpolation(begin_node)

def on_interpolation(begin_node)
  return unless (final_node = begin_node.children.last)
  return unless final_node.array_type?
  return unless begin_node.parent.regexp_type?
  if array_of_literal_values?(final_node)
    register_array_of_literal_values(begin_node, final_node)
  else
    register_array_of_nonliteral_values(begin_node)
  end
end

def register_array_of_literal_values(begin_node, node)

def register_array_of_literal_values(begin_node, node)
  array_values = array_values(node)
  if character_class?(array_values)
    message = MSG_CHARACTER_CLASS
    replacement = character_class_for(array_values)
  else
    message = MSG_ALTERNATION
    replacement = alternation_for(array_values)
  end
  add_offense(begin_node, message: message) do |corrector|
    corrector.replace(begin_node, replacement)
  end
end

def register_array_of_nonliteral_values(node)

def register_array_of_nonliteral_values(node)
  # Add offense but do not correct if the array contains any nonliteral values.
  add_offense(node, message: MSG_UNKNOWN)
end