class RuboCop::Cop::Style::UnneededSort
This cop is used to identify instances of sorting and then taking only the first or last element. The same behavior can be accomplished without a relatively expensive sort by using `Enumerable#min` instead of sorting and taking the first element and `Enumerable#max` instead of sorting and taking the last element. Similarly, `Enumerable#min_by` and `Enumerable#max_by` can replace `Enumerable#sort_by` calls after which only the first or last element is used.
@example
# bad [2, 1, 3].sort.first [2, 1, 3].sort[0] [2, 1, 3].sort.at(0) [2, 1, 3].sort.slice(0) # good [2, 1, 3].min # bad [2, 1, 3].sort.last [2, 1, 3].sort[-1] [2, 1, 3].sort.at(-1) [2, 1, 3].sort.slice(-1) # good [2, 1, 3].max # bad arr.sort_by(&:foo).first arr.sort_by(&:foo)[0] arr.sort_by(&:foo).at(0) arr.sort_by(&:foo).slice(0) # good arr.min_by(&:foo) # bad arr.sort_by(&:foo).last arr.sort_by(&:foo)[-1] arr.sort_by(&:foo).at(-1) arr.sort_by(&:foo).slice(-1) # good arr.max_by(&:foo)
Constants
- MSG
Public Instance Methods
autocorrect(node)
click to toggle source
# File lib/rubocop/cop/style/unneeded_sort.rb, line 89 def autocorrect(node) sort_node, sorter, accessor = unneeded_sort?(node) lambda do |corrector| # Remove accessor, e.g. `first` or `[-1]`. corrector.remove( range_between( accessor_start(node), node.loc.expression.end_pos ) ) # Replace "sort" or "sort_by" with the appropriate min/max method. corrector.replace( sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)) ) end end
on_send(node)
click to toggle source
# File lib/rubocop/cop/style/unneeded_sort.rb, line 74 def on_send(node) unneeded_sort?(node) do |sort_node, sorter, accessor| range = range_between( sort_node.loc.selector.begin_pos, node.loc.expression.end_pos ) add_offense(node, location: range, message: message(node, sorter, accessor)) end end
Private Instance Methods
accessor_start(node)
click to toggle source
This gets the start of the accessor whether it has a dot (e.g. `.first`) or doesn't (e.g. `[0]`)
# File lib/rubocop/cop/style/unneeded_sort.rb, line 155 def accessor_start(node) if node.loc.dot node.loc.dot.begin_pos else node.loc.selector.begin_pos end end
arg_node(node)
click to toggle source
# File lib/rubocop/cop/style/unneeded_sort.rb, line 145 def arg_node(node) node.arguments.first end
arg_value(node)
click to toggle source
# File lib/rubocop/cop/style/unneeded_sort.rb, line 149 def arg_value(node) arg_node(node).nil? ? nil : arg_node(node).node_parts.first end
base(accessor, arg)
click to toggle source
# File lib/rubocop/cop/style/unneeded_sort.rb, line 129 def base(accessor, arg) if accessor == :first || (arg&.zero?) 'min' elsif accessor == :last || arg == -1 'max' end end
message(node, sorter, accessor)
click to toggle source
# File lib/rubocop/cop/style/unneeded_sort.rb, line 111 def message(node, sorter, accessor) accessor_source = range_between( node.loc.selector.begin_pos, node.loc.expression.end_pos ).source format(MSG, suggestion: suggestion(sorter, accessor, arg_value(node)), sorter: sorter, accessor_source: accessor_source) end
suffix(sorter)
click to toggle source
# File lib/rubocop/cop/style/unneeded_sort.rb, line 137 def suffix(sorter) if sorter == :sort '' elsif sorter == :sort_by '_by' end end
suggestion(sorter, accessor, arg)
click to toggle source
# File lib/rubocop/cop/style/unneeded_sort.rb, line 125 def suggestion(sorter, accessor, arg) base(accessor, arg) + suffix(sorter) end