-
-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new
Performance/ConstantRegexp
cop
- Loading branch information
Showing
10 changed files
with
172 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Performance | ||
# This cop finds regular expressions whose all dynamic components are 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 | ||
# 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 | ||
# | ||
class ConstantRegexp < Base | ||
extend AutoCorrector | ||
|
||
MSG = 'Extract this regexp into a constant or append an `/o` option to its options.' | ||
|
||
def on_regexp(node) | ||
return if within_const_assignment?(node) || | ||
!const_regexp?(node) || | ||
node.single_interpolation? | ||
|
||
add_offense(node) do |corrector| | ||
corrector.replace(node, "#{node.source}o") | ||
end | ||
end | ||
|
||
private | ||
|
||
def within_const_assignment?(node) | ||
node.each_ancestor(:casgn).any? | ||
end | ||
|
||
def const_regexp?(node) | ||
return false unless node.interpolation? | ||
|
||
node.each_child_node(:begin).all? do |begin_node| | ||
inner_node = begin_node.children.first | ||
inner_node&.const_type? | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::Performance::ConstantRegexp do | ||
subject(:cop) { described_class.new } | ||
|
||
it 'registers an offense and corrects when regexp contains interpolated constant' do | ||
expect_offense(<<~RUBY) | ||
str.match?(/\A\#{CONST}/) | ||
^^^^^^^^^^^ Extract this regexp into a constant or append an `/o` option to its options. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
str.match?(/\A\#{CONST}/o) | ||
RUBY | ||
end | ||
|
||
it 'registers an offense and corrects when regexp contains multiple interpolated constants' do | ||
expect_offense(<<~RUBY) | ||
str.match?(/\A\#{CONST1}something\#{CONST2}\z/) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Extract this regexp into a constant or append an `/o` option to its options. | ||
RUBY | ||
|
||
expect_correction(<<~RUBY) | ||
str.match?(/\A\#{CONST1}something\#{CONST2}\z/o) | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when regexp does not contain interpolated constant' do | ||
expect_no_offenses(<<~RUBY) | ||
str.match?(/foo/) | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when regexp is within assignment to a constant' do | ||
expect_no_offenses(<<~RUBY) | ||
CONST = str.match?(/\#{ANOTHER_CONST}/) | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when regexp has `/o` option' do | ||
expect_no_offenses(<<~RUBY) | ||
str.match?(/\#{CONST}/o) | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense when regexp contains interpolated constant and '\ | ||
'and interpolated non constant' do | ||
expect_no_offenses(<<~RUBY) | ||
str.match?(/\#{CONST}\#{do_something(1)}/) | ||
RUBY | ||
end | ||
end |