Class: RuboCop::Cop::Style::InverseMethods

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

Overview

Check for usages of not (not or !) called on a method when an inverse of that method can be used instead.

Methods that can be inverted by a not (not or !) should be defined in InverseMethods.

Methods that are inverted by inverting the return of the block that is passed to the method should be defined in InverseBlocks.

Examples:

# bad
!foo.none?
!foo.any? { |f| f.even? }
!foo.blank?
!(foo == bar)
foo.select { |f| !f.even? }
foo.reject { |f| f != 7 }

# good
foo.none?
foo.blank?
foo.any? { |f| f.even? }
foo != bar
foo == bar
!!('foo' =~ /^\w+$/)
!(foo.class < Numeric) # Checking class hierarchy is allowed
# Blocks with guard clauses are ignored:
foo.select do |f|
  next if f.zero?
  f != 1
end

Cop Safety Information:

  • This cop is unsafe because it cannot be guaranteed that the method and its inverse method are both defined on receiver, and also are actually inverse of each other.

Constant Summary collapse

MSG =
'Use `%<inverse>s` instead of inverting `%<method>s`.'
CLASS_COMPARISON_METHODS =
%i[<= >= < >].freeze
EQUALITY_METHODS =
%i[== != =~ !~ <= >= < >].freeze
NEGATED_EQUALITY_METHODS =
%i[!= !~].freeze
CAMEL_CASE =
/[A-Z]+[a-z]+/.freeze
RESTRICT_ON_SEND =
[:!].freeze

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source

Class Method Summary collapse

Instance Method Summary collapse

Methods included from AutoCorrector

support_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, badge, #begin_investigation, #callbacks_needed, callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #cop_config, cop_name, #cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #offenses, #on_investigation_end, #on_new_investigation, #on_other_file, #parse, #ready, #relevant_file?, support_autocorrect?, support_multiple_source?, #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 Util

silence_warnings

Constructor Details

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

Class Method Details

.autocorrect_incompatible_withObject



56
57
58
# File 'lib/rubocop/cop/style/inverse_methods.rb', line 56

def self.autocorrect_incompatible_with
  [Style::Not, Style::SymbolProc]
end

Instance Method Details

#inverse_block?(node) ⇒ Object



70
71
72
73
74
75
76
# File 'lib/rubocop/cop/style/inverse_methods.rb', line 70

def_node_matcher :inverse_block?, <<~PATTERN
  ({block numblock} $(send (...) $_) ... { $(send ... :!)
                                           $(send (...) {:!= :!~} ...)
                                           (begin ... $(send ... :!))
                                           (begin ... $(send (...) {:!= :!~} ...))
                                         })
PATTERN

#inverse_candidate?(node) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/rubocop/cop/style/inverse_methods.rb', line 61

def_node_matcher :inverse_candidate?, <<~PATTERN
  {
    (send $(send $(...) $_ $...) :!)
    (send ({block numblock} $(send $(...) $_) $...) :!)
    (send (begin $(send $(...) $_ $...)) :!)
  }
PATTERN

#on_block(node) ⇒ Object Also known as: on_numblock



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/rubocop/cop/style/inverse_methods.rb', line 91

def on_block(node)
  inverse_block?(node) do |_method_call, method, block|
    return unless inverse_blocks.key?(method)
    return if negated?(node) && negated?(node.parent)
    return if node.each_node(:next).any?

    # Inverse method offenses inside of the block of an inverse method
    # offense, such as `y.reject { |key, _value| !(key =~ /c\d/) }`,
    # can cause autocorrection to apply improper corrections.
    ignore_node(block)
    add_offense(node, message: message(method, inverse_blocks[method])) do |corrector|
      correct_inverse_block(corrector, node)
    end
  end
end

#on_send(node) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rubocop/cop/style/inverse_methods.rb', line 78

def on_send(node)
  inverse_candidate?(node) do |_method_call, lhs, method, rhs|
    return unless inverse_methods.key?(method)
    return if negated?(node)
    return if part_of_ignored_node?(node)
    return if possible_class_hierarchy_check?(lhs, rhs, method)

    add_offense(node, message: message(method, inverse_methods[method])) do |corrector|
      correct_inverse_method(corrector, node)
    end
  end
end