123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Performance::CompareWithBlock

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, AutoCorrector, Base
Instance Chain:
self, RangeHelp, Base
Inherits: Base
  • Object
Defined in: lib/rubocop/cop/performance/compare_with_block.rb

Overview

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:

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

Constant Summary

Instance Method Summary

Instance Method Details

#compare_range(send, node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/compare_with_block.rb', line 114

def compare_range(send, node)
  range_between(send.loc.selector.begin_pos, node.loc.end.end_pos)
end

#message(send, method, var_a, var_b, args) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/compare_with_block.rb', line 91

def message(send, method, var_a, var_b, args)
  compare_method     = send.method_name
  replacement_method = REPLACEMENT[compare_method]
  if method == :[]
    key = args.first
    instead = " { |a| a[#{key.source}] }"
    str_a = "#{var_a}[#{key.source}]"
    str_b = "#{var_b}[#{key.source}]"
  else
    instead = "(&:#{method})"
    str_a = "#{var_a}.#{method}"
    str_b = "#{var_b}.#{method}"
  end
  format(MSG, compare_method: compare_method,
              replacement_method: replacement_method,
              instead: instead,
              var_a: var_a,
              var_b: var_b,
              str_a: str_a,
              str_b: str_b)
end

#on_block(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/compare_with_block.rb', line 55

def on_block(node)
  compare?(node) do |send, var_a, var_b, body|
    replaceable_body?(body, var_a, var_b) do |method, args_a, args_b|
      return unless slow_compare?(method, args_a, args_b)

      range = compare_range(send, node)

      add_offense(range, message: message(send, method, var_a, var_b, args_a)) do |corrector|
        replacement = if method == :[]
                        "#{REPLACEMENT[send.method_name]} { |a| a[#{args_a.first.source}] }"
                      else
                        "#{REPLACEMENT[send.method_name]}(&:#{method})"
                      end
        corrector.replace(range, replacement)
      end
    end
  end
end

#slow_compare?(method, args_a, args_b) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/compare_with_block.rb', line 76

def slow_compare?(method, args_a, args_b)
  return false unless args_a == args_b

  if method == :[]
    return false unless args_a.size == 1

    key = args_a.first
    return false unless %i[sym str int].include?(key.type)
  else
    return false unless args_a.empty?
  end
  true
end