class RubbyCop::Cop::Performance::Count
This cop is used to identify usages of `count` on an `Enumerable` that follow calls to `select` or `reject`. Querying logic can instead be passed to the `count` call.
@example
# 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
`ActiveRecord` compatibility: `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 {…}`.
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 }
Constants
- MSG
Public Instance Methods
on_send(node)
click to toggle source
# File lib/rubbycop/cop/performance/count.rb, line 52 def on_send(node) return if rails_safe_mode? count_candidate?(node) do |selector_node, selector, counter| return unless eligible_node?(node) range = source_starting_at(node) do selector_node.loc.selector.begin_pos end add_offense(node, range, format(MSG, selector, counter)) end end
Private Instance Methods
autocorrect(node)
click to toggle source
# File lib/rubbycop/cop/performance/count.rb, line 68 def autocorrect(node) selector_node, selector, _counter = count_candidate?(node) selector_loc = selector_node.loc.selector return if selector == :reject range = source_starting_at(node) { |n| n.loc.dot.begin_pos } lambda do |corrector| corrector.remove(range) corrector.replace(selector_loc, 'count') end end
eligible_node?(node)
click to toggle source
# File lib/rubbycop/cop/performance/count.rb, line 82 def eligible_node?(node) !(node.parent && node.parent.block_type?) end
source_starting_at(node) { |node| ... }
click to toggle source
# File lib/rubbycop/cop/performance/count.rb, line 86 def source_starting_at(node) begin_pos = if block_given? yield node else node.source_range.begin_pos end range_between(begin_pos, node.source_range.end_pos) end