性能

Performance/AncestorsInclude

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

1.7

-

识别 ancestors.include? 的用法,并将其更改为使用

安全

此规则不安全,因为它无法判断接收者是类还是对象。例如,误报发生在 Nokogiri::XML::Node#ancestors 上。

示例

# bad
A.ancestors.include?(B)

# good
A <= B

性能/ArraySemiInfiniteRangeSlice

所需 Ruby 版本:2.7
默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

始终(不安全)

1.9

-

识别使用半无限范围对数组进行切片的地方,这些地方可以用 Array#takeArray#drop 代替。此规则是由于微基准测试中的错误而创建的,因此默认情况下已禁用。请参考 https://github.com/rubocop/rubocop-performance/pull/175#issuecomment-731892717

安全

此规则对于字符串切片不安全,因为字符串没有 #take#drop 方法。

示例

# 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)

性能/BigDecimalWithNumericArgument

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.7

-

识别将数值参数传递给 BigDecimal 的地方,这些地方应该将数值参数转换为字符串。从字符串初始化 BigDecimal 比从数值初始化更快。

示例

# bad
BigDecimal(1, 2)
4.to_d(6)
BigDecimal(1.2, 3, exception: true)
4.5.to_d(6, exception: true)

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

性能/BindCall

所需 Ruby 版本:2.7
默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

1.6

-

在 Ruby 2.7 中,添加了 UnboundMethod#bind_call

此规则识别可以将 bind(obj).call(args, …​) 替换为 bind_call(obj, args, …​) 的地方。

bind_call(obj, args, …​) 方法比 bind(obj).call(args, …​) 更快。

示例

# bad
umethod.bind(obj).call(foo, bar)
umethod.bind(obj).(foo, bar)

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

性能/BlockGivenWithExplicitBlock

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.9

-

识别在显式检查块参数足以的情况下,不必要地使用 block_given? 的地方。

示例

# 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

性能/Caller

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.49

1.9

识别可以将 caller[n] 替换为 caller(n..n).first 的地方。

示例

# 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

性能/CaseWhenSplat

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

始终(不安全)

0.34

1.13

将带有 splat 的 when 条件重新排序到 when 分支的末尾可以提高性能。

每次运行case when语句时,Ruby 都需要为 splat 展开分配内存。由于 Ruby 不像其他一些语言那样支持case when内部的穿透,因此when分支的顺序无关紧要。通过将任何 splat 展开放在when分支列表的末尾,我们将减少为展开分配内存的次数。唯一的例外是,如果您的多个when条件对于任何给定条件都可能为真。这种情况很可能是在定义一个更高层次的 when 条件来覆盖 splat 展开内部的条件。

安全

此 cop 不是不安全的自动更正,因为它不是保证的性能改进。如果case条件处理的数据以有利于命中 splat 展开中的条件的方式进行规范化,则将 splat 条件移到末尾可能会使用更多内存,并且运行速度略慢。有关更多详细信息,请参阅:https://github.com/rubocop/rubocop/pull/6163

示例

# 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

Performance/Casecmp

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

始终(不安全)

0.36

1.21

识别可以使用casecmp更好地实现不区分大小写字符串比较的地方。

此 cop 默认情况下处于禁用状态,因为String#casecmp仅适用于 ASCII 字符。请参阅 https://github.com/rubocop/rubocop/issues/9753.

如果您只使用 ASCII 字符,则可以安全地启用此 cop。

安全

此 cop 不安全,因为String#casecmpString#casecmp?在使用非 ASCII 字符时行为不同。

示例

# 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?

Performance/ChainArrayAllocation

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

0.59

-

识别array.compact.flatten.map { |x| x.downcase }的使用情况。这些方法中的每一个(compactflattenmap)都会生成一个新的中间数组,该数组会立即被丢弃。相反,当我们知道它是安全的时,更快地进行变异。

示例

# 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

性能/CollectionLiteralInLoop

默认启用 安全 支持自动更正 添加版本 更改版本

待定

1.8

-

识别在循环中使用数组和哈希字面量的地方。最好将它们提取到局部变量或常量中,以避免在每次迭代时进行不必要的分配。

您可以使用 MinSize 设置要考虑违规的最小元素数量。

示例

# 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

可配置属性

名称 默认值 可配置值

MinSize

1

整数

性能/CompareWithBlock

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.46

-

识别可以将 sort { |a, b| a.foo <⇒ b.foo } 替换为 sort_by(&:foo) 的地方。此 cop 还检查 sort!minmaxminmax 方法。

示例

# 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] }

性能/ConcurrentMonotonicTime

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.12

-

识别可以将 Concurrent.monotonic_time 替换为 Process.clock_gettime(Process::CLOCK_MONOTONIC) 的地方。

示例

# bad
Concurrent.monotonic_time

# good
Process.clock_gettime(Process::CLOCK_MONOTONIC)

性能/ConstantRegexp

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.9

1.10

查找具有动态组件的正则表达式,这些组件都是常量。

每次执行包含此类正则表达式的代码时,Ruby 都会分配一个新的 Regexp 对象。将其提取到常量中、对其进行记忆或添加 /o 选项以仅执行一次 #{} 插值并重用该 Regexp 对象会更有效。

示例

# 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

性能/Count

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.31

1.8

识别对 Enumerable 上的 count 的使用,这些使用遵循对 selectfind_allfilterreject 的调用。查询逻辑可以改为传递到 count 调用中。

安全

此 cop 不安全,因为它与 ActiveRecord 和其他框架存在已知的兼容性问题。在 Rails 5.1 之前,ActiveRecord 会忽略传递给 count 的块。其他方法(如 select)会将关联转换为数组,然后在数组上运行块。使 count 与块一起工作的简单解决方法是调用 to_a.count {…​}

例如

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

变成

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

示例

# 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

性能/DeletePrefix

所需的 Ruby 版本:2.5
默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

1.6

1.11

在 Ruby 2.5 中,添加了 String#delete_prefix

此代码检查器识别可以将 gsub(/\Aprefix/, '')sub(/\Aprefix/, '') 替换为 delete_prefix('prefix') 的地方。

此代码检查器具有 SafeMultiline 配置选项,默认情况下为 true,因为 ^prefix 不安全,因为它对于接收者是多行字符串时,其行为将与 delete_prefix 不兼容。

delete_prefix('prefix') 方法比 gsub(/\Aprefix/, '') 更快。

安全性

此代码检查器不安全,因为 Pathnamesub 但没有 delete_prefix

示例

# bad
str.gsub(/\Aprefix/, '')
str.gsub!(/\Aprefix/, '')

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

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

SafeMultiline:true(默认)

# good
str.gsub(/^prefix/, '')
str.gsub!(/^prefix/, '')
str.sub(/^prefix/, '')
str.sub!(/^prefix/, '')

SafeMultiline:false

# bad
str.gsub(/^prefix/, '')
str.gsub!(/^prefix/, '')
str.sub(/^prefix/, '')
str.sub!(/^prefix/, '')

可配置属性

名称 默认值 可配置值

SafeMultiline

true

布尔值

性能/DeleteSuffix

所需的 Ruby 版本:2.5
默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

1.6

1.11

在 Ruby 2.5 中,添加了 String#delete_suffix

此代码检查器识别可以将 gsub(/suffix\z/, '')sub(/suffix\z/, '') 替换为 delete_suffix('suffix') 的地方。

此代码检查器具有 SafeMultiline 配置选项,默认情况下为 true,因为 suffix$ 不安全,因为它对于接收者是多行字符串时,其行为将与 delete_suffix? 不兼容。

delete_suffix('suffix') 方法比 gsub(/suffix\z/, '') 更快。

安全性

此代码检查器不安全,因为 Pathnamesub 但没有 delete_suffix

示例

# 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(默认)

# good
str.gsub(/suffix$/, '')
str.gsub!(/suffix$/, '')
str.sub(/suffix$/, '')
str.sub!(/suffix$/, '')

SafeMultiline:false

# bad
str.gsub(/suffix$/, '')
str.gsub!(/suffix$/, '')
str.sub(/suffix$/, '')
str.sub!(/suffix$/, '')

可配置属性

名称 默认值 可配置值

SafeMultiline

true

布尔值

性能/Detect

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.30

1.8

识别 firstlast[0][-1] 连接到 selectfind_allfilter 的用法,并将它们更改为使用 detect

安全性

此代码检查器不安全,因为它假设接收者是 Array 或等效类型,但无法可靠地检测到它。例如,如果接收者是 Hash,它可能会报告误报。

示例

# 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 }

性能/DoubleStartEndWith

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.36

0.48

检查由 || 分隔的两次 #start_with?#end_with? 调用。在某些情况下,此类调用可以用单个 #start_with?/#end_with? 调用替换。

IncludeActiveSupportAliases 配置选项用于检查 starts_with?ends_with?。这些方法由 Active Support 定义。

示例

# 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)

IncludeActiveSupportAliases: false(默认)

# 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

# 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)

可配置属性

名称 默认值 可配置值

IncludeActiveSupportAliases

false

布尔值

性能/EndWith

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.36

1.10

识别不必要地使用正则表达式的情况,而 String#end_with? 就足够了。

此 cop 具有 SafeMultiline 配置选项,默认情况下为 true,因为 end$ 不安全,因为它在接收者为多行字符串时将与 end_with? 的行为不兼容。

安全

这将更改为一个新的方法调用,该调用不能保证在对象上。切换这些方法必须在了解变量类型的基础上进行,而 rubocop 不具备这种能力。

示例

# 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(默认)

# good
'abc'.match?(/bc$/)
/bc$/.match?('abc')
'abc' =~ /bc$/
/bc$/ =~ 'abc'
'abc'.match(/bc$/)
/bc$/.match('abc')

SafeMultiline: false

# bad
'abc'.match?(/bc$/)
/bc$/.match?('abc')
'abc' =~ /bc$/
/bc$/ =~ 'abc'
'abc'.match(/bc$/)
/bc$/.match('abc')

可配置属性

名称 默认值 可配置值

SafeMultiline

true

布尔值

性能/FixedSize

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

0.35

-

不要计算静态大小对象的尺寸。

示例

# 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

性能/FlatMap

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.30

-

识别 map { …​ }.flatten 的用法,并将其更改为使用 flat_map { …​ }

示例

# 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

可配置属性

名称 默认值 可配置值

EnabledForFlattenWithoutParams

false

布尔值

性能/低效哈希搜索

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.56

-

检查哈希中对键和值的低效搜索。

Hash#keys.include?Hash#key? 效率低,因为前者会分配一个新的数组,然后对该数组进行 O(n) 搜索,而 Hash#key? 不会分配任何数组,并执行更快的 O(1) 键搜索。

Hash#values.include?Hash#value? 效率低。虽然它们都对所有值执行 O(n) 搜索,但调用 values 会分配一个新的数组,而使用 value? 则不会。

安全性

此检查器不安全,因为它无法判断接收者是否为哈希对象。

示例

# 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)

性能/IoReadlines

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

始终

1.7

-

识别可以将低效的 readlines 方法替换为 each_line 的位置,以避免将整个文件内容加载到内存中。

示例

# 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 }

性能/MapCompact

所需 Ruby 版本:2.7
默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

1.11

-

在 Ruby 2.7 中,添加了 Enumerable#filter_map

此检查器识别可以将 map { …​ }.compact 替换为 filter_map 的位置。

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

安全性

此检查器的自动更正不安全,因为 map { …​ }.compactfilter_map 不兼容。

示例

# bad
ary.map(&:foo).compact
ary.collect(&:foo).compact

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

性能/MapMethodChain

默认启用 安全 支持自动更正 添加版本 更改版本

待定

1.19

-

检查 map 方法是否在链中使用。

不支持自动更正,因为无法自动确定合适的块变量名。

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]

安全性

此检查器不安全,因为如果第一次方法执行的次数影响后续方法的返回值,则会发生误报。

示例

# bad
array.map(&:foo).map(&:bar)

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

性能/MethodObjectAsBlock

默认启用 安全 支持自动更正 添加版本 更改版本

待定

1.9

-

识别将方法转换为块(使用 &method)并作为参数传递给方法调用的位置。使用显式块并调用其中的方法更快。

示例

# 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) }

性能/OpenStruct

默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

0.61

-

检查 OpenStruct.new 调用。OpenStruct 的实例化会使 Ruby 全局方法缓存失效,因为它会导致程序运行时动态方法定义。这可能会影响性能,尤其是在具有多个 OpenStruct 实例化的单线程应用程序中。

安全

此代码不安全,因为 OpenStruct.newStruct.new 不等效。

示例

# 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

性能/范围包含

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.36

1.7

识别 Range#include?Range#member? 的使用,它们会遍历 Range 中的每个项目以查看指定项目是否存在。相比之下,Range#cover? 只需将目标项目与 Range 的起点和终点进行比较。在绝大多数情况下,这就是我们想要的。

安全

此代码不安全,因为 Range#include?(或 Range#member?)和 Range#cover? 的行为不等效。Range#cover? 可能无法提供预期结果的示例。

('a'..'z').cover?('yellow') # => true

示例

# bad
('a'..'z').include?('b') # => true
('a'..'z').member?('b')  # => true

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

性能/冗余块调用

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.36

-

识别 &block 参数和 block.call 的使用,yield 可以完成相同的功能。

示例

# 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

性能/冗余相等比较块

所需的 Ruby 版本:2.5
默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

1.10

-

检查 Enumerable#all?Enumerable#any?Enumerable#one?Enumerable#none? 的使用是否在块中与 === 或类似方法进行比较。

默认情况下,Object#=== 的行为与 Object#== 相同,但这种行为在子类中被适当地重写。例如,当参数在范围内时,Range#=== 返回 true

此代码具有 AllowRegexpMatch 选项,默认情况下为 true,因为 regexp.match?('string') 通常在块中使用,会导致相反的结果。

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

安全

此代码不安全,因为 ===== 的行为并不总是相同。

示例

# 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(默认)

# good
items.all? { |item| item =~ pattern }
items.all? { |item| item.match?(pattern) }

AllowRegexpMatch: false

# bad
items.all? { |item| item =~ pattern }
items.all? { |item| item.match?(pattern) }

可配置属性

名称 默认值 可配置值

AllowRegexpMatch

true

布尔值

性能/冗余匹配

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.36

-

识别使用Regexp#matchString#match的情况,它们返回#<MatchData>/nil=~的返回值是一个整数索引/nil,并且性能更高。

示例

# bad
do_something if str.match(/regex/)
while regex.match('str')
  do_something
end

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

性能/冗余合并

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.36

1.11

识别可以使用Hash#[]=替换Hash#merge!的地方。您可以使用MaxKeyValuePairs设置要考虑违规的最大键值对数量。

安全

此检查器不安全,因为 RuboCop 无法确定merge!的接收者是否实际上是一个哈希。

示例

# bad
hash.merge!(a: 1)
hash.merge!({'key' => 'value'})

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

MaxKeyValuePairs: 2(默认)

# bad
hash.merge!(a: 1, b: 2)

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

可配置属性

名称 默认值 可配置值

MaxKeyValuePairs

2

整数

性能/冗余排序块

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.7

-

识别可以使用sort替换sort { |a, b| a <⇒ b }的地方。

示例

# bad
array.sort { |a, b| a <=> b }

# good
array.sort

性能/冗余拆分正则表达式参数

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.10

-

识别可以使用字符串替换split参数中的确定性正则表达式的地方。

示例

# bad
'a,b,c'.split(/,/)

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

性能/冗余字符串字符

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.7

-

检查冗余的String#chars

示例

# 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`.

性能/正则表达式匹配

所需的 Ruby 版本:2.4
默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.47

-

在 Ruby 2.4 中,添加了String#match?Regexp#match?Symbol#match?。这些方法比match更快。因为这些方法避免创建MatchData对象或保存反向引用。因此,当不使用MatchData时,请使用match?而不是match

示例

# 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

性能/反向枚举

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.30

-

识别reverse.each的使用情况,并将其更改为使用reverse_each

如果使用返回值,则不会检测到它,因为结果将不同。

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

示例

# bad
items.reverse.each

# good
items.reverse_each

性能/ReverseFirst

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.7

-

识别可以将 reverse.first(n)reverse.first 替换为 last(n).reverselast 的地方。

示例

# bad
array.reverse.first(5)
array.reverse.first

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

性能/SelectMap

所需 Ruby 版本:2.7
默认启用 安全 支持自动更正 添加版本 更改版本

已禁用

1.11

-

在 Ruby 2.7 中,添加了 Enumerable#filter_map

此代码检测器识别可以将 select.map 替换为 filter_map 的地方。

示例

# bad
ary.select(&:foo).map(&:bar)
ary.filter(&:foo).map(&:bar)

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

性能/Size

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.30

-

识别在 ArrayHash 上使用 count 的地方,并将它们更改为 size

待办事项:添加对可能已分配给数组或哈希的变量的更高级检测。

示例

# 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 }

性能/SortReverse

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.7

-

识别可以将 sort { |a, b| b <⇒ a } 替换为更快的 sort.reverse 的地方。

示例

# bad
array.sort { |a, b| b <=> a }

# good
array.sort.reverse

性能/Squeeze

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.7

-

识别可以将 gsub(/a+/, 'a')gsub!(/a+/, 'a') 替换为 squeeze('a')squeeze!('a') 的地方。

squeeze('a') 方法比 gsub(/a+/, 'a') 更快。

示例

# bad
str.gsub(/a+/, 'a')
str.gsub!(/a+/, 'a')

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

性能/StartWith

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.36

1.10

识别不必要使用正则表达式的地方,String#start_with? 就足够了。

此代码检测器具有 SafeMultiline 配置选项,默认情况下为 true,因为 ^start 不安全,因为它在接收者为多行字符串时将与 start_with? 不兼容。

安全性

这将更改为一个新的方法调用,该调用不能保证在对象上。切换这些方法必须在了解变量类型的基础上进行,而 rubocop 不具备这种能力。

示例

# bad
'abc'.match?(/\Aab/)
/\Aab/.match?('abc')
'abc' =~ /\Aab/
/\Aab/ =~ 'abc'
'abc'.match(/\Aab/)
/\Aab/.match('abc')

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

SafeMultiline: true(默认)

# good
'abc'.match?(/^ab/)
/^ab/.match?('abc')
'abc' =~ /^ab/
/^ab/ =~ 'abc'
'abc'.match(/^ab/)
/^ab/.match('abc')

SafeMultiline: false

# bad
'abc'.match?(/^ab/)
/^ab/.match?('abc')
'abc' =~ /^ab/
/^ab/ =~ 'abc'
'abc'.match(/^ab/)
/^ab/.match('abc')

可配置属性

名称 默认值 可配置值

SafeMultiline

true

布尔值

性能/StringIdentifierArgument

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终

1.13

-

识别可以将字符串标识符参数替换为符号标识符参数的地方。它防止了内部字符串到符号转换的冗余。

此代码检测器针对接受标识符(例如方法名)参数的方法,以下示例是其中的一部分。

示例

# bad
send('do_something')
attr_accessor 'do_something'
instance_variable_get('@ivar')
respond_to?("string_#{interpolation}")

# good
send(:do_something)
attr_accessor :do_something
instance_variable_get(:@ivar)
respond_to?(:"string_#{interpolation}")

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

性能/StringInclude

默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

1.7

1.12

识别在String#include? 就能满足的情况下,不必要地使用正则表达式的情况。

安全性

如果接收者为 nil 或 Symbol,则此 cop 的违规行为不安全,无法自动更正。

示例

# bad
str.match?(/ab/)
/ab/.match?(str)
str =~ /ab/
/ab/ =~ str
str.match(/ab/)
/ab/.match(str)
/ab/ === str

# good
str.include?('ab')

性能/字符串替换

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.33

-

识别可以用trdelete 替换gsub 的地方。

示例

# 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(' ')

性能/求和

所需的 Ruby 版本:2.4
默认启用 安全 支持自动更正 添加版本 更改版本

待定

始终(不安全)

1.8

1.13

识别可以用Enumerable#sum 方法替换自定义代码来查找某些 Enumerable 对象中元素总和的地方。

安全性

只要显式提供初始值,自动更正就不会有问题。

[1, 2, 3].reduce(4, :+) # => 10
[1, 2, 3].sum(4) # => 10

[].reduce(4, :+) # => 4
[].sum(4) # => 4

这对实现了:+ 方法的非数字类型也适用。

['l', 'o'].reduce('Hel', :+) # => "Hello"
['l', 'o'].sum('Hel') # => "Hello"

但是,当不提供初始值时,Enumerable#reduce 会将第一个枚举的值作为初始值,并依次将所有后续值加到它,而Enumerable#sum 会将初始值设置为0 (Integer),这会导致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)

示例

OnlySumOrWithInitialValue: false (默认)

# 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

# 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)

可配置属性

名称 默认值 可配置值

OnlySumOrWithInitialValue

false

布尔值

性能/TimesMap

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.36

1.13

检查.times.map 调用。在大多数情况下,此类调用可以用显式数组创建替换。

安全性

此 cop 的自动更正不安全,因为如果接收者为 0 或更小,Integer#times 不会执行任何操作。但是,如果参数小于 0,Array.new 会引发错误。

例如

-1.times{}    # does nothing
Array.new(-1) # ArgumentError: negative array size

示例

# bad
9.times.map do |i|
  i.to_s
end

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

性能/解冻字符串

所需的 Ruby 版本:2.3
默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终(不安全)

0.50

1.9

在 Ruby 2.3 或更高版本中,使用一元加运算符解冻字符串字面量,而不是String#dupString.new。一元加运算符比String#dup 快。

安全

此代码的自动更正不安全,因为 `String.new`(不带运算符)与 `+''` 不完全相同。它们在编码方面有所不同。`String.new.encoding` 始终为 `ASCII-8BIT`。但是,`(+'').encoding` 与脚本编码相同(例如 `UTF-8`)。如果您期望 `ASCII-8BIT` 编码,请禁用此代码检查器。

示例

# 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'
+''

性能/UriDefaultParser

默认启用 安全 支持自动更正 添加版本 更改版本

已启用

始终

0.50

-

识别可以使用 `URI::DEFAULT_PARSER` 替换 `URI::Parser.new` 的地方。

示例

# bad
URI::Parser.new

# good
URI::DEFAULT_PARSER