class RuboCop::Cop::Performance::RegexpMatch

In Ruby 2.4, `String#match?`, `Regexp#match?` and `Symbol#match?` have been added. The methods are faster than `match`. Because the methods avoid creating a `MatchData` object or saving backref. So, when `MatchData` is not used, use `match?` instead of `match`.

@example

# bad
def foo
  if x =~ /re/
    do_something
  end
end

# bad
def foo
  if x.match(/re/)
    do_something
  end
end

# bad
def foo
  if /re/ === x
    do_something
  end
end

# good
def foo
  if x.match?(/re/)
    do_something
  end
end

# good
def foo
  if x =~ /re/
    do_something(Regexp.last_match)
  end
end

# good
def foo
  if x.match(/re/)
    do_something($~)
  end
end

# good
def foo
  if /re/ === x
    do_something($~)
  end
end

Constants

MATCH_NODE_PATTERN
MSG

Public Instance Methods

autocorrect(node) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 124
def autocorrect(node)
  lambda do |corrector|
    if match_method?(node)
      corrector.replace(node.loc.selector, 'match?')
    elsif match_operator?(node) || match_threequals?(node)
      recv, _, arg = *node
      correct_operator(corrector, recv, arg)
    elsif match_with_lvasgn?(node)
      recv, arg = *node
      correct_operator(corrector, recv, arg)
    end
  end
end
match_with_lvasgn?(node) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 83
def match_with_lvasgn?(node)
  return false unless node.match_with_lvasgn_type?
  regexp, _rhs = *node
  regexp.to_regexp.named_captures.empty?
end
on_case(node) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 114
def on_case(node)
  return if node.condition

  node.each_when do |when_node|
    when_node.each_condition do |condition|
      check_condition(condition)
    end
  end
end
on_if(node) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 110
def on_if(node)
  check_condition(node.condition)
end

Private Instance Methods

check_condition(cond) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 140
def check_condition(cond)
  match_node?(cond) do
    return if last_match_used?(cond)

    add_offense(cond)
  end
end
correct_operator(corrector, recv, arg) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 211
def correct_operator(corrector, recv, arg)
  buffer = processed_source.buffer
  op_begin_pos = recv.loc.expression.end_pos
  op_end_pos = arg.loc.expression.begin_pos
  op_range = Parser::Source::Range.new(buffer, op_begin_pos, op_end_pos)
  corrector.replace(op_range, '.match?(')
  corrector.insert_after(arg.loc.expression, ')')
end
find_last_match(body, range, scope_root) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 171
def find_last_match(body, range, scope_root)
  last_matches(body).find do |ref|
    ref_pos = ref.loc.expression.begin_pos
    range.cover?(ref_pos) &&
      scope_root(ref) == scope_root
  end
end
last_match_used?(match_node) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 152
def last_match_used?(match_node)
  scope_root = scope_root(match_node)
  body = scope_root ? scope_body(scope_root) : match_node.ancestors.last
  match_node_pos = match_node.loc.expression.begin_pos

  next_match_pos = next_match_pos(body, match_node_pos, scope_root)
  range = match_node_pos..next_match_pos

  find_last_match(body, range, scope_root)
end
match_gvar?(sym) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 200
def match_gvar?(sym)
  %i[
    $~
    $MATCH
    $PREMATCH
    $POSTMATCH
    $LAST_PAREN_MATCH
    $LAST_MATCH_INFO
  ].include?(sym)
end
message(node) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 148
def message(node)
  format(MSG, node.loc.selector.source)
end
next_match_pos(body, match_node_pos, scope_root) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 163
def next_match_pos(body, match_node_pos, scope_root)
  node = search_match_nodes(body).find do |match|
    match.loc.expression.begin_pos > match_node_pos &&
      scope_root(match) == scope_root
  end
  node ? node.loc.expression.begin_pos : Float::INFINITY
end
scope_body(node) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 179
def scope_body(node)
  children = node.children
  case node.type
  when :module
    children[1]
  when :defs
    children[3]
  else
    children[2]
  end
end
scope_root(node) click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 191
def scope_root(node)
  node.each_ancestor.find do |ancestor|
    ancestor.def_type? ||
      ancestor.defs_type? ||
      ancestor.class_type? ||
      ancestor.module_type?
  end
end