class RuboCop::Cop::Performance::RegexpMatch
end
end
do_something($~)
if /re/ === x
def foo
# good
end
end
do_something($~)
if x.match(/re/)
def foo
# good
end
end
do_something(Regexp.last_match)
if x =~ /re/
def foo
# good
end
end
do_something
if x.match?(/re/)
def foo
# good
end
end
do_something
if /re/ === x
def foo
# bad
end
end
do_something
if x.match(/re/)
def foo
# bad
end
end
do_something
if x =~ /re/
def foo
# bad
@example
So, when ‘MatchData` is not used, use `match?` instead of `match`.
backref.
Because the methods avoid creating a `MatchData` object or saving
have been added. The methods are faster than `match`.
In Ruby 2.4, `String#match?`, `Regexp#match?` and `Symbol#match?`
def autocorrect(node)
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
def check_condition(cond)
def check_condition(cond) match_node?(cond) do return if last_match_used?(cond) add_offense(cond) end end
def correct_operator(corrector, recv, arg)
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
def find_last_match(body, range, scope_root)
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
def last_match_used?(match_node)
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
def match_gvar?(sym)
def match_gvar?(sym) %i[ $~ $MATCH $PREMATCH $POSTMATCH $LAST_PAREN_MATCH $LAST_MATCH_INFO ].include?(sym) end
def match_with_lvasgn?(node)
def match_with_lvasgn?(node) return false unless node.match_with_lvasgn_type? regexp, _rhs = *node regexp.to_regexp.named_captures.empty? end
def message(node)
def message(node) format(MSG, node.loc.selector.source) end
def next_match_pos(body, match_node_pos, scope_root)
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
def on_case(node)
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
def on_if(node)
def on_if(node) check_condition(node.condition) end
def scope_body(node)
def scope_body(node) children = node.children case node.type when :module children[1] when :defs children[3] else children[2] end end
def scope_root(node)
def scope_root(node) node.each_ancestor.find do |ancestor| ancestor.def_type? || ancestor.defs_type? || ancestor.class_type? || ancestor.module_type? end end