class RuboCop::Cop::Performance::ConstantRegexp

This cop finds regular expressions with dynamic components that are all constants.

Ruby allocates a new Regexp object every time it executes a code containing such a regular expression. It is more efficient to extract it into a constant, memoize it, or add an `/o` option to perform `#{}` interpolation only once and reuse that Regexp object.

@example

# bad
def tokens(pattern)
  pattern.scan(TOKEN).reject { |token| token.match?(/\A#{SEPARATORS}\Z/) }
end

# good
ALL_SEPARATORS = /\A#{SEPARATORS}\Z/
def tokens(pattern)
  pattern.scan(TOKEN).reject { |token| token.match?(ALL_SEPARATORS) }
end

# good
def tokens(pattern)
  pattern.scan(TOKEN).reject { |token| token.match?(/\A#{SEPARATORS}\Z/o) }
end

# good
def separators
  @separators ||= /\A#{SEPARATORS}\Z/
end

Constants

MSG

Public Instance Methods

on_regexp(node) click to toggle source
# File lib/rubocop/cop/performance/constant_regexp.rb, line 41
def on_regexp(node)
  return if within_allowed_assignment?(node) ||
            !include_interpolated_const?(node) ||
            node.single_interpolation?

  add_offense(node) do |corrector|
    corrector.insert_after(node, 'o')
  end
end

Private Instance Methods

include_interpolated_const?(node) click to toggle source
# File lib/rubocop/cop/performance/constant_regexp.rb, line 62
def include_interpolated_const?(node)
  return false unless node.interpolation?

  node.each_child_node(:begin).all? do |begin_node|
    inner_node = begin_node.children.first
    inner_node && (inner_node.const_type? || regexp_escape?(inner_node))
  end
end
within_allowed_assignment?(node) click to toggle source
# File lib/rubocop/cop/performance/constant_regexp.rb, line 53
def within_allowed_assignment?(node)
  node.each_ancestor(:casgn, :or_asgn).any?
end