Fix violations
This commit is contained in:
		
							parent
							
								
									c354377f3e
								
							
						
					
					
						commit
						eeb31d3050
					
				@ -10,14 +10,10 @@ class PATH
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  delegate each: :@paths
 | 
					  delegate each: :@paths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
  # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
  Element = T.type_alias { T.nilable(T.any(Pathname, String, PATH)) }
 | 
					  Element = T.type_alias { T.nilable(T.any(Pathname, String, PATH)) }
 | 
				
			||||||
  private_constant :Element
 | 
					  private_constant :Element
 | 
				
			||||||
  Elements = T.type_alias { T.any(Element, T::Array[Element]) }
 | 
					  Elements = T.type_alias { T.any(Element, T::Array[Element]) }
 | 
				
			||||||
  private_constant :Elements
 | 
					  private_constant :Elements
 | 
				
			||||||
  # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  sig { params(paths: Elements).void }
 | 
					  sig { params(paths: Elements).void }
 | 
				
			||||||
  def initialize(*paths)
 | 
					  def initialize(*paths)
 | 
				
			||||||
    @paths = parse(paths)
 | 
					    @paths = parse(paths)
 | 
				
			||||||
 | 
				
			|||||||
@ -10,11 +10,7 @@ module Cask
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    requires_ancestor { Kernel }
 | 
					    requires_ancestor { Kernel }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
    # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
    Paths = T.type_alias { T.any(String, Pathname, T::Array[T.any(String, Pathname)]) }
 | 
					    Paths = T.type_alias { T.any(String, Pathname, T::Array[T.any(String, Pathname)]) }
 | 
				
			||||||
    # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sig { params(paths: Paths, permissions_str: String).void }
 | 
					    sig { params(paths: Paths, permissions_str: String).void }
 | 
				
			||||||
    def set_permissions(paths, permissions_str)
 | 
					    def set_permissions(paths, permissions_str)
 | 
				
			||||||
      full_paths = remove_nonexistent(paths)
 | 
					      full_paths = remove_nonexistent(paths)
 | 
				
			||||||
 | 
				
			|||||||
@ -6,16 +6,12 @@ require "ostruct"
 | 
				
			|||||||
module Homebrew
 | 
					module Homebrew
 | 
				
			||||||
  module CLI
 | 
					  module CLI
 | 
				
			||||||
    class Args < OpenStruct
 | 
					    class Args < OpenStruct
 | 
				
			||||||
      # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
      # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
      # Represents a processed option. The array elements are:
 | 
					      # Represents a processed option. The array elements are:
 | 
				
			||||||
      #   0: short option name (e.g. "-d")
 | 
					      #   0: short option name (e.g. "-d")
 | 
				
			||||||
      #   1: long option name (e.g. "--debug")
 | 
					      #   1: long option name (e.g. "--debug")
 | 
				
			||||||
      #   2: option description (e.g. "Print debugging information")
 | 
					      #   2: option description (e.g. "Print debugging information")
 | 
				
			||||||
      #   3: whether the option is hidden
 | 
					      #   3: whether the option is hidden
 | 
				
			||||||
      OptionsType = T.type_alias { T::Array[[String, T.nilable(String), String, T::Boolean]] }
 | 
					      OptionsType = T.type_alias { T::Array[[String, T.nilable(String), String, T::Boolean]] }
 | 
				
			||||||
      # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      sig { returns(T::Array[String]) }
 | 
					      sig { returns(T::Array[String]) }
 | 
				
			||||||
      attr_reader :options_only, :flags_only
 | 
					      attr_reader :options_only, :flags_only
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -13,10 +13,7 @@ require "utils/formatter"
 | 
				
			|||||||
module Homebrew
 | 
					module Homebrew
 | 
				
			||||||
  module CLI
 | 
					  module CLI
 | 
				
			||||||
    class Parser
 | 
					    class Parser
 | 
				
			||||||
      # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
      # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
      ArgType = T.type_alias { T.any(NilClass, Symbol, T::Array[String], T::Array[Symbol]) }
 | 
					      ArgType = T.type_alias { T.any(NilClass, Symbol, T::Array[String], T::Array[Symbol]) }
 | 
				
			||||||
      # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
      HIDDEN_DESC_PLACEHOLDER = "@@HIDDEN@@"
 | 
					      HIDDEN_DESC_PLACEHOLDER = "@@HIDDEN@@"
 | 
				
			||||||
      SYMBOL_TO_USAGE_MAPPING = T.let({
 | 
					      SYMBOL_TO_USAGE_MAPPING = T.let({
 | 
				
			||||||
        text_or_regex: "<text>|`/`<regex>`/`",
 | 
					        text_or_regex: "<text>|`/`<regex>`/`",
 | 
				
			||||||
 | 
				
			|||||||
@ -5,8 +5,6 @@ require "test_runner_formula"
 | 
				
			|||||||
require "github_runner"
 | 
					require "github_runner"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GitHubRunnerMatrix
 | 
					class GitHubRunnerMatrix
 | 
				
			||||||
  # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
  # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
  RunnerSpec = T.type_alias { T.any(LinuxRunnerSpec, MacOSRunnerSpec) }
 | 
					  RunnerSpec = T.type_alias { T.any(LinuxRunnerSpec, MacOSRunnerSpec) }
 | 
				
			||||||
  private_constant :RunnerSpec
 | 
					  private_constant :RunnerSpec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -36,8 +34,6 @@ class GitHubRunnerMatrix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  RunnerSpecHash = T.type_alias { T.any(LinuxRunnerSpecHash, MacOSRunnerSpecHash) }
 | 
					  RunnerSpecHash = T.type_alias { T.any(LinuxRunnerSpecHash, MacOSRunnerSpecHash) }
 | 
				
			||||||
  private_constant :RunnerSpecHash
 | 
					  private_constant :RunnerSpecHash
 | 
				
			||||||
  # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  sig { returns(T::Array[GitHubRunner]) }
 | 
					  sig { returns(T::Array[GitHubRunner]) }
 | 
				
			||||||
  attr_reader :runners
 | 
					  attr_reader :runners
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -13,12 +13,8 @@ module Tapioca
 | 
				
			|||||||
        end.flatten.freeze, T::Array[String]
 | 
					        end.flatten.freeze, T::Array[String]
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
      # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
      Parsable = T.type_alias { T.any(T.class_of(Homebrew::CLI::Args), T.class_of(Homebrew::AbstractCommand)) }
 | 
					      Parsable = T.type_alias { T.any(T.class_of(Homebrew::CLI::Args), T.class_of(Homebrew::AbstractCommand)) }
 | 
				
			||||||
      ConstantType = type_member { { fixed: Parsable } }
 | 
					      ConstantType = type_member { { fixed: Parsable } }
 | 
				
			||||||
      # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      sig { override.returns(T::Enumerable[Parsable]) }
 | 
					      sig { override.returns(T::Enumerable[Parsable]) }
 | 
				
			||||||
      def self.gather_constants
 | 
					      def self.gather_constants
 | 
				
			||||||
        # require all the commands to ensure the command subclasses are defined
 | 
					        # require all the commands to ensure the command subclasses are defined
 | 
				
			||||||
 | 
				
			|||||||
@ -7,10 +7,7 @@ require "env_config"
 | 
				
			|||||||
module Tapioca
 | 
					module Tapioca
 | 
				
			||||||
  module Compilers
 | 
					  module Compilers
 | 
				
			||||||
    class EnvConfig < Tapioca::Dsl::Compiler
 | 
					    class EnvConfig < Tapioca::Dsl::Compiler
 | 
				
			||||||
      # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
      # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
      ConstantType = type_member { { fixed: Module } }
 | 
					      ConstantType = type_member { { fixed: Module } }
 | 
				
			||||||
      # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      sig { override.returns(T::Enumerable[Module]) }
 | 
					      sig { override.returns(T::Enumerable[Module]) }
 | 
				
			||||||
      def self.gather_constants = [Homebrew::EnvConfig]
 | 
					      def self.gather_constants = [Homebrew::EnvConfig]
 | 
				
			||||||
 | 
				
			|||||||
@ -8,13 +8,9 @@ require_relative "../../../rubocops"
 | 
				
			|||||||
module Tapioca
 | 
					module Tapioca
 | 
				
			||||||
  module Compilers
 | 
					  module Compilers
 | 
				
			||||||
    class RuboCop < Tapioca::Dsl::Compiler
 | 
					    class RuboCop < Tapioca::Dsl::Compiler
 | 
				
			||||||
      # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
      # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
      # This should be a module whose singleton class contains RuboCop::AST::NodePattern::Macros,
 | 
					      # This should be a module whose singleton class contains RuboCop::AST::NodePattern::Macros,
 | 
				
			||||||
      #   but I don't know how to express that in Sorbet.
 | 
					      #   but I don't know how to express that in Sorbet.
 | 
				
			||||||
      ConstantType = type_member { { fixed: Module } }
 | 
					      ConstantType = type_member { { fixed: Module } }
 | 
				
			||||||
      # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      sig { override.returns(T::Enumerable[Module]) }
 | 
					      sig { override.returns(T::Enumerable[Module]) }
 | 
				
			||||||
      def self.gather_constants
 | 
					      def self.gather_constants
 | 
				
			||||||
        all_modules.select do |klass|
 | 
					        all_modules.select do |klass|
 | 
				
			||||||
 | 
				
			|||||||
@ -7,10 +7,7 @@ require "utils/tty"
 | 
				
			|||||||
module Tapioca
 | 
					module Tapioca
 | 
				
			||||||
  module Compilers
 | 
					  module Compilers
 | 
				
			||||||
    class Tty < Tapioca::Dsl::Compiler
 | 
					    class Tty < Tapioca::Dsl::Compiler
 | 
				
			||||||
      # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
      # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
      ConstantType = type_member { { fixed: Module } }
 | 
					      ConstantType = type_member { { fixed: Module } }
 | 
				
			||||||
      # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      sig { override.returns(T::Enumerable[Module]) }
 | 
					      sig { override.returns(T::Enumerable[Module]) }
 | 
				
			||||||
      def self.gather_constants = [::Tty]
 | 
					      def self.gather_constants = [::Tty]
 | 
				
			||||||
 | 
				
			|||||||
@ -1,630 +0,0 @@
 | 
				
			|||||||
# frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
require "rubocops/extend/mutable_constant_exclude_unfreezable"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RSpec.describe(RuboCop::Cop::Style::MutableConstant, :config) do
 | 
					 | 
				
			||||||
  let(:prefix) { nil }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  shared_examples "mutable objects" do |o|
 | 
					 | 
				
			||||||
    context "when using T.let" do
 | 
					 | 
				
			||||||
      context "when assigning with =" do
 | 
					 | 
				
			||||||
        it "registers an offense for #{o} assigned to a constant " \
 | 
					 | 
				
			||||||
           "and corrects by adding .freeze" do
 | 
					 | 
				
			||||||
          expect_offense([prefix, <<~RUBY].compact.join("\n"), o:)
 | 
					 | 
				
			||||||
            CONST = T.let(%<o>s, Object)
 | 
					 | 
				
			||||||
                          ^{o} Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
          expect_correction([prefix, <<~RUBY].compact.join("\n"))
 | 
					 | 
				
			||||||
            CONST = T.let(#{o}.freeze, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when assigning with ||=" do
 | 
					 | 
				
			||||||
        it "registers an offense for #{o} assigned to a constant " \
 | 
					 | 
				
			||||||
           "and corrects by adding .freeze" do
 | 
					 | 
				
			||||||
          expect_offense([prefix, <<~RUBY].compact.join("\n"), o:)
 | 
					 | 
				
			||||||
            CONST ||= T.let(%<o>s, Object)
 | 
					 | 
				
			||||||
                            ^{o} Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
          expect_correction([prefix, <<~RUBY].compact.join("\n"))
 | 
					 | 
				
			||||||
            CONST ||= T.let(#{o}.freeze, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "when not using T.let" do
 | 
					 | 
				
			||||||
      context "when assigning with =" do
 | 
					 | 
				
			||||||
        it "registers an offense for #{o} assigned to a constant " \
 | 
					 | 
				
			||||||
           "and corrects by adding .freeze" do
 | 
					 | 
				
			||||||
          expect_offense([prefix, <<~RUBY].compact.join("\n"), o:)
 | 
					 | 
				
			||||||
            CONST = %<o>s
 | 
					 | 
				
			||||||
                    ^{o} Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
          expect_correction([prefix, <<~RUBY].compact.join("\n"))
 | 
					 | 
				
			||||||
            CONST = #{o}.freeze
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when assigning with ||=" do
 | 
					 | 
				
			||||||
        it "registers an offense for #{o} assigned to a constant " \
 | 
					 | 
				
			||||||
           "and corrects by adding .freeze" do
 | 
					 | 
				
			||||||
          expect_offense([prefix, <<~RUBY].compact.join("\n"), o:)
 | 
					 | 
				
			||||||
            CONST ||= %<o>s
 | 
					 | 
				
			||||||
                      ^{o} Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
          expect_correction([prefix, <<~RUBY].compact.join("\n"))
 | 
					 | 
				
			||||||
            CONST ||= #{o}.freeze
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  shared_examples "immutable objects" do |o|
 | 
					 | 
				
			||||||
    context "when using T.let" do
 | 
					 | 
				
			||||||
      it "allows #{o} to be assigned to a constant" do
 | 
					 | 
				
			||||||
        const = if o.start_with?("<<~HERE")
 | 
					 | 
				
			||||||
          heredoc = o.delete_prefix("<<~HERE")
 | 
					 | 
				
			||||||
          "CONST = T.let(<<~HERE, Object)#{heredoc}"
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
          "CONST = T.let(#{o.chomp}, Object)"
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
        source = [prefix, const].compact.join("\n")
 | 
					 | 
				
			||||||
        expect_no_offenses(source)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "allows #{o} to be ||= to a constant" do
 | 
					 | 
				
			||||||
        const = if o.start_with?("<<~HERE")
 | 
					 | 
				
			||||||
          heredoc = o.delete_prefix("<<~HERE")
 | 
					 | 
				
			||||||
          "CONST ||= T.let(<<~HERE, Object)#{heredoc}"
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
          "CONST ||= T.let(#{o.chomp}, Object)"
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
        source = [prefix, const].compact.join("\n")
 | 
					 | 
				
			||||||
        expect_no_offenses(source)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "when not using T.let" do
 | 
					 | 
				
			||||||
      it "allows #{o} to be assigned to a constant" do
 | 
					 | 
				
			||||||
        source = [prefix, "CONST = #{o}"].compact.join("\n")
 | 
					 | 
				
			||||||
        expect_no_offenses(source)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "allows #{o} to be ||= to a constant" do
 | 
					 | 
				
			||||||
        source = [prefix, "CONST ||= #{o}"].compact.join("\n")
 | 
					 | 
				
			||||||
        expect_no_offenses(source)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  shared_examples "literals that are frozen" do |o|
 | 
					 | 
				
			||||||
    let(:prefix) { o }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "[1, 2, 3]"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "%w(a b c)"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "{ a: 1, b: 2 }"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "'str'"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", %Q("top#{1 + 2}")
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "1"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "1.5"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", ":sym"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "FOO + BAR"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "FOO - BAR"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "'foo' + 'bar'"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "ENV['foo']"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "::ENV['foo']"
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  shared_examples "literals that are not frozen" do |o|
 | 
					 | 
				
			||||||
    let(:prefix) { o }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "[1, 2, 3]"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "%w(a b c)"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "{ a: 1, b: 2 }"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "'str'"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", %Q("top#{1 + 2}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "1"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "1.5"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", ":sym"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "FOO + BAR"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "FOO - BAR"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "'foo' + 'bar'"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "ENV['foo']"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "::ENV['foo']"
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  shared_examples "string literal" do
 | 
					 | 
				
			||||||
    # TODO : It is not yet decided when frozen string will be the default.
 | 
					 | 
				
			||||||
    # It has been abandoned in the Ruby 3.0 period, but may default in
 | 
					 | 
				
			||||||
    # the long run. So these tests are left with a provisional value of 4.0.
 | 
					 | 
				
			||||||
    if RuboCop::TargetRuby.supported_versions.include?(4.0)
 | 
					 | 
				
			||||||
      context "when the target ruby version >= 4.0" do
 | 
					 | 
				
			||||||
        let(:ruby_version) { 4.0 }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        context "when the frozen string literal comment is missing" do
 | 
					 | 
				
			||||||
          it_behaves_like "immutable objects", %Q("#{a}")
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        context "when the frozen string literal comment is true" do
 | 
					 | 
				
			||||||
          let(:prefix) { "# frozen_string_literal: true" }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          it_behaves_like "immutable objects", %Q("#{a}")
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        context "when the frozen string literal comment is false" do
 | 
					 | 
				
			||||||
          let(:prefix) { "# frozen_string_literal: false" }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          it_behaves_like "immutable objects", %Q("#{a}")
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "with Ruby 3.0 or higher", :ruby30 do
 | 
					 | 
				
			||||||
      context "when the frozen string literal comment is missing" do
 | 
					 | 
				
			||||||
        it_behaves_like "mutable objects", %Q("#{a}")
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when the frozen string literal comment is true" do
 | 
					 | 
				
			||||||
        let(:prefix) { "# frozen_string_literal: true" }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it_behaves_like "mutable objects", %Q("#{a}")
 | 
					 | 
				
			||||||
        it_behaves_like "immutable objects", <<~RUBY
 | 
					 | 
				
			||||||
          <<~HERE
 | 
					 | 
				
			||||||
            foo
 | 
					 | 
				
			||||||
            bar
 | 
					 | 
				
			||||||
          HERE
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
        it "registers an offense when using interpolated heredoc constant" do
 | 
					 | 
				
			||||||
          expect_offense(<<~'RUBY')
 | 
					 | 
				
			||||||
            # frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CONST = T.let(<<~HERE, Object)
 | 
					 | 
				
			||||||
                          ^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
              foo #{use_interpolation}
 | 
					 | 
				
			||||||
              bar
 | 
					 | 
				
			||||||
            HERE
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it "does not register an offense when using a multiline string" do
 | 
					 | 
				
			||||||
          expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
            # frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CONST = T.let('foo' \
 | 
					 | 
				
			||||||
                    'bar', Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it "registers an offense when using a multiline string with interpolation" do
 | 
					 | 
				
			||||||
          expect_offense(<<~'RUBY')
 | 
					 | 
				
			||||||
            # frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CONST = T.let("#{foo}" \
 | 
					 | 
				
			||||||
                          ^^^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
                    'bar', Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when the frozen string literal comment is false" do
 | 
					 | 
				
			||||||
        let(:prefix) { "# frozen_string_literal: false" }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it_behaves_like "mutable objects", %Q("#{a}")
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "with Ruby 2.7 or lower", :ruby27 do
 | 
					 | 
				
			||||||
      context "when the frozen string literal comment is missing" do
 | 
					 | 
				
			||||||
        it_behaves_like "mutable objects", %Q("#{a}")
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when the frozen string literal comment is true" do
 | 
					 | 
				
			||||||
        let(:prefix) { "# frozen_string_literal: true" }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it_behaves_like "immutable objects", %Q("#{a}")
 | 
					 | 
				
			||||||
        it_behaves_like "immutable objects", <<~RUBY
 | 
					 | 
				
			||||||
          <<~HERE
 | 
					 | 
				
			||||||
            foo
 | 
					 | 
				
			||||||
            bar
 | 
					 | 
				
			||||||
          HERE
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
        it "does not register an offense when using interpolated heredoc constant" do
 | 
					 | 
				
			||||||
          expect_no_offenses(<<~'RUBY')
 | 
					 | 
				
			||||||
            # frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CONST = T.let(<<~HERE, Object)
 | 
					 | 
				
			||||||
              foo #{use_interpolation}
 | 
					 | 
				
			||||||
              bar
 | 
					 | 
				
			||||||
            HERE
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it "does not register an offense when using a multiline string" do
 | 
					 | 
				
			||||||
          expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
            # frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            CONST = T.let('foo' \
 | 
					 | 
				
			||||||
                    'bar', Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when the frozen string literal comment is false" do
 | 
					 | 
				
			||||||
        let(:prefix) { "# frozen_string_literal: false" }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it_behaves_like "mutable objects", %Q("#{a}")
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  context "with Strict: false" do
 | 
					 | 
				
			||||||
    let(:cop_config) { { "EnforcedStyle" => "literals" } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "[1, 2, 3]"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "%w(a b c)"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "{ a: 1, b: 2 }"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "'str'"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", %Q("top#{1 + 2}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "1"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "1.5"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", ":sym"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "FOO + BAR"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "FOO - BAR"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "'foo' + 'bar'"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "ENV['foo']"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "::ENV['foo']"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it "allows method call assignments" do
 | 
					 | 
				
			||||||
      expect_no_offenses("TOP_TEST = Something.new")
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "when assigning an array without brackets" do
 | 
					 | 
				
			||||||
      it "does not insert brackets for %w() arrays" do
 | 
					 | 
				
			||||||
        expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
          XXX = T.let(%w(YYY ZZZ), Object)
 | 
					 | 
				
			||||||
                      ^^^^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
          XXX = T.let(%w(YYY ZZZ).freeze, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Ruby 3.0's Regexp and Range literals are frozen.
 | 
					 | 
				
			||||||
    #
 | 
					 | 
				
			||||||
    # https://bugs.ruby-lang.org/issues/15504
 | 
					 | 
				
			||||||
    # https://bugs.ruby-lang.org/issues/16377
 | 
					 | 
				
			||||||
    context "with Ruby 3.0 or higher", :ruby30 do
 | 
					 | 
				
			||||||
      context "when assigning a regexp" do
 | 
					 | 
				
			||||||
        it "does not register an offense" do
 | 
					 | 
				
			||||||
          expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let(/regexp/, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when assigning a range (irange)" do
 | 
					 | 
				
			||||||
        it "does not register an offense when without parenthesis" do
 | 
					 | 
				
			||||||
          expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let(1..99, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it "does not register an offense when with parenthesis" do
 | 
					 | 
				
			||||||
          expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let((1..99), Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when assigning a range (erange)" do
 | 
					 | 
				
			||||||
        it "does not register an offense when without parenthesis" do
 | 
					 | 
				
			||||||
          expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let(1...99, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it "does not register an offense when with parenthesis" do
 | 
					 | 
				
			||||||
          expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let((1...99), Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when using shareable_constant_value" do
 | 
					 | 
				
			||||||
        it_behaves_like "literals that are frozen", "# shareable_constant_value: literal"
 | 
					 | 
				
			||||||
        it_behaves_like "literals that are frozen", "# shareable_constant_value: experimental_everything"
 | 
					 | 
				
			||||||
        it_behaves_like "literals that are frozen", "# shareable_constant_value: experimental_copy"
 | 
					 | 
				
			||||||
        it_behaves_like "literals that are not frozen", "# shareable_constant_value: none"
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "raises offense when shareable_constant_value is specified as an inline comment" do
 | 
					 | 
				
			||||||
        expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
          X = T.let([1, 2, 3], Object) # shareable_constant_value: literal
 | 
					 | 
				
			||||||
                    ^^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          Y = T.let([4, 5, 6], Object)
 | 
					 | 
				
			||||||
                    ^^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "raises offense only for shareable_constant_value as none when set in the order of: " \
 | 
					 | 
				
			||||||
         "literal, none and experimental_everything" do
 | 
					 | 
				
			||||||
        expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
          # shareable_constant_value: literal
 | 
					 | 
				
			||||||
          X = T.let([1, 2, 3], Object)
 | 
					 | 
				
			||||||
          # shareable_constant_value: none
 | 
					 | 
				
			||||||
          Y = T.let([4, 5, 6], Object)
 | 
					 | 
				
			||||||
                    ^^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          # shareable_constant_value: experimental_everything
 | 
					 | 
				
			||||||
          Z = T.let([7, 8, 9], Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "with Ruby 2.7 or lower", :ruby27 do
 | 
					 | 
				
			||||||
      context "when assigning a regexp" do
 | 
					 | 
				
			||||||
        it "registers an offense" do
 | 
					 | 
				
			||||||
          expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let(/regexp/, Object)
 | 
					 | 
				
			||||||
                        ^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let(/regexp/.freeze, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when assigning a range (irange) without parenthesis" do
 | 
					 | 
				
			||||||
        it "adds parenthesis when auto-correcting" do
 | 
					 | 
				
			||||||
          expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let(1..99, Object)
 | 
					 | 
				
			||||||
                        ^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let((1..99).freeze, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it "does not insert parenthesis to range enclosed in parentheses" do
 | 
					 | 
				
			||||||
          expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let((1..99), Object)
 | 
					 | 
				
			||||||
                        ^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let((1..99).freeze, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when assigning a range (erange) without parenthesis" do
 | 
					 | 
				
			||||||
        it "adds parenthesis when auto-correcting" do
 | 
					 | 
				
			||||||
          expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let(1...99, Object)
 | 
					 | 
				
			||||||
                        ^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let((1...99).freeze, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it "does not insert parenthesis to range enclosed in parentheses" do
 | 
					 | 
				
			||||||
          expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let((1...99), Object)
 | 
					 | 
				
			||||||
                        ^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
            XXX = T.let((1...99).freeze, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context "when using shareable_constant_values" do
 | 
					 | 
				
			||||||
        it_behaves_like "literals that are not frozen", "# shareable_constant_value: literal"
 | 
					 | 
				
			||||||
        it_behaves_like "literals that are not frozen", "# shareable_constant_value: experimental_everything"
 | 
					 | 
				
			||||||
        it_behaves_like "literals that are not frozen", "# shareable_constant_value: experimental_copy"
 | 
					 | 
				
			||||||
        it_behaves_like "literals that are not frozen", "# shareable_constant_value: none"
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it_behaves_like "string literal"
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  context "with Strict: true" do
 | 
					 | 
				
			||||||
    let(:cop_config) { { "EnforcedStyle" => "strict" } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "[1, 2, 3]"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "%w(a b c)"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "{ a: 1, b: 2 }"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "'str'"
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", %Q("top#{1 + 2}")
 | 
					 | 
				
			||||||
    it_behaves_like "mutable objects", "Something.new"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "1"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "1.5"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", ":sym"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "ENV['foo']"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "::ENV['foo']"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "OTHER_CONST"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "::OTHER_CONST"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "Namespace::OTHER_CONST"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "::Namespace::OTHER_CONST"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "Struct.new"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "::Struct.new"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "Struct.new(:a, :b)"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "T.type_alias { T.nilable(T.any(Pathname, String)) }"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "::T.type_alias { T.nilable(T.any(Pathname, String)) }"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", "type_member { { fixed: Module } }"
 | 
					 | 
				
			||||||
    it_behaves_like "immutable objects", <<~RUBY
 | 
					 | 
				
			||||||
      Struct.new(:node) do
 | 
					 | 
				
			||||||
        def assignment?
 | 
					 | 
				
			||||||
          true
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it "allows calls to freeze" do
 | 
					 | 
				
			||||||
      expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
        CONST = T.let([1].freeze, Object)
 | 
					 | 
				
			||||||
      RUBY
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "when assigning with an operator" do
 | 
					 | 
				
			||||||
      shared_examples "operator methods" do |o|
 | 
					 | 
				
			||||||
        it "registers an offense and corrects with parens and freeze" do
 | 
					 | 
				
			||||||
          expect_offense(<<~RUBY, o:)
 | 
					 | 
				
			||||||
            CONST = T.let(FOO %<o>s BAR, Object)
 | 
					 | 
				
			||||||
                          ^^^^^{o}^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
            CONST = T.let((FOO #{o} BAR).freeze, Object)
 | 
					 | 
				
			||||||
          RUBY
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it_behaves_like "operator methods", "+"
 | 
					 | 
				
			||||||
      it_behaves_like "operator methods", "-"
 | 
					 | 
				
			||||||
      it_behaves_like "operator methods", "*"
 | 
					 | 
				
			||||||
      it_behaves_like "operator methods", "/"
 | 
					 | 
				
			||||||
      it_behaves_like "operator methods", "%"
 | 
					 | 
				
			||||||
      it_behaves_like "operator methods", "**"
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "when assigning with multiple operator calls" do
 | 
					 | 
				
			||||||
      it "registers an offense and corrects with parens and freeze" do
 | 
					 | 
				
			||||||
        expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
          FOO = [1].freeze
 | 
					 | 
				
			||||||
          BAR = [2].freeze
 | 
					 | 
				
			||||||
          BAZ = [3].freeze
 | 
					 | 
				
			||||||
          CONST = T.let(FOO + BAR + BAZ, Object)
 | 
					 | 
				
			||||||
                        ^^^^^^^^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
          FOO = [1].freeze
 | 
					 | 
				
			||||||
          BAR = [2].freeze
 | 
					 | 
				
			||||||
          BAZ = [3].freeze
 | 
					 | 
				
			||||||
          CONST = T.let((FOO + BAR + BAZ).freeze, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "with methods and operators that produce frozen objects" do
 | 
					 | 
				
			||||||
      it "accepts assigning to an environment variable with a fallback" do
 | 
					 | 
				
			||||||
        expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let(ENV['foo'] || 'foo', Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
        expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let(::ENV['foo'] || 'foo', Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "accepts operating on a constant and an interger" do
 | 
					 | 
				
			||||||
        expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let(FOO + 2, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "accepts operating on multiple integers" do
 | 
					 | 
				
			||||||
        expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let(1 + 2, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "accepts operating on a constant and a float" do
 | 
					 | 
				
			||||||
        expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let(FOO + 2.1, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "accepts operating on multiple floats" do
 | 
					 | 
				
			||||||
        expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let(1.2 + 2.1, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "accepts comparison operators" do
 | 
					 | 
				
			||||||
        expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let(FOO == BAR, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "accepts checking fixed size" do
 | 
					 | 
				
			||||||
        expect_no_offenses(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let('foo'.count, Object)
 | 
					 | 
				
			||||||
          CONST = T.let('foo'.count('f'), Object)
 | 
					 | 
				
			||||||
          CONST = T.let([1, 2, 3].count { |n| n > 2 }, Object)
 | 
					 | 
				
			||||||
          CONST = T.let([1, 2, 3].count(2) { |n| n > 2 }, Object)
 | 
					 | 
				
			||||||
          CONST = T.let('foo'.length, Object)
 | 
					 | 
				
			||||||
          CONST = T.let('foo'.size, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "with operators that produce unfrozen objects" do
 | 
					 | 
				
			||||||
      it "registers an offense when operating on a constant and a string" do
 | 
					 | 
				
			||||||
        expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let(FOO + 'bar', Object)
 | 
					 | 
				
			||||||
                        ^^^^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let((FOO + 'bar').freeze, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it "registers an offense when operating on multiple strings" do
 | 
					 | 
				
			||||||
        expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let('foo' + 'bar' + 'baz', Object)
 | 
					 | 
				
			||||||
                        ^^^^^^^^^^^^^^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
          CONST = T.let(('foo' + 'bar' + 'baz').freeze, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    context "when assigning an array without brackets" do
 | 
					 | 
				
			||||||
      it "does not insert brackets for %w() arrays" do
 | 
					 | 
				
			||||||
        expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
          XXX = T.let(%w(YYY ZZZ), Object)
 | 
					 | 
				
			||||||
                      ^^^^^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
          XXX = T.let(%w(YYY ZZZ).freeze, Object)
 | 
					 | 
				
			||||||
        RUBY
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it "freezes a heredoc" do
 | 
					 | 
				
			||||||
      expect_offense(<<~RUBY)
 | 
					 | 
				
			||||||
        FOO = T.let(<<-HERE, Object)
 | 
					 | 
				
			||||||
                    ^^^^^^^ Freeze mutable objects assigned to constants.
 | 
					 | 
				
			||||||
          SOMETHING
 | 
					 | 
				
			||||||
        HERE
 | 
					 | 
				
			||||||
      RUBY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      expect_correction(<<~RUBY)
 | 
					 | 
				
			||||||
        FOO = T.let(<<-HERE.freeze, Object)
 | 
					 | 
				
			||||||
          SOMETHING
 | 
					 | 
				
			||||||
        HERE
 | 
					 | 
				
			||||||
      RUBY
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it_behaves_like "string literal"
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
@ -11,10 +11,7 @@ module UnpackStrategy
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  requires_ancestor { Kernel }
 | 
					  requires_ancestor { Kernel }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
 | 
					 | 
				
			||||||
  # rubocop:disable Style/MutableConstant
 | 
					 | 
				
			||||||
  UnpackStrategyType = T.type_alias { T.all(T::Class[UnpackStrategy], UnpackStrategy::ClassMethods) }
 | 
					  UnpackStrategyType = T.type_alias { T.all(T::Class[UnpackStrategy], UnpackStrategy::ClassMethods) }
 | 
				
			||||||
  # rubocop:enable Style/MutableConstant
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  module ClassMethods
 | 
					  module ClassMethods
 | 
				
			||||||
    extend T::Helpers
 | 
					    extend T::Helpers
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user