////
  Do NOT edit this file by hand directly, as it is automatically generated.

  Please make any necessary changes to the cop documentation within the source files themselves.
////

= Performance

[#performanceancestorsinclude]
== Performance/AncestorsInclude

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| No
| Always (Unsafe)
| 1.7
| -
|===

Identifies usages of `ancestors.include?` and change them to use `<=` instead.

[#safety-performanceancestorsinclude]
=== Safety

This cop is unsafe because it can't tell whether the receiver is a class or an object.
e.g. the false positive was for `Nokogiri::XML::Node#ancestors`.

[#examples-performanceancestorsinclude]
=== Examples

[source,ruby]
----
# bad
A.ancestors.include?(B)

# good
A <= B
----

[#references-performanceancestorsinclude]
=== References

* https://github.com/fastruby/fast-ruby#ancestorsinclude-vs--code

[#performancearraysemiinfiniterangeslice]
== Performance/ArraySemiInfiniteRangeSlice

NOTE: Requires Ruby version 2.7

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Disabled
| No
| Always (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

[#safety-performancearraysemiinfiniterangeslice]
=== Safety

This cop is unsafe for string slices because strings do not have `#take` and `#drop` methods.

[#examples-performancearraysemiinfiniterangeslice]
=== Examples

[source,ruby]
----
# bad
array[..2]
array[...2]
array[2..]
array[2...]
array.slice(..2)

# good
array.take(3)
array.take(2)
array.drop(2)
array.drop(2)
array.take(3)
----

[#performancebigdecimalwithnumericargument]
== Performance/BigDecimalWithNumericArgument

NOTE: Requires Ruby version 3.1

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Disabled
| Yes
| Always
| 1.7
| 1.26
|===

Identifies places where a float argument to BigDecimal should be converted to a string.
Initializing from String is faster than from Float for BigDecimal.

Also identifies places where an integer string argument to BigDecimal should be converted to
an integer. Initializing from Integer is faster than from String for BigDecimal.

NOTE: This cop is disabled by default because the performance of initializing with a String
and Number differ between versions. Additionally, performance depends on the size of the Number,
and if it is an Integer or a Float. Since this is very specific to `bigdecimal` internals,
suggestions from this cop are not unlikely to result in code that performs worse than before.

[#examples-performancebigdecimalwithnumericargument]
=== Examples

[source,ruby]
----
# bad
BigDecimal(1.2, 3, exception: true)
4.5.to_d(6, exception: true)

# good
BigDecimal('1.2', 3, exception: true)
BigDecimal('4.5', 6, exception: true)

# bad
BigDecimal('1', 2)
BigDecimal('4', 6)

# good
BigDecimal(1, 2)
4.to_d(6)
----

[#performancebindcall]
== Performance/BindCall

NOTE: Requires Ruby version 2.7

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 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, ...)`.

[#examples-performancebindcall]
=== Examples

[source,ruby]
----
# bad
umethod.bind(obj).call(foo, bar)
umethod.bind(obj).(foo, bar)

# good
umethod.bind_call(obj, foo, bar)
----

[#performanceblockgivenwithexplicitblock]
== Performance/BlockGivenWithExplicitBlock

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Disabled
| Yes
| Always
| 1.9
| 1.22
|===

Identifies unnecessary use of a `block_given?` where explicit check
of block argument would suffice.

NOTE: This cop produces code with significantly worse performance when a
block is being passed to the method and as such should not be enabled.

[#examples-performanceblockgivenwithexplicitblock]
=== Examples

[source,ruby]
----
# bad
def method(&block)
  do_something if block_given?
end

# good
def method(&block)
  do_something if block
end

# good - block is reassigned
def method(&block)
  block ||= -> { do_something }
  warn "Using default ..." unless block_given?
  # ...
end
----

[#performancecaller]
== Performance/Caller

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 0.49
| 1.9
|===

Identifies places where `caller[n]` can be replaced by `caller(n..n).first`.

[#examples-performancecaller]
=== Examples

[source,ruby]
----
# bad
caller[1]
caller.first
caller_locations[1]
caller_locations.first

# good
caller(2..2).first
caller(1..1).first
caller_locations(2..2).first
caller_locations(1..1).first
----

[#performancecasewhensplat]
== Performance/CaseWhenSplat

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Disabled
| Yes
| Always (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-performancecasewhensplat]
=== 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

[#examples-performancecasewhensplat]
=== Examples

[source,ruby]
----
# bad
case foo
when *condition
  bar
when baz
  foobar
end

case foo
when *[1, 2, 3, 4]
  bar
when 5
  baz
end

# good
case foo
when baz
  foobar
when *condition
  bar
end

case foo
when 1, 2, 3, 4
  bar
when 5
  baz
end
----

[#performancecasecmp]
== Performance/Casecmp

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Disabled
| No
| Always (Unsafe)
| 0.36
| 1.21
|===

Identifies places where a case-insensitive string comparison
can better be implemented using `casecmp`.

This cop is disabled by default because `String#casecmp` only works with
ASCII characters. See https://github.com/rubocop/rubocop/issues/9753.

If you are working only with ASCII characters, then this cop can be
safely enabled.

[#safety-performancecasecmp]
=== Safety

This cop is unsafe because `String#casecmp` and `String#casecmp?` behave
differently when using Non-ASCII characters.

[#examples-performancecasecmp]
=== Examples

[source,ruby]
----
# bad
str.downcase == 'abc'
str.upcase.eql? 'ABC'
'abc' == str.downcase
'ABC'.eql? str.upcase
str.downcase == str.downcase

# good
str.casecmp('ABC').zero?
'abc'.casecmp(str).zero?
----

[#references-performancecasecmp]
=== References

* https://github.com/fastruby/fast-ruby#stringcasecmp-vs--stringcasecmp-vs-stringdowncase---code

[#performancechainarrayallocation]
== 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.

[#examples-performancechainarrayallocation]
=== Examples

[source,ruby]
----
# bad
array = ["a", "b", "c"]
array.compact.flatten.map { |x| x.downcase }

# good
array = ["a", "b", "c"]
array.compact!
array.flatten!
array.map! { |x| x.downcase }
array
----

[#performancecollectionliteralinloop]
== 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`.

NOTE: Since Ruby 3.4, certain simple arguments to `Array#include?` are
optimized directly in Ruby. This avoids allocations without changing the
code, as such no offense will be registered in those cases. Currently that
includes: strings, `self`, local variables, instance variables, and method
calls without arguments. Additionally, any number of methods can be chained:
`[1, 2, 3].include?(@foo)` and `[1, 2, 3].include?(@foo.bar.baz)` both avoid
the array allocation.

[#examples-performancecollectionliteralinloop]
=== Examples

[source,ruby]
----
# bad
users.select do |user|
  %i[superadmin admin].include?(user.role)
end

# good
admin_roles = %i[superadmin admin]
users.select do |user|
  admin_roles.include?(user.role)
end

# good
ADMIN_ROLES = %i[superadmin admin]
...
users.select do |user|
  ADMIN_ROLES.include?(user.role)
end
----

[#configurable-attributes-performancecollectionliteralinloop]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| MinSize
| `1`
| Integer
|===

[#performancecomparewithblock]
== Performance/CompareWithBlock

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 0.46
| -
|===

Identifies places where `sort { |a, b| a.foo <=> b.foo }`
can be replaced by `sort_by(&:foo)`.
This cop also checks `sort!`, `min`, `max` and `minmax` methods.

[#examples-performancecomparewithblock]
=== Examples

[source,ruby]
----
# bad
array.sort   { |a, b| a.foo <=> b.foo }
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.minmax { |a, b| a.foo <=> b.foo }
array.sort   { |a, b| a[:foo] <=> b[:foo] }

# good
array.sort_by(&:foo)
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.minmax_by(&:foo)
array.sort_by { |a| a[:foo] }
----

[#performanceconcurrentmonotonictime]
== Performance/ConcurrentMonotonicTime

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always
| 1.12
| -
|===

Identifies places where `Concurrent.monotonic_time`
can be replaced by `Process.clock_gettime(Process::CLOCK_MONOTONIC)`.

[#examples-performanceconcurrentmonotonictime]
=== Examples

[source,ruby]
----
# bad
Concurrent.monotonic_time

# good
Process.clock_gettime(Process::CLOCK_MONOTONIC)
----

[#references-performanceconcurrentmonotonictime]
=== References

* https://github.com/rails/rails/pull/43502

[#performanceconstantregexp]
== Performance/ConstantRegexp

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always
| 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-performanceconstantregexp]
=== Examples

[source,ruby]
----
# 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
----

[#performancecount]
== Performance/Count

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always (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-performancecount]
=== Safety

This cop is unsafe because it has known compatibility issues with `ActiveRecord` and other
frameworks. Before Rails 5.1, `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:

[source,ruby]
----
Model.where(id: [1, 2, 3]).select { |m| m.method == true }.size
----

becomes:

[source,ruby]
----
Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }
----

[#examples-performancecount]
=== Examples

[source,ruby]
----
# 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
----

[#performancedeleteprefix]
== Performance/DeletePrefix

NOTE: Requires Ruby version 2.5

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| No
| Always (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/, '')`.

[#safety-performancedeleteprefix]
=== Safety

This cop is unsafe because `Pathname` has `sub` but not `delete_prefix`.

[#examples-performancedeleteprefix]
=== Examples

[source,ruby]
----
# bad
str.gsub(/\Aprefix/, '')
str.gsub!(/\Aprefix/, '')

str.sub(/\Aprefix/, '')
str.sub!(/\Aprefix/, '')

# good
str.delete_prefix('prefix')
str.delete_prefix!('prefix')
----

[#safemultiline_-true-_default_-performancedeleteprefix]
==== SafeMultiline: true (default)

[source,ruby]
----
# good
str.gsub(/^prefix/, '')
str.gsub!(/^prefix/, '')
str.sub(/^prefix/, '')
str.sub!(/^prefix/, '')
----

[#safemultiline_-false-performancedeleteprefix]
==== SafeMultiline: false

[source,ruby]
----
# bad
str.gsub(/^prefix/, '')
str.gsub!(/^prefix/, '')
str.sub(/^prefix/, '')
str.sub!(/^prefix/, '')
----

[#configurable-attributes-performancedeleteprefix]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| SafeMultiline
| `true`
| Boolean
|===

[#performancedeletesuffix]
== Performance/DeleteSuffix

NOTE: Requires Ruby version 2.5

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| No
| Always (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/, '')`.

[#safety-performancedeletesuffix]
=== Safety

This cop is unsafe because `Pathname` has `sub` but not `delete_suffix`.

[#examples-performancedeletesuffix]
=== Examples

[source,ruby]
----
# 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')
----

[#safemultiline_-true-_default_-performancedeletesuffix]
==== SafeMultiline: true (default)

[source,ruby]
----
# good
str.gsub(/suffix$/, '')
str.gsub!(/suffix$/, '')
str.sub(/suffix$/, '')
str.sub!(/suffix$/, '')
----

[#safemultiline_-false-performancedeletesuffix]
==== SafeMultiline: false

[source,ruby]
----
# bad
str.gsub(/suffix$/, '')
str.gsub!(/suffix$/, '')
str.sub(/suffix$/, '')
str.sub!(/suffix$/, '')
----

[#configurable-attributes-performancedeletesuffix]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| SafeMultiline
| `true`
| Boolean
|===

[#performancedetect]
== Performance/Detect

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always (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-performancedetect]
=== 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-performancedetect]
=== Examples

[source,ruby]
----
# 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 }
----

[#references-performancedetect]
=== References

* https://github.com/fastruby/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code

[#performancedoublestartendwith]
== Performance/DoubleStartEndWith

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 0.36
| 0.48
|===

Checks for consecutive `#start_with?` or `#end_with?` calls.
These methods accept multiple arguments, so in some cases like when
they are separated by `||`, they can be combined into a single method call.

`IncludeActiveSupportAliases` configuration option is used to check for
`starts_with?` and `ends_with?`. These methods are defined by Active Support.

[#examples-performancedoublestartendwith]
=== Examples

[source,ruby]
----
# bad
str.start_with?("a") || str.start_with?(Some::CONST)
str.start_with?("a", "b") || str.start_with?("c")
!str.start_with?(foo) && !str.start_with?(bar)
str.end_with?(var1) || str.end_with?(var2)

# good
str.start_with?("a", Some::CONST)
str.start_with?("a", "b", "c")
!str.start_with?(foo, bar)
str.end_with?(var1, var2)
----

[#includeactivesupportaliases_-false-_default_-performancedoublestartendwith]
==== IncludeActiveSupportAliases: false (default)

[source,ruby]
----
# good
str.starts_with?("a", "b") || str.starts_with?("c")
str.ends_with?(var1) || str.ends_with?(var2)

str.starts_with?("a", "b", "c")
str.ends_with?(var1, var2)
----

[#includeactivesupportaliases_-true-performancedoublestartendwith]
==== IncludeActiveSupportAliases: true

[source,ruby]
----
# bad
str.starts_with?("a", "b") || str.starts_with?("c")
str.ends_with?(var1) || str.ends_with?(var2)

# good
str.starts_with?("a", "b", "c")
str.ends_with?(var1, var2)
----

[#configurable-attributes-performancedoublestartendwith]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| IncludeActiveSupportAliases
| `false`
| Boolean
|===

[#performanceendwith]
== Performance/EndWith

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always (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-performanceendwith]
=== 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-performanceendwith]
=== Examples

[source,ruby]
----
# 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')
----

[#safemultiline_-true-_default_-performanceendwith]
==== SafeMultiline: true (default)

[source,ruby]
----
# good
'abc'.match?(/bc$/)
/bc$/.match?('abc')
'abc' =~ /bc$/
/bc$/ =~ 'abc'
'abc'.match(/bc$/)
/bc$/.match('abc')
----

[#safemultiline_-false-performanceendwith]
==== SafeMultiline: false

[source,ruby]
----
# bad
'abc'.match?(/bc$/)
/bc$/.match?('abc')
'abc' =~ /bc$/
/bc$/ =~ 'abc'
'abc'.match(/bc$/)
/bc$/.match('abc')
----

[#configurable-attributes-performanceendwith]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| SafeMultiline
| `true`
| Boolean
|===

[#references-performanceendwith]
=== References

* https://github.com/fastruby/fast-ruby#stringmatch-vs-stringmatch-vs-stringstart_withstringend_with-code-start-code-end

[#performancefixedsize]
== 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-performancefixedsize]
=== Examples

[source,ruby]
----
# 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
----

[#performanceflatmap]
== Performance/FlatMap

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 0.30
| -
|===

Identifies usages of `map { ... }.flatten` and
change them to use `flat_map { ... }` instead.

[#examples-performanceflatmap]
=== Examples

[source,ruby]
----
# 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
----

[#configurable-attributes-performanceflatmap]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| EnabledForFlattenWithoutParams
| `false`
| Boolean
|===

[#references-performanceflatmap]
=== References

* https://github.com/fastruby/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code

[#performanceinefficienthashsearch]
== Performance/InefficientHashSearch

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| No
| Always (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.

[#safety-performanceinefficienthashsearch]
=== Safety

This cop is unsafe because it can't tell whether the receiver is a hash object.

[#examples-performanceinefficienthashsearch]
=== Examples

[source,ruby]
----
# 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)
----

[#references-performanceinefficienthashsearch]
=== References

* https://github.com/fastruby/fast-ruby#hashkey-instead-of-hashkeysinclude-code

[#performanceioreadlines]
== Performance/IoReadlines

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Disabled
| Yes
| Always
| 1.7
| -
|===

Identifies places where inefficient `readlines` method
can be replaced by `each_line` to avoid fully loading file content into memory.

[#examples-performanceioreadlines]
=== Examples

[source,ruby]
----
# 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 }
----

[#references-performanceioreadlines]
=== References

* https://docs.gitlab.com/development/performance/#reading-from-files-and-other-data-sources

[#performancemapcompact]
== Performance/MapCompact

NOTE: Requires Ruby version 2.7

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| No
| Always (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`.

[source,ruby]
----
[true, false, nil].compact              #=> [true, false]
[true, false, nil].filter_map(&:itself) #=> [true]
----

[#safety-performancemapcompact]
=== Safety

This cop is unsafe because `map { ... }.compact` might yield
different results than `filter_map`. As illustrated in the example, `filter_map`
also filters out falsey values, while `compact` only gets rid of `nil`.

[#examples-performancemapcompact]
=== Examples

[source,ruby]
----
# bad
ary.map(&:foo).compact
ary.collect(&:foo).compact

# good
ary.filter_map(&:foo)
ary.map(&:foo).compact!
ary.compact.map(&:foo)
----

[#performancemapmethodchain]
== Performance/MapMethodChain

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| No
| No
| 1.19
| -
|===

Checks if the map method is used in a chain.

Autocorrection is not supported because an appropriate block variable name cannot be determined automatically.

[source,ruby]
----
class X
  def initialize
    @@num = 0
  end

  def foo
    @@num += 1
    self
  end

  def bar
    @@num * 2
  end
end

[X.new, X.new].map(&:foo).map(&:bar) # => [4, 4]
[X.new, X.new].map { |x| x.foo.bar } # => [2, 4]
----

[#safety-performancemapmethodchain]
=== Safety

This cop is unsafe because false positives occur if the number of times the first method is executed
affects the return value of subsequent methods.

[#examples-performancemapmethodchain]
=== Examples

[source,ruby]
----
# bad
array.map(&:foo).map(&:bar)

# good
array.map { |item| item.foo.bar }
----

[#performancemethodobjectasblock]
== 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.

[#examples-performancemethodobjectasblock]
=== Examples

[source,ruby]
----
# bad
array.map(&method(:do_something))
[1, 2, 3].each(&out.method(:puts))

# good
array.map { |x| do_something(x) }
[1, 2, 3].each { |x| out.puts(x) }
----

[#references-performancemethodobjectasblock]
=== References

* https://github.com/fastruby/fast-ruby#normal-way-to-apply-method-vs-method-code

[#performanceopenstruct]
== 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.

[#safety-performanceopenstruct]
=== Safety

This cop is unsafe because `OpenStruct.new` and `Struct.new`
are not equivalent.

[#examples-performanceopenstruct]
=== Examples

[source,ruby]
----
# bad
class MyClass
  def my_method
    OpenStruct.new(my_key1: 'my_value1', my_key2: 'my_value2')
  end
end

# good
class MyClass
  MyStruct = Struct.new(:my_key1, :my_key2)
  def my_method
    MyStruct.new('my_value1', 'my_value2')
  end
end
----

[#performancerangeinclude]
== Performance/RangeInclude

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| No
| Always (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-performancerangeinclude]
=== Safety

This cop is unsafe because `Range#include?` (or `Range#member?`) and `Range#cover?`
are not equivalent behavior.
Example of a case where `Range#cover?` may not provide the desired result:

[source,ruby]
----
('a'..'z').cover?('yellow') # => true
----

[#examples-performancerangeinclude]
=== Examples

[source,ruby]
----
# bad
('a'..'z').include?('b') # => true
('a'..'z').member?('b')  # => true

# good
('a'..'z').cover?('b') # => true
----

[#references-performancerangeinclude]
=== References

* https://github.com/fastruby/fast-ruby#cover-vs-include-code

[#performanceredundantblockcall]
== Performance/RedundantBlockCall

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 0.36
| -
|===

Identifies the use of a `&block` parameter and `block.call`
where `yield` would do just as well.

[#examples-performanceredundantblockcall]
=== Examples

[source,ruby]
----
# bad
def method(&block)
  block.call
end
def another(&func)
  func.call 1, 2, 3
end

# good
def method
  yield
end
def another
  yield 1, 2, 3
end
----

[#references-performanceredundantblockcall]
=== References

* https://github.com/fastruby/fast-ruby#proccall-and-block-arguments-vs-yieldcode

[#performanceredundantequalitycomparisonblock]
== Performance/RedundantEqualityComparisonBlock

NOTE: Requires Ruby version 2.5

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| No
| Always (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:

[source,ruby]
----
[/pattern/].all? { |regexp| regexp.match?('pattern') } # => true
[/pattern/].all? { |regexp| regexp =~ 'pattern' }      # => true
[/pattern/].all?('pattern')                            # => false
----

[#safety-performanceredundantequalitycomparisonblock]
=== Safety

This cop is unsafe because `===` and `==` do not always behave the same.

[#examples-performanceredundantequalitycomparisonblock]
=== Examples

[source,ruby]
----
# 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)
----

[#allowregexpmatch_-true-_default_-performanceredundantequalitycomparisonblock]
==== AllowRegexpMatch: true (default)

[source,ruby]
----
# good
items.all? { |item| item =~ pattern }
items.all? { |item| item.match?(pattern) }
----

[#allowregexpmatch_-false-performanceredundantequalitycomparisonblock]
==== AllowRegexpMatch: false

[source,ruby]
----
# bad
items.all? { |item| item =~ pattern }
items.all? { |item| item.match?(pattern) }
----

[#configurable-attributes-performanceredundantequalitycomparisonblock]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| AllowRegexpMatch
| `true`
| Boolean
|===

[#references-performanceredundantequalitycomparisonblock]
=== References

* https://github.com/rails/rails/pull/41363

[#performanceredundantmatch]
== Performance/RedundantMatch

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 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.

[#examples-performanceredundantmatch]
=== Examples

[source,ruby]
----
# bad
do_something if str.match(/regex/)
while regex.match('str')
  do_something
end

# good
method(str =~ /regex/)
return value unless regex =~ 'str'
----

[#performanceredundantmerge]
== Performance/RedundantMerge

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| No
| Always (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-performanceredundantmerge]
=== Safety

This cop is unsafe because RuboCop cannot determine if the
receiver of `merge!` is actually a hash or not.

[#examples-performanceredundantmerge]
=== Examples

[source,ruby]
----
# bad
hash.merge!(a: 1)
hash.merge!({'key' => 'value'})

# good
hash[:a] = 1
hash['key'] = 'value'
----

[#maxkeyvaluepairs_-2-_default_-performanceredundantmerge]
==== MaxKeyValuePairs: 2 (default)

[source,ruby]
----
# bad
hash.merge!(a: 1, b: 2)

# good
hash[:a] = 1
hash[:b] = 2
----

[#configurable-attributes-performanceredundantmerge]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| MaxKeyValuePairs
| `2`
| Integer
|===

[#references-performanceredundantmerge]
=== References

* https://github.com/fastruby/fast-ruby#hashmerge-vs-hash-code

[#performanceredundantsortblock]
== Performance/RedundantSortBlock

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always
| 1.7
| -
|===

Identifies places where `sort { |a, b| a <=> b }` can be replaced with `sort`.

[#examples-performanceredundantsortblock]
=== Examples

[source,ruby]
----
# bad
array.sort { |a, b| a <=> b }

# good
array.sort
----

[#performanceredundantsplitregexpargument]
== Performance/RedundantSplitRegexpArgument

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always
| 1.10
| -
|===

Identifies places where `split` argument can be replaced from
a deterministic regexp to a string.

[#examples-performanceredundantsplitregexpargument]
=== Examples

[source,ruby]
----
# bad
'a,b,c'.split(/,/)

# good
'a,b,c'.split(',')
----

[#performanceredundantstringchars]
== Performance/RedundantStringChars

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always
| 1.7
| -
|===

Checks for redundant `String#chars`.

[#examples-performanceredundantstringchars]
=== Examples

[source,ruby]
----
# 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`.
----

[#performanceregexpmatch]
== Performance/RegexpMatch

NOTE: Requires Ruby version 2.4

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 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-performanceregexpmatch]
=== Examples

[source,ruby]
----
# 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
----

[#references-performanceregexpmatch]
=== References

* https://github.com/fastruby/fast-ruby#regexp-vs-regexpmatch-vs-regexpmatch-vs-stringmatch-vs-string-vs-stringmatch-code-

[#performancereverseeach]
== Performance/ReverseEach

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 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.

[source,ruby]
----
[1, 2, 3].reverse.each {} #=> [3, 2, 1]
[1, 2, 3].reverse_each {} #=> [1, 2, 3]
----

[#examples-performancereverseeach]
=== Examples

[source,ruby]
----
# bad
items.reverse.each

# good
items.reverse_each
----

[#references-performancereverseeach]
=== References

* https://github.com/fastruby/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code

[#performancereversefirst]
== Performance/ReverseFirst

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always
| 1.7
| -
|===

Identifies places where `reverse.first(n)` and `reverse.first`
can be replaced by `last(n).reverse` and `last`.

[#examples-performancereversefirst]
=== Examples

[source,ruby]
----
# bad
array.reverse.first(5)
array.reverse.first

# good
array.last(5).reverse
array.last
----

[#performanceselectmap]
== Performance/SelectMap

NOTE: Requires 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`.

[#examples-performanceselectmap]
=== Examples

[source,ruby]
----
# bad
ary.select(&:foo).map(&:bar)
ary.filter(&:foo).map(&:bar)

# good
ary.filter_map { |o| o.bar if o.foo }
----

[#performancesize]
== Performance/Size

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 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-performancesize]
=== Examples

[source,ruby]
----
# 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 }
----

[#references-performancesize]
=== References

* https://github.com/fastruby/fast-ruby#arraylength-vs-arraysize-vs-arraycount-code

[#performancesortreverse]
== Performance/SortReverse

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always
| 1.7
| -
|===

Identifies places where `sort { |a, b| b <=> a }`
can be replaced by a faster `sort.reverse`.

[#examples-performancesortreverse]
=== Examples

[source,ruby]
----
# bad
array.sort { |a, b| b <=> a }

# good
array.sort.reverse
----

[#performancesqueeze]
== Performance/Squeeze

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always
| 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')`.

[#examples-performancesqueeze]
=== Examples

[source,ruby]
----
# bad
str.gsub(/a+/, 'a')
str.gsub!(/a+/, 'a')

# good
str.squeeze('a')
str.squeeze!('a')
----

[#references-performancesqueeze]
=== References

* https://github.com/fastruby/fast-ruby#remove-extra-spaces-or-other-contiguous-characters-code

[#performancestartwith]
== Performance/StartWith

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always (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-performancestartwith]
=== 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-performancestartwith]
=== Examples

[source,ruby]
----
# bad
'abc'.match?(/\Aab/)
/\Aab/.match?('abc')
'abc' =~ /\Aab/
/\Aab/ =~ 'abc'
'abc'.match(/\Aab/)
/\Aab/.match('abc')

# good
'abc'.start_with?('ab')
----

[#safemultiline_-true-_default_-performancestartwith]
==== SafeMultiline: true (default)

[source,ruby]
----
# good
'abc'.match?(/^ab/)
/^ab/.match?('abc')
'abc' =~ /^ab/
/^ab/ =~ 'abc'
'abc'.match(/^ab/)
/^ab/.match('abc')
----

[#safemultiline_-false-performancestartwith]
==== SafeMultiline: false

[source,ruby]
----
# bad
'abc'.match?(/^ab/)
/^ab/.match?('abc')
'abc' =~ /^ab/
/^ab/ =~ 'abc'
'abc'.match(/^ab/)
/^ab/.match('abc')
----

[#configurable-attributes-performancestartwith]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| SafeMultiline
| `true`
| Boolean
|===

[#references-performancestartwith]
=== References

* https://github.com/fastruby/fast-ruby#stringmatch-vs-stringmatch-vs-stringstart_withstringend_with-code-start-code-end

[#performancestringbytesize]
== Performance/StringBytesize

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| No
| Always (Unsafe)
| 1.23
| -
|===

Checks for calls to `#bytes` counting method and suggests using `bytesize` instead.
The `bytesize` method is more efficient and directly returns the size in bytes,
avoiding the intermediate array allocation that `bytes.size` incurs.

[#safety-performancestringbytesize]
=== Safety

This cop is unsafe because it assumes that the receiver
responds to `#bytesize` method.

[#examples-performancestringbytesize]
=== Examples

[source,ruby]
----
# bad
string_var.bytes.count
"foobar".bytes.size

# good
string_var.bytesize
"foobar".bytesize
----

[#performancestringidentifierargument]
== Performance/StringIdentifierArgument

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always
| 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.

[#examples-performancestringidentifierargument]
=== Examples

[source,ruby]
----
# bad
send('do_something')
attr_accessor 'do_something'
instance_variable_get('@ivar')

# good
send(:do_something)
attr_accessor :do_something
instance_variable_get(:@ivar)

# good - these methods don't support namespaced symbols
const_get("#{module_path}::Base")
const_source_location("#{module_path}::Base")
const_defined?("#{module_path}::Base")

# good - using a symbol when string interpolation is involved causes a performance regression.
respond_to?("string_#{interpolation}")
----

[#performancestringinclude]
== Performance/StringInclude

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always (Unsafe)
| 1.7
| 1.12
|===

Identifies unnecessary use of a regex where `String#include?` would suffice.

[#safety-performancestringinclude]
=== Safety

This cop's offenses are not safe to autocorrect if a receiver is nil or a Symbol.

[#examples-performancestringinclude]
=== Examples

[source,ruby]
----
# bad
str.match?(/ab/)
/ab/.match?(str)
str =~ /ab/
/ab/ =~ str
str.match(/ab/)
/ab/.match(str)
/ab/ === str

# good
str.include?('ab')
----

[#performancestringreplacement]
== Performance/StringReplacement

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 0.33
| -
|===

Identifies places where `gsub` can be replaced by `tr` or `delete`.

[#examples-performancestringreplacement]
=== Examples

[source,ruby]
----
# bad
'abc'.gsub('b', 'd')
'abc'.gsub('a', '')
'abc'.gsub(/a/, 'd')
'abc'.gsub!('a', 'd')

# good
'abc'.gsub(/.*/, 'a')
'abc'.gsub(/a+/, 'd')
'abc'.tr('b', 'd')
'a b c'.delete(' ')
----

[#references-performancestringreplacement]
=== References

* https://github.com/fastruby/fast-ruby#stringgsub-vs-stringtr-code

[#performancesum]
== Performance/Sum

NOTE: Requires Ruby version 2.4

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| Yes
| Always (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-performancesum]
=== Safety

Autocorrections are unproblematic wherever an initial value is provided explicitly:

[source,ruby]
----
[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:

[source,ruby]
----
['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`:

[source,ruby]
----
[].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-performancesum]
=== Examples

[#onlysumorwithinitialvalue_-false-_default_-performancesum]
==== OnlySumOrWithInitialValue: false (default)

[source,ruby]
----
# 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)
----

[#onlysumorwithinitialvalue_-true-performancesum]
==== OnlySumOrWithInitialValue: true

[source,ruby]
----
# bad
[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(10)
[1, 2, 3].sum { |elem| elem ** 2 }
[1, 2, 3].sum(10, &:count)
----

[#configurable-attributes-performancesum]
=== Configurable attributes

|===
| Name | Default value | Configurable values

| OnlySumOrWithInitialValue
| `false`
| Boolean
|===

[#references-performancesum]
=== References

* https://www.bigbinary.com/blog/ruby-2-4-introduces-enumerable-sum

[#performancetimesmap]
== Performance/TimesMap

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always (Unsafe)
| 0.36
| 1.13
|===

Checks for .times.map calls.
In most cases such calls can be replaced
with an explicit array creation.

[#safety-performancetimesmap]
=== Safety

This cop's autocorrection is unsafe because `Integer#times` does nothing if receiver is 0
or less. However, `Array.new` raises an error if argument is less than 0.

For example:

[source,ruby]
----
-1.times{}    # does nothing
Array.new(-1) # ArgumentError: negative array size
----

[#examples-performancetimesmap]
=== Examples

[source,ruby]
----
# bad
9.times.map do |i|
  i.to_s
end

# good
Array.new(9) do |i|
  i.to_s
end
----

[#performanceunfreezestring]
== Performance/UnfreezeString

NOTE: Requires Ruby version 2.3

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always (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-performanceunfreezestring]
=== 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.

[#examples-performanceunfreezestring]
=== Examples

[source,ruby]
----
# bad
''.dup          # when Ruby 3.2 or lower
"something".dup # when Ruby 3.2 or lower
String.new
String.new('')
String.new('something')

# good
+'something'
+''
----

[#performanceuridefaultparser]
== Performance/UriDefaultParser

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Enabled
| Yes
| Always
| 0.50
| -
|===

Identifies places where `URI::Parser.new` can be replaced by `URI::DEFAULT_PARSER`.

[#examples-performanceuridefaultparser]
=== Examples

[source,ruby]
----
# bad
URI::Parser.new

# good
URI::DEFAULT_PARSER
----

[#performancezipwithoutblock]
== Performance/ZipWithoutBlock

|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed

| Pending
| No
| Always (Unsafe)
| 1.24
| -
|===

Checks for `map { |id| [id] }` and suggests replacing it with `zip`.

[#safety-performancezipwithoutblock]
=== Safety

This cop is unsafe for novel definitions of `map` and `collect`
on non-Enumerable objects that do not respond to `zip`.
To make your object enumerable, define an `each` method
as described in https://ruby-doc.org/core/Enumerable.html

[#examples-performancezipwithoutblock]
=== Examples

[source,ruby]
----
# bad
[1, 2, 3].map { |id| [id] }

# good
[1, 2, 3].zip
----
