Performance
Performance/AncestorsInclude
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Yes (Unsafe) |
1.7 |
- |
Identifies usages of ancestors.include?
and change them to use ⇐
instead.
Performance/ArraySemiInfiniteRangeSlice
Required Ruby version: 2.7 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
No |
Yes (Unsafe) |
1.9 |
- |
Identifies places where slicing arrays with semi-infinite ranges
can be replaced by Array#take
and Array#drop
.
This cop was created due to a mistake in microbenchmark and hence is disabled by default.
Refer https://github.com/rubocop/rubocop-performance/pull/175#issuecomment-731892717
Performance/BigDecimalWithNumericArgument
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes |
1.7 |
- |
Identifies places where numeric argument to BigDecimal should be converted to string. Initializing from String is faster than from Numeric for BigDecimal.
Performance/BindCall
Required Ruby version: 2.7 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
1.6 |
- |
In Ruby 2.7, UnboundMethod#bind_call
has been added.
This cop identifies places where bind(obj).call(args, …)
can be replaced by bind_call(obj, args, …)
.
The bind_call(obj, args, …)
method is faster than
bind(obj).call(args, …)
.
Performance/BlockGivenWithExplicitBlock
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes |
1.9 |
- |
Identifies unnecessary use of a block_given?
where explicit check
of block argument would suffice.
Performance/Caller
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.49 |
1.9 |
Identifies places where caller[n]
can be replaced by caller(n..n).first
.
Performance/CaseWhenSplat
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
Yes (Unsafe) |
0.34 |
1.13 |
Reordering when
conditions with a splat to the end
of the when
branches can improve performance.
Ruby has to allocate memory for the splat expansion every time
that the case
when
statement is run. Since Ruby does not support
fall through inside of case
when
, like some other languages do,
the order of the when
branches should not matter. By placing any
splat expansions at the end of the list of when
branches we will
reduce the number of times that memory has to be allocated for
the expansion. The exception to this is if multiple of your when
conditions can be true for any given condition. A likely scenario for
this defining a higher level when condition to override a condition
that is inside of the splat expansion.
Safety
This cop is not unsafe autocorrection because it is not a guaranteed
performance improvement. If the data being processed by the case
condition is
normalized in a manner that favors hitting a condition in the splat expansion,
it is possible that moving the splat condition to the end will use more memory,
and run slightly slower.
See for more details: https://github.com/rubocop/rubocop/pull/6163
Performance/Casecmp
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Yes (Unsafe) |
0.36 |
- |
Identifies places where a case-insensitive string comparison
can better be implemented using casecmp
.
Safety
This cop is unsafe because String#casecmp
and String#casecmp?
behave
differently when using Non-ASCII characters.
Performance/ChainArrayAllocation
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
0.59 |
- |
Identifies usages of array.compact.flatten.map { |x| x.downcase }
.
Each of these methods (compact
, flatten
, map
) will generate a new intermediate array
that is promptly thrown away. Instead it is faster to mutate when we know it’s safe.
Performance/CollectionLiteralInLoop
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
1.8 |
- |
Identifies places where Array and Hash literals are used within loops. It is better to extract them into a local variable or constant to avoid unnecessary allocations on each iteration.
You can set the minimum number of elements to consider
an offense with MinSize
.
Performance/CompareWithBlock
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.46 |
- |
Identifies places where sort { |a, b| a.foo <⇒ b.foo }
can be replaced by sort_by(&:foo)
.
This cop also checks max
and min
methods.
Examples
# bad
array.sort { |a, b| a.foo <=> b.foo }
array.max { |a, b| a.foo <=> b.foo }
array.min { |a, b| a.foo <=> b.foo }
array.sort { |a, b| a[:foo] <=> b[:foo] }
# good
array.sort_by(&:foo)
array.sort_by { |v| v.foo }
array.sort_by do |var|
var.foo
end
array.max_by(&:foo)
array.min_by(&:foo)
array.sort_by { |a| a[:foo] }
Performance/ConcurrentMonotonicTime
Performance/ConstantRegexp
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes |
1.9 |
1.10 |
Finds regular expressions with dynamic components that are all 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,
memoize it, or add an /o
option to perform #{}
interpolation only once and
reuse that Regexp object.
Examples
# 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
# good
def separators
@separators ||= /\A#{SEPARATORS}\Z/
end
Performance/Count
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes (Unsafe) |
0.31 |
1.8 |
Identifies usages of count
on an Enumerable
that
follow calls to select
, find_all
, filter
or reject
. Querying logic can instead be
passed to the count
call.
Safety
This cop is unsafe because it has known compatibility issues with ActiveRecord
and other
frameworks. ActiveRecord’s count
ignores the block that is passed to it.
ActiveRecord
will ignore the block that is passed to count
.
Other methods, such as select
, will convert the association to an
array and then run the block on the array. A simple work around to
make count
work with a block is to call to_a.count {…}
.
For example:
`Model.where(id: [1, 2, 3]).select { |m| m.method == true }.size`
becomes:
`Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }`
Examples
# bad
[1, 2, 3].select { |e| e > 2 }.size
[1, 2, 3].reject { |e| e > 2 }.size
[1, 2, 3].select { |e| e > 2 }.length
[1, 2, 3].reject { |e| e > 2 }.length
[1, 2, 3].select { |e| e > 2 }.count { |e| e.odd? }
[1, 2, 3].reject { |e| e > 2 }.count { |e| e.even? }
array.select(&:value).count
# good
[1, 2, 3].count { |e| e > 2 }
[1, 2, 3].count { |e| e < 2 }
[1, 2, 3].count { |e| e > 2 && e.odd? }
[1, 2, 3].count { |e| e < 2 && e.even? }
Model.select('field AS field_one').count
Model.select(:value).count
Performance/DeletePrefix
Required Ruby version: 2.5 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Yes (Unsafe) |
1.6 |
1.11 |
In Ruby 2.5, String#delete_prefix
has been added.
This cop identifies places where gsub(/\Aprefix/, '')
and sub(/\Aprefix/, '')
can be replaced by delete_prefix('prefix')
.
This cop has SafeMultiline
configuration option that true
by default because
^prefix
is unsafe as it will behave incompatible with delete_prefix
for receiver is multiline string.
The delete_prefix('prefix')
method is faster than gsub(/\Aprefix/, '')
.
Examples
# bad
str.gsub(/\Aprefix/, '')
str.gsub!(/\Aprefix/, '')
str.sub(/\Aprefix/, '')
str.sub!(/\Aprefix/, '')
# good
str.delete_prefix('prefix')
str.delete_prefix!('prefix')
Performance/DeleteSuffix
Required Ruby version: 2.5 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Yes (Unsafe) |
1.6 |
1.11 |
In Ruby 2.5, String#delete_suffix
has been added.
This cop identifies places where gsub(/suffix\z/, '')
and sub(/suffix\z/, '')
can be replaced by delete_suffix('suffix')
.
This cop has SafeMultiline
configuration option that true
by default because
suffix$
is unsafe as it will behave incompatible with delete_suffix?
for receiver is multiline string.
The delete_suffix('suffix')
method is faster than gsub(/suffix\z/, '')
.
Examples
# bad
str.gsub(/suffix\z/, '')
str.gsub!(/suffix\z/, '')
str.sub(/suffix\z/, '')
str.sub!(/suffix\z/, '')
# good
str.delete_suffix('suffix')
str.delete_suffix!('suffix')
Performance/Detect
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes (Unsafe) |
0.30 |
1.8 |
Identifies usages of first
, last
, [0]
or [-1]
chained to select
, find_all
or filter
and change them to use
detect
instead.
Safety
This cop is unsafe because it assumes that the receiver is an
Array
or equivalent, but can’t reliably detect it. For example,
if the receiver is a Hash
, it may report a false positive.
Examples
# bad
[].select { |item| true }.first
[].select { |item| true }.last
[].find_all { |item| true }.first
[].find_all { |item| true }.last
[].filter { |item| true }.first
[].filter { |item| true }.last
[].filter { |item| true }[0]
[].filter { |item| true }[-1]
# good
[].detect { |item| true }
[].reverse.detect { |item| true }
Performance/DoubleStartEndWith
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.36 |
0.48 |
Checks for double #start_with?
or #end_with?
calls
separated by ||
. In some cases such calls can be replaced
with an single #start_with?
/#end_with?
call.
IncludeActiveSupportAliases
configuration option is used to check for
starts_with?
and ends_with?
. These methods are defined by Active Support.
Examples
# bad
str.start_with?("a") || str.start_with?(Some::CONST)
str.start_with?("a", "b") || str.start_with?("c")
str.end_with?(var1) || str.end_with?(var2)
# good
str.start_with?("a", Some::CONST)
str.start_with?("a", "b", "c")
str.end_with?(var1, var2)
Performance/EndWith
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes (Unsafe) |
0.36 |
1.10 |
Identifies unnecessary use of a regex where String#end_with?
would suffice.
This cop has SafeMultiline
configuration option that true
by default because
end$
is unsafe as it will behave incompatible with end_with?
for receiver is multiline string.
Safety
This will change to a new method call which isn’t guaranteed to be on the object. Switching these methods has to be done with knowledge of the types of the variables which rubocop doesn’t have.
Examples
# bad
'abc'.match?(/bc\Z/)
/bc\Z/.match?('abc')
'abc' =~ /bc\Z/
/bc\Z/ =~ 'abc'
'abc'.match(/bc\Z/)
/bc\Z/.match('abc')
# good
'abc'.end_with?('bc')
Performance/FixedSize
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
No |
0.35 |
- |
Do not compute the size of statically sized objects.
Examples
# String methods
# bad
'foo'.size
%q[bar].count
%(qux).length
# Symbol methods
# bad
:fred.size
:'baz'.length
# Array methods
# bad
[1, 2, thud].count
%W(1, 2, bar).size
# Hash methods
# bad
{ a: corge, b: grault }.length
# good
foo.size
bar.count
qux.length
# good
:"#{fred}".size
CONST = :baz.length
# good
[1, 2, *thud].count
garply = [1, 2, 3]
garply.size
# good
{ a: corge, **grault }.length
waldo = { a: corge, b: grault }
waldo.size
Performance/FlatMap
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.30 |
- |
Identifies usages of map { … }.flatten
and
change them to use flat_map { … }
instead.
Examples
# bad
[1, 2, 3, 4].map { |e| [e, e] }.flatten(1)
[1, 2, 3, 4].collect { |e| [e, e] }.flatten(1)
# good
[1, 2, 3, 4].flat_map { |e| [e, e] }
[1, 2, 3, 4].map { |e| [e, e] }.flatten
[1, 2, 3, 4].collect { |e| [e, e] }.flatten
Performance/InefficientHashSearch
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Yes (Unsafe) |
0.56 |
- |
Checks for inefficient searching of keys and values within hashes.
Hash#keys.include?
is less efficient than Hash#key?
because
the former allocates a new array and then performs an O(n) search
through that array, while Hash#key?
does not allocate any array and
performs a faster O(1) search for the key.
Hash#values.include?
is less efficient than Hash#value?
. While they
both perform an O(n) search through all of the values, calling values
allocates a new array while using value?
does not.
Examples
# bad
{ a: 1, b: 2 }.keys.include?(:a)
{ a: 1, b: 2 }.keys.include?(:z)
h = { a: 1, b: 2 }; h.keys.include?(100)
# good
{ a: 1, b: 2 }.key?(:a)
{ a: 1, b: 2 }.has_key?(:z)
h = { a: 1, b: 2 }; h.key?(100)
# bad
{ a: 1, b: 2 }.values.include?(2)
{ a: 1, b: 2 }.values.include?('garbage')
h = { a: 1, b: 2 }; h.values.include?(nil)
# good
{ a: 1, b: 2 }.value?(2)
{ a: 1, b: 2 }.has_value?('garbage')
h = { a: 1, b: 2 }; h.value?(nil)
Performance/IoReadlines
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
Yes |
1.7 |
- |
Identifies places where inefficient readlines
method
can be replaced by each_line
to avoid fully loading file content into memory.
Examples
# bad
File.readlines('testfile').each { |l| puts l }
IO.readlines('testfile', chomp: true).each { |l| puts l }
conn.readlines(10).map { |l| l.size }
file.readlines.find { |l| l.start_with?('#') }
file.readlines.each { |l| puts l }
# good
File.open('testfile', 'r').each_line { |l| puts l }
IO.open('testfile').each_line(chomp: true) { |l| puts l }
conn.each_line(10).map { |l| l.size }
file.each_line.find { |l| l.start_with?('#') }
file.each_line { |l| puts l }
Performance/MapCompact
Required Ruby version: 2.7 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes (Unsafe) |
1.11 |
- |
In Ruby 2.7, Enumerable#filter_map
has been added.
This cop identifies places where map { … }.compact
can be replaced by filter_map
.
[true, false, nil].compact #=> [true, false]
[true, false, nil].filter_map(&:itself) #=> [true]
Performance/MethodObjectAsBlock
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
No |
1.9 |
- |
Identifies places where methods are converted to blocks, with the
use of &method
, and passed as arguments to method calls.
It is faster to replace those with explicit blocks, calling those methods inside.
Performance/OpenStruct
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
No |
No |
0.61 |
- |
Checks for OpenStruct.new
calls.
Instantiation of an OpenStruct
invalidates
Ruby global method cache as it causes dynamic method
definition during program runtime.
This could have an effect on performance,
especially in case of single-threaded
applications with multiple OpenStruct
instantiations.
Performance/RangeInclude
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Yes (Unsafe) |
0.36 |
1.7 |
Identifies uses of Range#include?
and Range#member?
, which iterates over each
item in a Range
to see if a specified item is there. In contrast,
Range#cover?
simply compares the target item with the beginning and
end points of the Range
. In a great majority of cases, this is what
is wanted.
Safety
This cop is unsafe because Range#include?
(or Range#member?
) and Range#cover?
are not equivalent behavior.
Performance/RedundantBlockCall
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.36 |
- |
Identifies the use of a &block
parameter and block.call
where yield
would do just as well.
Performance/RedundantEqualityComparisonBlock
Required Ruby version: 2.5 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
No |
Yes (Unsafe) |
1.10 |
- |
Checks for uses Enumerable#all?
, Enumerable#any?
, Enumerable#one?
,
and Enumerable#none?
are compared with ===
or similar methods in block.
By default, Object#===
behaves the same as Object#==
, but this
behavior is appropriately overridden in subclass. For example,
Range#===
returns true
when argument is within the range.
This cop has AllowRegexpMatch
option and it is true by default because
regexp.match?('string')
often used in block changes to the opposite result:
[/pattern/].all? { |regexp| regexp.match?('pattern') } # => true
[/pattern/].all? { |regexp| regexp =~ 'pattern' } # => true
[/pattern/].all?('pattern') # => false
Examples
# bad
items.all? { |item| pattern === item }
items.all? { |item| item == other }
items.all? { |item| item.is_a?(Klass) }
items.all? { |item| item.kind_of?(Klass) }
# good
items.all?(pattern)
items.all?(Klass)
Performance/RedundantMatch
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.36 |
- |
Identifies the use of Regexp#match
or String#match
, which
returns #<MatchData>
/nil
. The return value of =~
is an integral
index/nil
and is more performant.
Performance/RedundantMerge
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
No |
Yes (Unsafe) |
0.36 |
1.11 |
Identifies places where Hash#merge!
can be replaced by Hash#[]=
.
You can set the maximum number of key-value pairs to consider
an offense with MaxKeyValuePairs
.
Safety
This cop is unsafe because RuboCop cannot determine if the
receiver of merge!
is actually a hash or not.
Performance/RedundantStringChars
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes |
1.7 |
- |
Checks for redundant String#chars
.
Examples
# bad
str.chars[0..2]
str.chars.slice(0..2)
str.chars.last
# good
str[0..2].chars
# bad
str.chars.first
str.chars.first(2)
# good
str[0]
str[0...2].chars
str[-1]
# bad
str.chars.take(2)
str.chars.length
str.chars.size
str.chars.empty?
# good
str[0...2].chars
str.length
str.size
str.empty?
# For example, if the receiver is an empty string, it will be incompatible.
# If a negative value is specified for the receiver, `nil` is returned.
str.chars.last(2) # Incompatible with `str[-2..-1].chars`.
str.chars.drop(2) # Incompatible with `str[2..-1].chars`.
Performance/RegexpMatch
Required Ruby version: 2.4 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.47 |
- |
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
.
Examples
# 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
Performance/ReverseEach
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.30 |
- |
Identifies usages of reverse.each
and change them to use reverse_each
instead.
If the return value is used, it will not be detected because the result will be different.
[1, 2, 3].reverse.each {} #=> [3, 2, 1]
[1, 2, 3].reverse_each {} #=> [1, 2, 3]
Performance/ReverseFirst
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes |
1.7 |
- |
Identifies places where reverse.first(n)
and reverse.first
can be replaced by last(n).reverse
and last
.
Performance/SelectMap
Required Ruby version: 2.7 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Disabled |
Yes |
No |
1.11 |
- |
In Ruby 2.7, Enumerable#filter_map
has been added.
This cop identifies places where select.map
can be replaced by filter_map
.
Performance/Size
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.30 |
- |
Identifies usages of count
on an Array
and Hash
and change them to size
.
TODO: Add advanced detection of variables that could have been assigned to an array or a hash.
Examples
# bad
[1, 2, 3].count
(1..3).to_a.count
Array[*1..3].count
Array(1..3).count
# bad
{a: 1, b: 2, c: 3}.count
[[:foo, :bar], [1, 2]].to_h.count
Hash[*('a'..'z')].count
Hash(key: :value).count
# good
[1, 2, 3].size
(1..3).to_a.size
Array[*1..3].size
Array(1..3).size
# good
{a: 1, b: 2, c: 3}.size
[[:foo, :bar], [1, 2]].to_h.size
Hash[*('a'..'z')].size
Hash(key: :value).size
# good
[1, 2, 3].count { |e| e > 2 }
Performance/Squeeze
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes |
1.7 |
- |
Identifies places where gsub(/a+/, 'a')
and gsub!(/a+/, 'a')
can be replaced by squeeze('a')
and squeeze!('a')
.
The squeeze('a')
method is faster than gsub(/a+/, 'a')
.
Performance/StartWith
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes (Unsafe) |
0.36 |
1.10 |
Identifies unnecessary use of a regex where String#start_with?
would suffice.
This cop has SafeMultiline
configuration option that true
by default because
^start
is unsafe as it will behave incompatible with start_with?
for receiver is multiline string.
Safety
This will change to a new method call which isn’t guaranteed to be on the object. Switching these methods has to be done with knowledge of the types of the variables which rubocop doesn’t have.
Examples
# bad
'abc'.match?(/\Aab/)
/\Aab/.match?('abc')
'abc' =~ /\Aab/
/\Aab/ =~ 'abc'
'abc'.match(/\Aab/)
/\Aab/.match('abc')
# good
'abc'.start_with?('ab')
Performance/StringIdentifierArgument
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes |
1.13 |
- |
Identifies places where string identifier argument can be replaced by symbol identifier argument. It prevents the redundancy of the internal string-to-symbol conversion.
This cop targets methods that take identifier (e.g. method name) argument and the following examples are parts of it.
Performance/StringInclude
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes (Unsafe) |
1.7 |
1.12 |
Identifies unnecessary use of a regex where String#include?
would suffice.
Performance/StringReplacement
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes |
0.33 |
- |
Identifies places where gsub
can be replaced by tr
or delete
.
Performance/Sum
Required Ruby version: 2.4 |
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Pending |
Yes |
Yes (Unsafe) |
1.8 |
1.13 |
Identifies places where custom code finding the sum of elements
in some Enumerable object can be replaced by Enumerable#sum
method.
Safety
Autocorrections are unproblematic wherever an initial value is provided explicitly:
[1, 2, 3].reduce(4, :+) # => 10
[1, 2, 3].sum(4) # => 10
[].reduce(4, :+) # => 4
[].sum(4) # => 4
This also holds true for non-numeric types which implement a :+
method:
['l', 'o'].reduce('Hel', :+) # => "Hello"
['l', 'o'].sum('Hel') # => "Hello"
When no initial value is provided though, Enumerable#reduce
will pick the first enumerated value
as initial value and successively add all following values to it, whereas
Enumerable#sum
will set an initial value of 0
(Integer
) which can lead to a TypeError
:
[].reduce(:+) # => nil
[1, 2, 3].reduce(:+) # => 6
['H', 'e', 'l', 'l', 'o'].reduce(:+) # => "Hello"
[].sum # => 0
[1, 2, 3].sum # => 6
['H', 'e', 'l', 'l', 'o'].sum # => in `+': String can't be coerced into Integer (TypeError)
Examples
OnlySumOrWithInitialValue: false (default)
# bad
[1, 2, 3].inject(:+) # Autocorrections for cases without initial value are unsafe
[1, 2, 3].inject(&:+) # and will only be performed when using the `-A` option.
[1, 2, 3].reduce { |acc, elem| acc + elem } # They can be prohibited completely using `SafeAutoCorrect: true`.
[1, 2, 3].reduce(10, :+)
[1, 2, 3].map { |elem| elem ** 2 }.sum
[1, 2, 3].collect(&:count).sum(10)
# good
[1, 2, 3].sum
[1, 2, 3].sum(10)
[1, 2, 3].sum { |elem| elem ** 2 }
[1, 2, 3].sum(10, &:count)
Performance/TimesMap
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes (Unsafe) |
0.36 |
1.13 |
Checks for .times.map calls. In most cases such calls can be replaced with an explicit array creation.
Performance/UnfreezeString
Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed |
---|---|---|---|---|
Enabled |
Yes |
Yes (Unsafe) |
0.50 |
1.9 |
In Ruby 2.3 or later, use unary plus operator to unfreeze a string
literal instead of String#dup
and String.new
.
Unary plus operator is faster than String#dup
.
Safety
This cop’s autocorrection is unsafe because String.new
(without operator) is not
exactly the same as +''
. These differ in encoding. String.new.encoding
is always
ASCII-8BIT
. However, (+'').encoding
is the same as script encoding(e.g. UTF-8
).
if you expect ASCII-8BIT
encoding, disable this cop.