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 !~ /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.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
- TYPES_IMPLEMENTING_MATCH
Constants are included in this list because it is unlikely that someone will store `nil` as a constant and then use it for comparison
Public Instance Methods
match_with_lvasgn?(node)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 102 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 135 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 131 def on_if(node) check_condition(node.condition) end
Private Instance Methods
autocorrect(corrector, node)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 158 def autocorrect(corrector, node) if match_method?(node) || match_with_int_arg_method?(node) corrector.replace(node.loc.selector, 'match?') elsif match_operator?(node) || match_threequals?(node) recv, oper, arg = *node correct_operator(corrector, recv, arg, oper) elsif match_with_lvasgn?(node) recv, arg = *node correct_operator(corrector, recv, arg) end end
check_condition(cond)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 147 def check_condition(cond) match_node?(cond) do return if last_match_used?(cond) message = message(cond) add_offense(cond, message: message) do |corrector| autocorrect(corrector, cond) end end end
correct_operator(corrector, recv, arg, oper = nil)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 251 def correct_operator(corrector, recv, arg, oper = nil) op_range = correction_range(recv, arg) replace_with_match_predicate_method(corrector, recv, arg, op_range) corrector.insert_after(arg.loc.expression, ')') unless op_range.source.end_with?('(') corrector.insert_before(recv.loc.expression, '!') if oper == :!~ end
correction_range(recv, arg)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 276 def correction_range(recv, arg) buffer = processed_source.buffer op_begin_pos = recv.loc.expression.end_pos op_end_pos = arg.loc.expression.begin_pos Parser::Source::Range.new(buffer, op_begin_pos, op_end_pos) end
find_last_match(body, range, scope_root)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 214 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 174 def last_match_used?(match_node) scope_root = scope_root(match_node) body = scope_root ? scope_body(scope_root) : match_node.ancestors.last range = range_to_search_for_last_matches(match_node, body, scope_root) find_last_match(body, range, scope_root) end
match_gvar?(sym)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 240 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 170 def message(node) format(MSG, current: node.loc.selector.source) end
modifier_form?(match_node)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 210 def modifier_form?(match_node) match_node.parent.if_type? && match_node.parent.modifier_form? end
next_match_pos(body, match_node_pos, scope_root)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 196 def next_match_pos(body, match_node_pos, scope_root) node = search_match_nodes(body).find do |match| begin_pos = if modifier_form?(match) match.parent.if_branch.loc.expression.begin_pos else match.loc.expression.begin_pos end begin_pos > match_node_pos && scope_root(match) == scope_root end node ? node.loc.expression.begin_pos : Float::INFINITY end
range_to_search_for_last_matches(match_node, body, scope_root)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 183 def range_to_search_for_last_matches(match_node, body, scope_root) expression = if modifier_form?(match_node) match_node.parent.if_branch.loc.expression else match_node.loc.expression end match_node_pos = expression.begin_pos next_match_pos = next_match_pos(body, match_node_pos, scope_root) match_node_pos..next_match_pos end
replace_with_match_predicate_method(corrector, recv, arg, op_range)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 260 def replace_with_match_predicate_method(corrector, recv, arg, op_range) if TYPES_IMPLEMENTING_MATCH.include?(recv.type) corrector.replace(op_range, '.match?(') elsif TYPES_IMPLEMENTING_MATCH.include?(arg.type) corrector.replace(op_range, '.match?(') swap_receiver_and_arg(corrector, recv, arg) else corrector.replace(op_range, '&.match?(') end end
scope_body(node)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 222 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 234 def scope_root(node) node.each_ancestor.find do |ancestor| ancestor.def_type? || ancestor.defs_type? || ancestor.class_type? || ancestor.module_type? end end
swap_receiver_and_arg(corrector, recv, arg)
click to toggle source
# File lib/rubocop/cop/performance/regexp_match.rb, line 271 def swap_receiver_and_arg(corrector, recv, arg) corrector.replace(recv.loc.expression, arg.source) corrector.replace(arg.loc.expression, recv.source) end