From 3b65ca4f85b185769c19bed7e96cc8bfcbdbdd09 Mon Sep 17 00:00:00 2001 From: Douglas Eichelberger Date: Sat, 6 Sep 2025 22:04:22 -0700 Subject: [PATCH] Fix some specs --- Library/Homebrew/bottle_specification.rb | 4 +-- Library/Homebrew/bundle/skipper.rb | 4 +-- Library/Homebrew/cask/config.rb | 34 +++++++++---------- Library/Homebrew/dependency_collector.rb | 2 +- Library/Homebrew/download_strategy.rb | 2 +- Library/Homebrew/extend/kernel.rb | 2 +- Library/Homebrew/formula.rb | 2 +- Library/Homebrew/lazy_object.rb | 3 ++ .../requirements/xcode_requirement.rb | 4 +-- Library/Homebrew/sbom.rb | 31 +++++++---------- Library/Homebrew/software_spec.rb | 2 +- Library/Homebrew/system_command.rb | 2 +- .../test/download_strategies/curl_spec.rb | 2 +- Library/Homebrew/test/spec_helper.rb | 7 ++++ 14 files changed, 53 insertions(+), 48 deletions(-) diff --git a/Library/Homebrew/bottle_specification.rb b/Library/Homebrew/bottle_specification.rb index 83d81f62cc..540a8fc5fd 100644 --- a/Library/Homebrew/bottle_specification.rb +++ b/Library/Homebrew/bottle_specification.rb @@ -9,7 +9,7 @@ class BottleSpecification attr_reader :collector - sig { returns(T::Hash[String, T.untyped]) } + sig { returns(T::Hash[Symbol, T.untyped]) } attr_reader :root_url_specs sig { returns(String) } @@ -20,7 +20,7 @@ class BottleSpecification @rebuild = T.let(0, Integer) @repository = T.let(Homebrew::DEFAULT_REPOSITORY, String) @collector = T.let(Utils::Bottles::Collector.new, Utils::Bottles::Collector) - @root_url_specs = T.let({}, T::Hash[String, T.untyped]) + @root_url_specs = T.let({}, T::Hash[Symbol, T.untyped]) @root_url = T.let(nil, T.nilable(String)) end diff --git a/Library/Homebrew/bundle/skipper.rb b/Library/Homebrew/bundle/skipper.rb index c6b4ccd8f1..1261b5a621 100644 --- a/Library/Homebrew/bundle/skipper.rb +++ b/Library/Homebrew/bundle/skipper.rb @@ -37,11 +37,11 @@ module Homebrew private - sig { returns(T::Hash[Symbol, T::Array[String]]) } + sig { returns(T::Hash[Symbol, T.nilable(T::Array[String])]) } def skipped_entries return @skipped_entries if @skipped_entries - @skipped_entries ||= T.let({}, T.nilable(T::Hash[Symbol, T::Array[String]])) + @skipped_entries ||= T.let({}, T.nilable(T::Hash[Symbol, T.nilable(T::Array[String])])) [:brew, :cask, :mas, :tap, :whalebrew].each do |type| @skipped_entries[type] = ENV["HOMEBREW_BUNDLE_#{type.to_s.upcase}_SKIP"]&.split diff --git a/Library/Homebrew/cask/config.rb b/Library/Homebrew/cask/config.rb index 68b0f91e95..53a647839a 100644 --- a/Library/Homebrew/cask/config.rb +++ b/Library/Homebrew/cask/config.rb @@ -12,6 +12,7 @@ module Cask # # @api internal class Config + ConfigValue = T.type_alias { T.any(LazyObject, String, Pathname, T::Array[String]) } DEFAULT_DIRS = T.let( { appdir: "/Applications", @@ -33,7 +34,7 @@ module Cask T::Hash[Symbol, String], ) - sig { returns(T::Hash[Symbol, String]) } + sig { returns(T::Hash[Symbol, T.any(LazyObject, String)]) } def self.defaults { languages: LazyObject.new { ::OS::Mac.languages }, @@ -79,12 +80,11 @@ module Cask sig { params( - config: T::Enumerable[ - [T.any(String, Symbol), T.any(String, Pathname, T::Array[String])], - ], - ).returns( - T::Hash[Symbol, T.any(String, Pathname, T::Array[String])], - ) + config: T.any( + T::Hash[Symbol, T.any(LazyObject, String)], + T::Enumerable[[T.any(String, Symbol), ConfigValue]], + ), + ).returns(T::Hash[Symbol, ConfigValue]) } def self.canonicalize(config) config.to_h do |k, v| @@ -93,7 +93,7 @@ module Cask if DEFAULT_DIRS.key?(key) raise TypeError, "Invalid path for default dir #{k}: #{v.inspect}" if v.is_a?(Array) - [key, Pathname(v).expand_path] + [key, Pathname(v.to_s).expand_path] else [key, v] end @@ -103,14 +103,14 @@ module Cask # Get the explicit configuration. # # @api internal - sig { returns(T::Hash[Symbol, T.any(String, Pathname, T::Array[String])]) } + sig { returns(T::Hash[Symbol, ConfigValue]) } attr_accessor :explicit sig { params( - default: T.nilable(T::Hash[Symbol, T.any(String, Pathname, T::Array[String])]), - env: T.nilable(T::Hash[Symbol, T.any(String, Pathname, T::Array[String])]), - explicit: T::Hash[Symbol, T.any(String, Pathname, T::Array[String])], + default: T.nilable(T::Hash[Symbol, ConfigValue]), + env: T.nilable(T::Hash[Symbol, ConfigValue]), + explicit: T::Hash[Symbol, ConfigValue], ignore_invalid_keys: T::Boolean, ).void } @@ -118,18 +118,18 @@ module Cask if default @default = T.let( self.class.canonicalize(self.class.defaults.merge(default)), - T.nilable(T::Hash[Symbol, T.any(String, Pathname, T::Array[String])]), + T.nilable(T::Hash[Symbol, ConfigValue]), ) end if env @env = T.let( self.class.canonicalize(env), - T.nilable(T::Hash[Symbol, T.any(String, Pathname, T::Array[String])]), + T.nilable(T::Hash[Symbol, ConfigValue]), ) end @explicit = T.let( self.class.canonicalize(explicit), - T::Hash[Symbol, T.any(String, Pathname, T::Array[String])], + T::Hash[Symbol, ConfigValue], ) if ignore_invalid_keys @@ -142,12 +142,12 @@ module Cask @explicit.assert_valid_keys(*self.class.defaults.keys) end - sig { returns(T::Hash[Symbol, T.any(String, Pathname, T::Array[String])]) } + sig { returns(T::Hash[Symbol, ConfigValue]) } def default @default ||= self.class.canonicalize(self.class.defaults) end - sig { returns(T::Hash[Symbol, T.any(String, Pathname, T::Array[String])]) } + sig { returns(T::Hash[Symbol, ConfigValue]) } def env @env ||= self.class.canonicalize( Homebrew::EnvConfig.cask_opts diff --git a/Library/Homebrew/dependency_collector.rb b/Library/Homebrew/dependency_collector.rb index 68e68c3fa9..3724f97cd4 100644 --- a/Library/Homebrew/dependency_collector.rb +++ b/Library/Homebrew/dependency_collector.rb @@ -135,7 +135,7 @@ class DependencyCollector sig { params(spec: T.any(String, Resource, Symbol, Requirement, Dependency, Class), - tags: T::Array[Symbol]).returns(T.any(Dependency, Requirement, Array, NilClass)) + tags: T::Array[T.any(String, Symbol)]).returns(T.any(Dependency, Requirement, Array, NilClass)) } def parse_spec(spec, tags) raise ArgumentError, "Implicit dependencies cannot be manually specified" if tags.include?(:implicit) diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index 5353ee2862..88fb6d63c7 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -643,7 +643,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy args end - sig { returns(T::Hash[Symbol, String]) } + sig { returns(T::Hash[Symbol, T.any(String, Symbol)]) } def _curl_opts return { user_agent: meta.fetch(:user_agent) } if meta.key?(:user_agent) diff --git a/Library/Homebrew/extend/kernel.rb b/Library/Homebrew/extend/kernel.rb index a38121b094..c6057d276f 100644 --- a/Library/Homebrew/extend/kernel.rb +++ b/Library/Homebrew/extend/kernel.rb @@ -283,7 +283,7 @@ module Kernel # @api public sig { type_parameters(:U) - .params(hash: T::Hash[Object, String], _block: T.proc.returns(T.type_parameter(:U))) + .params(hash: T::Hash[Object, T.nilable(String)], _block: T.proc.returns(T.type_parameter(:U))) .returns(T.type_parameter(:U)) } def with_env(hash, &_block) diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 33560d6e04..7f8a317979 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -3963,7 +3963,7 @@ class Formula # ``` # # @api public - sig { params(dep: T.any(String, Symbol, T::Hash[String, T.untyped], T::Class[Requirement])).void } + sig { params(dep: T.any(String, Symbol, T::Hash[T.any(String, Symbol), T.untyped], T::Class[Requirement])).void } def depends_on(dep) specs.each { |spec| spec.depends_on(dep) } end diff --git a/Library/Homebrew/lazy_object.rb b/Library/Homebrew/lazy_object.rb index c99bcb4db3..a09c92ed7a 100644 --- a/Library/Homebrew/lazy_object.rb +++ b/Library/Homebrew/lazy_object.rb @@ -28,4 +28,7 @@ class LazyObject < Delegator __getobj__.is_a?(klass) || super end + + def class = __getobj__.class + def to_s = __getobj__.to_s end diff --git a/Library/Homebrew/requirements/xcode_requirement.rb b/Library/Homebrew/requirements/xcode_requirement.rb index c0c9134238..abc31503ce 100644 --- a/Library/Homebrew/requirements/xcode_requirement.rb +++ b/Library/Homebrew/requirements/xcode_requirement.rb @@ -15,10 +15,10 @@ class XcodeRequirement < Requirement xcode_installed_version! end - sig { params(tags: T::Array[String]).void } + sig { params(tags: T::Array[T.any(String, Symbol)]).void } def initialize(tags = []) version = tags.shift if tags.first.to_s.match?(/(\d\.)+\d/) - @version = T.let(version, T.nilable(String)) + @version = T.let(version.to_s, T.nilable(String)) super end diff --git a/Library/Homebrew/sbom.rb b/Library/Homebrew/sbom.rb index b0b463a004..f370d48251 100644 --- a/Library/Homebrew/sbom.rb +++ b/Library/Homebrew/sbom.rb @@ -13,7 +13,7 @@ class SBOM include Utils::Output::Mixin FILENAME = "sbom.spdx.json" - SCHEMA_FILE = (HOMEBREW_LIBRARY_PATH/"data/schemas/sbom.json").freeze + SCHEMA_FILE = T.let((HOMEBREW_LIBRARY_PATH/"data/schemas/sbom.json").freeze, Pathname) # Instantiates a {SBOM} for a new installation of a formula. sig { params(formula: Formula, tab: Tab).returns(T.attached_class) } @@ -85,7 +85,7 @@ class SBOM sig { returns(T::Hash[String, T.untyped]) } def self.schema - @schema ||= JSON.parse(SCHEMA_FILE.read, freeze: true) + @schema ||= T.let(JSON.parse(SCHEMA_FILE.read, freeze: true), T.nilable(T::Hash[String, T.untyped])) end sig { params(bottling: T::Boolean).returns(T::Array[T::Hash[String, T.untyped]]) } @@ -134,17 +134,17 @@ class SBOM attr_reader :name, :homebrew_version, :time, :stdlib, :source, :built_on, :license attr_accessor :spdxfile - sig { params(attributes: Hash).void } + sig { params(attributes: T::Hash[Symbol, T.untyped]).void } def initialize(attributes = {}) attributes.each { |key, value| instance_variable_set(:"@#{key}", value) } end sig { params( - runtime_dependency_declaration: T::Array[Hash], - compiler_declaration: Hash, + runtime_dependency_declaration: T::Array[T::Hash[Symbol, T.untyped]], + compiler_declaration: T::Hash[String, T.untyped], bottling: T::Boolean, - ).returns(T::Array[Hash]) + ).returns(T::Array[T::Hash[Symbol, T.untyped]]) } def generate_relations_json(runtime_dependency_declaration, compiler_declaration, bottling:) runtime = runtime_dependency_declaration.map do |dependency| @@ -167,7 +167,7 @@ class SBOM spdxElementId: "SPDXRef-File-#{name}", relationshipType: "PACKAGE_OF", relatedSpdxElement: "SPDXRef-Archive-#{name}-src", - }], T::Array[Hash]) + }], T::Array[T::Hash[Symbol, T.untyped]]) unless bottling base << { @@ -189,16 +189,11 @@ class SBOM end sig { - params(runtime_dependency_declaration: T::Array[Hash], - compiler_declaration: Hash, - bottling: T::Boolean).returns( - T::Array[ - T::Hash[ - Symbol, - T.any(String, T::Array[T::Hash[Symbol, String]]), - ], - ], - ) + params( + runtime_dependency_declaration: T::Array[T::Hash[Symbol, T.untyped]], + compiler_declaration: T::Hash[String, T.untyped], + bottling: T::Boolean, + ).returns(T::Array[T::Hash[Symbol, T.untyped]]) } def generate_packages_json(runtime_dependency_declaration, compiler_declaration, bottling:) bottle = [] @@ -302,7 +297,7 @@ class SBOM end end - sig { params(bottling: T::Boolean).returns(T::Hash[Symbol, T.any(String, T::Array[T::Hash[Symbol, String]])]) } + sig { params(bottling: T::Boolean).returns(T::Hash[Symbol, T.anything]) } def to_spdx_sbom(bottling:) runtime_full = full_spdx_runtime_dependencies(bottling:) diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb index 82435a9a28..625aaf3306 100644 --- a/Library/Homebrew/software_spec.rb +++ b/Library/Homebrew/software_spec.rb @@ -242,7 +242,7 @@ class SoftwareSpec @build = BuildOptions.new(Options.create(@flags), options) end - sig { params(spec: T.any(String, Symbol, T::Hash[String, T.untyped], T::Class[Requirement], Dependable)).void } + sig { params(spec: T.any(String, Symbol, T::Hash[T.any(String, Symbol), T.untyped], T::Class[Requirement], Dependable)).void } def depends_on(spec) dep = dependency_collector.add(spec) add_dep_option(dep) if dep diff --git a/Library/Homebrew/system_command.rb b/Library/Homebrew/system_command.rb index b819da1ba2..51a262c8b0 100644 --- a/Library/Homebrew/system_command.rb +++ b/Library/Homebrew/system_command.rb @@ -478,7 +478,7 @@ class SystemCommand sig { params( command: T::Array[String], - output: T::Array[[Symbol, String]], + output: T::Array[[T.any(String, Symbol), String]], status: Process::Status, secrets: T::Array[String], ).void diff --git a/Library/Homebrew/test/download_strategies/curl_spec.rb b/Library/Homebrew/test/download_strategies/curl_spec.rb index a7c5deee52..28e478e47c 100644 --- a/Library/Homebrew/test/download_strategies/curl_spec.rb +++ b/Library/Homebrew/test/download_strategies/curl_spec.rb @@ -67,7 +67,7 @@ RSpec.describe CurlDownloadStrategy do context "with a generalized fake user agent" do alias_matcher :a_string_matching, :match - let(:specs) { { user_agent: :fake } } + let(:specs) { { user_agent: "fake" } } it "adds the appropriate curl args" do expect(strategy).to receive(:system_command) diff --git a/Library/Homebrew/test/spec_helper.rb b/Library/Homebrew/test/spec_helper.rb index 61246fc0d1..0f7da6eaa6 100644 --- a/Library/Homebrew/test/spec_helper.rb +++ b/Library/Homebrew/test/spec_helper.rb @@ -33,6 +33,13 @@ module T recursively_valid?(obj) end end + + class TypedHash < TypedEnumerable + # overrides Base + def valid?(obj) + recursively_valid?(obj) + end + end end end