From ae249ec282c7552d5658c11a8310180c4ce43343 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Fri, 26 Jan 2024 13:52:46 -0800 Subject: [PATCH] Vendor InverseMethods cop --- Library/.rubocop.yml | 11 ++--- Library/Homebrew/rubocops/all.rb | 1 + Library/Homebrew/rubocops/negate_include.rb | 43 +++++++++++++++++++ .../test/rubocops/negate_include_spec.rb | 29 +++++++++++++ 4 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 Library/Homebrew/rubocops/negate_include.rb create mode 100644 Library/Homebrew/test/rubocops/negate_include_spec.rb diff --git a/Library/.rubocop.yml b/Library/.rubocop.yml index 65011773b3..d2d2c77b76 100644 --- a/Library/.rubocop.yml +++ b/Library/.rubocop.yml @@ -64,6 +64,12 @@ Homebrew/CompactBlank: Homebrew/MoveToExtendOS: Enabled: false +Homebrew/NegateInclude: + Exclude: + # `exclude?` is not available here: + - "Homebrew/standalone/init.rb" + - "Homebrew/rubocops/**/*" + # `system` is a special case and aligns on second argument, so allow this for formulae. Layout/ArgumentAlignment: Exclude: @@ -339,13 +345,8 @@ Style/HashAsLastArrayItem: - "**/Formula/**/*.rb" Style/InverseMethods: - Exclude: - # Core extensions are not available here: - - "Homebrew/standalone/init.rb" - - "Homebrew/rubocops/**/*" InverseMethods: :blank?: :present? - :exclude?: :include? Style/InvertibleUnlessCondition: Enabled: true diff --git a/Library/Homebrew/rubocops/all.rb b/Library/Homebrew/rubocops/all.rb index 53bc42a57e..6e69c8724e 100644 --- a/Library/Homebrew/rubocops/all.rb +++ b/Library/Homebrew/rubocops/all.rb @@ -7,6 +7,7 @@ require_relative "blank" require_relative "compact_blank" require_relative "io_read" require_relative "move_to_extend_os" +require_relative "negate_include" require_relative "presence" require_relative "present" require_relative "safe_navigation_with_blank" diff --git a/Library/Homebrew/rubocops/negate_include.rb b/Library/Homebrew/rubocops/negate_include.rb new file mode 100644 index 0000000000..ccfec44c7c --- /dev/null +++ b/Library/Homebrew/rubocops/negate_include.rb @@ -0,0 +1,43 @@ +# typed: true +# frozen_string_literal: true + +module RuboCop + module Cop + module Homebrew + # Enforces the use of `collection.exclude?(obj)` + # over `!collection.include?(obj)`. + # + # @note + # This cop is unsafe because false positive will occur for + # receiver objects that do not have an `exclude?` method. (e.g. `IPAddr`) + # + # @example + # # bad + # !array.include?(2) + # !hash.include?(:key) + # + # # good + # array.exclude?(2) + # hash.exclude?(:key) + # + class NegateInclude < Base + extend AutoCorrector + + MSG = "Use `.exclude?` and remove the negation part." + RESTRICT_ON_SEND = [:!].freeze + + def_node_matcher :negate_include_call?, <<~PATTERN + (send (send $!nil? :include? $_) :!) + PATTERN + + def on_send(node) + return unless (receiver, obj = negate_include_call?(node)) + + add_offense(node) do |corrector| + corrector.replace(node, "#{receiver.source}.exclude?(#{obj.source})") + end + end + end + end + end +end diff --git a/Library/Homebrew/test/rubocops/negate_include_spec.rb b/Library/Homebrew/test/rubocops/negate_include_spec.rb new file mode 100644 index 0000000000..0d3799913f --- /dev/null +++ b/Library/Homebrew/test/rubocops/negate_include_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require "rubocops/negate_include" + +RSpec.describe RuboCop::Cop::Homebrew::NegateInclude, :config do + it "registers an offense and corrects when using `!include?`" do + expect_offense(<<~RUBY) + !array.include?(2) + ^^^^^^^^^^^^^^^^^^ Use `.exclude?` and remove the negation part. + RUBY + + expect_correction(<<~RUBY) + array.exclude?(2) + RUBY + end + + it "does not register an offense when using `!include?` without receiver" do + expect_no_offenses(<<~RUBY) + !include?(2) + RUBY + end + + it "does not register an offense when using `include?` or `exclude?`" do + expect_no_offenses(<<~RUBY) + array.include?(2) + array.exclude?(2) + RUBY + end +end