diff options
Diffstat (limited to 'lib/rubygems/resolver/api_specification.rb')
| -rw-r--r-- | lib/rubygems/resolver/api_specification.rb | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/lib/rubygems/resolver/api_specification.rb b/lib/rubygems/resolver/api_specification.rb index 1e22dd0b6f..ccfd6fe084 100644 --- a/lib/rubygems/resolver/api_specification.rb +++ b/lib/rubygems/resolver/api_specification.rb @@ -1,17 +1,28 @@ # frozen_string_literal: true + ## -# Represents a specification retrieved via the rubygems.org API. +# Represents a specification retrieved via the Compact Index API. # # This is used to avoid loading the full Specification object when all we need # is the name, version, and dependencies. class Gem::Resolver::APISpecification < Gem::Resolver::Specification + ## + # We assume that all instances of this class are immutable; + # so avoid duplicated generation for performance. + @@cache = {} + def self.new(set, api_data) + cache_key = [set, api_data] + cache = @@cache[cache_key] + return cache if cache + @@cache[cache_key] = super + end ## - # Creates an APISpecification for the given +set+ from the rubygems.org + # Creates an APISpecification for the given +set+ from the Compact Index API # +api_data+. # - # See http://guides.rubygems.org/rubygems-org-api/#misc_methods for the + # See https://guides.rubygems.org/rubygems-org-compact-index-api for the # format of the +api_data+. def initialize(set, api_data) @@ -19,20 +30,26 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification @set = set @name = api_data[:name] - @version = Gem::Version.new api_data[:number] - @platform = Gem::Platform.new api_data[:platform] + @version = Gem::Version.new(api_data[:number]).freeze + @platform = Gem::Platform.new(api_data[:platform]).freeze + @original_platform = api_data[:platform].freeze @dependencies = api_data[:dependencies].map do |name, ver| - Gem::Dependency.new name, ver.split(/\s*,\s*/) - end + Gem::Dependency.new(name, ver.split(/\s*,\s*/)).freeze + end.freeze + @required_ruby_version = Gem::Requirement.new(api_data.dig(:requirements, :ruby)).freeze + @required_rubygems_version = Gem::Requirement.new(api_data.dig(:requirements, :rubygems)).freeze end - def == other # :nodoc: - self.class === other and - @set == other.set and - @name == other.name and - @version == other.version and - @platform == other.platform and - @dependencies == other.dependencies + def ==(other) # :nodoc: + self.class === other && + @set == other.set && + @name == other.name && + @version == other.version && + @platform == other.platform + end + + def hash + @set.hash ^ @name.hash ^ @version.hash ^ @platform.hash end def fetch_development_dependencies # :nodoc: @@ -42,11 +59,11 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification end def installable_platform? # :nodoc: - Gem::Platform.match @platform + Gem::Platform.match_gem? @platform, @name end - def pretty_print q # :nodoc: - q.group 2, '[APISpecification', ']' do + def pretty_print(q) # :nodoc: + q.group 2, "[APISpecification", "]" do q.breakable q.text "name: #{name}" @@ -57,7 +74,7 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification q.text "platform: #{platform}" q.breakable - q.text 'dependencies:' + q.text "dependencies:" q.breakable q.pp @dependencies @@ -73,7 +90,11 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification @spec ||= begin tuple = Gem::NameTuple.new @name, @version, @platform + source.fetch_spec tuple + rescue Gem::RemoteFetcher::FetchError + raise if @original_platform == @platform + tuple = Gem::NameTuple.new @name, @version, @original_platform source.fetch_spec tuple end end @@ -81,6 +102,4 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification def source # :nodoc: @set.source end - end - |
