Class: RuboCop::Cop::Style::CollectionQuerying

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
RangeHelp
Defined in:
lib/rubocop/cop/style/collection_querying.rb

Overview

Prefer ‘Enumerable` predicate methods over expressions with `count`.

The cop checks calls to ‘count` without arguments, or with a block. It doesn’t register offenses for ‘count` with a positional argument because its behavior differs from predicate methods (`count` matches the argument using `==`, while `any?`, `none?` and `one?` use `===`).

NOTE: This cop doesn’t check ‘length` and `size` methods because they would yield false positives. For example, `String` implements `length` and `size`, but it doesn’t include ‘Enumerable`.

Examples:


# bad
x.count.positive?
x.count > 0
x.count != 0

x.count(&:foo?).positive?
x.count { |item| item.foo? }.positive?

# good
x.any?

x.any?(&:foo?)
x.any? { |item| item.foo? }

# bad
x.count.zero?
x.count == 0

# good
x.none?

# bad
x.count == 1
x.one?

AllCops:ActiveSupportExtensionsEnabled: false (default)


# good
x.count > 1

AllCops:ActiveSupportExtensionsEnabled: true


# bad
x.count > 1

# good
x.many?

Constant Summary collapse

MSG =
'Use `%<prefer>s` instead.'
RESTRICT_ON_SEND =
%i[positive? > != zero? ==].freeze
REPLACEMENTS =
{
  [:positive?, nil] => :any?,
  [:>, 0] => :any?,
  [:!=, 0] => :any?,
  [:zero?, nil] => :none?,
  [:==, 0] => :none?,
  [:==, 1] => :one?,
  [:>, 1] => :many?
}.freeze

Constants included from RangeHelp

RangeHelp::BYTE_ORDER_MARK, RangeHelp::NOT_GIVEN

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source

Instance Method Summary collapse

Methods included from AutoCorrector

support_autocorrect?

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, #always_autocorrect?, autocorrect_incompatible_with, badge, #begin_investigation, #callbacks_needed, callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #contextual_autocorrect?, #cop_config, #cop_name, cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #message, #offenses, #on_investigation_end, #on_new_investigation, #on_other_file, #parse, #parser_engine, #ready, #relevant_file?, requires_gem, #string_literals_frozen_by_default?, support_autocorrect?, support_multiple_source?, #target_gem_version, #target_rails_version, #target_ruby_version

Methods included from ExcludeLimit

#exclude_limit

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

silence_warnings

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Instance Method Details

#count_predicate(node) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/rubocop/cop/style/collection_querying.rb', line 115

def_node_matcher :count_predicate, <<~PATTERN
  (send
    {
      (any_block $(call !nil? :count) _ _)
      $(call !nil? :count (block-pass _)?)
    }
    {
      :positive? |
      :> (int 0) |
      :!= (int 0) |
      :zero? |
      :== (int 0) |
      :== (int 1) |
      :> (int 1)
    })
PATTERN

#on_send(node) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/rubocop/cop/style/collection_querying.rb', line 132

def on_send(node)
  return unless (count_node = count_predicate(node))

  replacement_method = replacement_method(node)

  return unless replacement_supported?(replacement_method)

  offense_range = count_node.loc.selector.join(node.source_range.end)
  add_offense(offense_range,
              message: format(MSG, prefer: replacement_method)) do |corrector|
    corrector.replace(count_node.loc.selector, replacement_method)
    corrector.remove(removal_range(node))
  end
end