Class: RuboCop::Cop::Performance::RegexpMatch
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
TargetRubyVersion,
AutoCorrector,
Base
|
|
Instance Chain:
self,
Base
|
|
Inherits: |
Base
|
Defined in: | lib/rubocop/cop/performance/regexp_match.rb |
Overview
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
.
Constant Summary
-
MATCH_NODE_PATTERN =
# File 'lib/rubocop/cop/performance/regexp_match.rb', line 112<<~PATTERN { #match_method? #match_with_int_arg_method? #match_operator? #match_threequals? #match_with_lvasgn? } PATTERN
-
MSG =
# File 'lib/rubocop/cop/performance/regexp_match.rb', line 84'Use `match?` instead of `%<current>s` when `MatchData` is not used.'
-
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%i[const regexp str sym].freeze
Class Method Summary
Instance Method Summary
- #match_with_lvasgn?(node) ⇒ Boolean
- #on_case(node)
- #on_if(node)
- #autocorrect(corrector, node) private
- #check_condition(cond) private
- #correct_operator(corrector, recv, arg, oper = nil) private
- #find_last_match(body, range, scope_root) private
- #last_match_used?(match_node) ⇒ Boolean private
- #match_gvar?(sym) ⇒ Boolean private
- #message(node) private
- #modifier_form?(match_node) ⇒ Boolean private
- #next_match_pos(body, match_node_pos, scope_root) private
- #range_to_search_for_last_matches(match_node, body, scope_root) private
- #replace_with_match_predicate_method(corrector, recv, arg, op_range) private
- #scope_body(node) private
- #scope_root(node) private
- #swap_receiver_and_arg(corrector, recv, arg) private
Class Method Details
.autocorrect_incompatible_with
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 134
def self.autocorrect_incompatible_with [ConstantRegexp] end
Instance Method Details
#autocorrect(corrector, node) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 165
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) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 154
def check_condition(cond) match_node?(cond) do return if last_match_used?(cond) = (cond) add_offense(cond, message: ) do |corrector| autocorrect(corrector, cond) end end end
#correct_operator(corrector, recv, arg, oper = nil) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 250
def correct_operator(corrector, recv, arg, oper = nil) op_range = recv.source_range.end.join(arg.source_range.begin) replace_with_match_predicate_method(corrector, recv, arg, op_range) corrector.insert_after(arg, ')') unless op_range.source.end_with?('(') corrector.insert_before(recv, '!') if oper == :!~ end
#find_last_match(body, range, scope_root) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 221
def find_last_match(body, range, scope_root) last_matches(body).find do |ref| ref_pos = ref.source_range.begin_pos range.cover?(ref_pos) && scope_root(ref) == scope_root end end
#last_match_used?(match_node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/performance/regexp_match.rb', line 181
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) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/performance/regexp_match.rb', line 246
def match_gvar?(sym) %i[$~ $MATCH $PREMATCH $POSTMATCH $LAST_PAREN_MATCH $LAST_MATCH_INFO].include?(sym) end
#match_with_lvasgn?(node) ⇒ Boolean
# File 'lib/rubocop/cop/performance/regexp_match.rb', line 105
def match_with_lvasgn?(node) return false unless node.match_with_lvasgn_type? regexp, _rhs = *node regexp.to_regexp.named_captures.empty? end
#message(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 177
def (node) format(MSG, current: node.loc.selector.source) end
#modifier_form?(match_node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/performance/regexp_match.rb', line 217
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) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 203
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.source_range.begin_pos else match.source_range.begin_pos end begin_pos > match_node_pos && scope_root(match) == scope_root end node ? node.source_range.begin_pos : Float::INFINITY end
#on_case(node)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 142
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)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 138
def on_if(node) check_condition(node.condition) end
#range_to_search_for_last_matches(match_node, body, scope_root) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 190
def range_to_search_for_last_matches(match_node, body, scope_root) expression = if modifier_form?(match_node) match_node.parent.if_branch.source_range else match_node.source_range 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) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 259
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) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 228
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) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 240
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) (private)
[ GitHub ]# File 'lib/rubocop/cop/performance/regexp_match.rb', line 270
def swap_receiver_and_arg(corrector, recv, arg) corrector.replace(recv, arg.source) corrector.replace(arg, recv.source) end