class Bundler::SpecSet - bundler: Ruby Standard Library Documentation

# class Bundler::SpecSet

### Public Class Methods

new(specs) click to toggle source

    # File bundler/spec_set.rb, line 10
    def initialize(specs)
      @specs = specs
    end

### Public Instance Methods

-(other) click to toggle source

    # File bundler/spec_set.rb, line 158
    def -(other)
      SpecSet.new(to_a - other.to_a)
    end

<<(spec) click to toggle source

    # File bundler/spec_set.rb, line 179
    def <<(spec)
      @specs << spec
    end

[](key) click to toggle source

    # File bundler/spec_set.rb, line 80
    def [](key)
      key = key.name if key.respond_to?(:name)
      lookup[key]&.reverse || []
    end

[]=(key, value) click to toggle source

    # File bundler/spec_set.rb, line 85
    def []=(key, value)
      @specs << value

      reset!
    end

add_extra_platforms!(platforms) click to toggle source

    # File bundler/spec_set.rb, line 50
    def add_extra_platforms!(platforms)
      return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty?

      new_platforms = all_platforms.select do |platform|
        next if platforms.include?(platform)
        next unless GemHelpers.generic(platform) == Gem::Platform::RUBY

        complete_platform(platform)
      end
      return platforms if new_platforms.empty?

      platforms.concat(new_platforms)

      less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && Bundler.local_platform === platform && platform === Bundler.local_platform }
      platforms.delete(Bundler.local_platform) if less_specific_platform

      platforms
    end

delete(specs) click to toggle source

    # File bundler/spec_set.rb, line 91
    def delete(specs)
      Array(specs).each {|spec| @specs.delete(spec) }

      reset!
    end

delete_by_name(name) click to toggle source

    # File bundler/spec_set.rb, line 166
    def delete_by_name(name)
      @specs.reject! {|spec| spec.name == name }

      reset!
    end

each(&b) click to toggle source

    # File bundler/spec_set.rb, line 195
    def each(&b)
      sorted.each(&b)
    end

empty?() click to toggle source

    # File bundler/spec_set.rb, line 191
    def empty?
      @specs.empty?
    end

find_by_name_and_platform(name, platform) click to toggle source

    # File bundler/spec_set.rb, line 162
    def find_by_name_and_platform(name, platform)
      @specs.detect {|spec| spec.name == name && spec.match_platform(platform) }
    end

for(dependencies, platforms_or_legacy_check = [nil], legacy_platforms = [nil], skips: []) click to toggle source

    # File bundler/spec_set.rb, line 14
    def for(dependencies, platforms_or_legacy_check = [nil], legacy_platforms = [nil], skips: [])
      platforms = if [true, false].include?(platforms_or_legacy_check)
        Bundler::SharedHelpers.major_deprecation 2,
          "SpecSet#for received a `check` parameter, but that's no longer used and deprecated. " \
          "SpecSet#for always implicitly performs validation. Please remove this parameter",
          print_caller_location: true

        legacy_platforms
      else
        platforms_or_legacy_check
      end

      materialize_dependencies(dependencies, platforms, skips: skips)

      @materializations.flat_map(&:specs).uniq
    end

incomplete_for_platform?(deps, platform) click to toggle source

    # File bundler/spec_set.rb, line 127
    def incomplete_for_platform?(deps, platform)
      return false if @specs.empty?

      validation_set = self.class.new(@specs)
      validation_set.for(deps, [platform])

      validation_set.incomplete_specs.any?
    end

incomplete_specs() click to toggle source

    # File bundler/spec_set.rb, line 150
    def incomplete_specs
      @materializations.flat_map(&:incomplete_specs)
    end

insecurely_materialized_specs() click to toggle source

    # File bundler/spec_set.rb, line 154
    def insecurely_materialized_specs
      materialized_specs.select(&:insecurely_materialized?)
    end

length() click to toggle source

    # File bundler/spec_set.rb, line 183
    def length
      @specs.length
    end

materialize(deps) click to toggle source

    # File bundler/spec_set.rb, line 109
    def materialize(deps)
      materialize_dependencies(deps)

      SpecSet.new(materialized_specs)
    end

materialized_for_all_platforms() click to toggle source

Materialize for all the specs in the spec set, regardless of what platform they’re for @return [Array<Gem::Specification>]

    # File bundler/spec_set.rb, line 117
    def materialized_for_all_platforms
      @specs.map do |s|
        next s unless s.is_a?(LazySpecification)
        s.source.remote!
        spec = s.materialize_strictly
        raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec
        spec
      end
    end

missing_specs() click to toggle source

    # File bundler/spec_set.rb, line 142
    def missing_specs
      @materializations.flat_map(&:completely_missing_specs)
    end

missing_specs_for(dependencies) click to toggle source

    # File bundler/spec_set.rb, line 136
    def missing_specs_for(dependencies)
      materialize_dependencies(dependencies)

      missing_specs
    end

names() click to toggle source

    # File bundler/spec_set.rb, line 199
    def names
      lookup.keys
    end

normalize_platforms!(deps, platforms) click to toggle source

    # File bundler/spec_set.rb, line 31
    def normalize_platforms!(deps, platforms)
      complete_platforms = add_extra_platforms!(platforms)

      complete_platforms.map do |platform|
        next platform if platform == Gem::Platform::RUBY

        begin
          Integer(platform.version)
        rescue ArgumentError, TypeError
          next platform
        end

        less_specific_platform = Gem::Platform.new([platform.cpu, platform.os, nil])
        next platform if incomplete_for_platform?(deps, less_specific_platform)

        less_specific_platform
      end.uniq
    end

partially_missing_specs() click to toggle source

    # File bundler/spec_set.rb, line 146
    def partially_missing_specs
      @materializations.flat_map(&:partially_missing_specs)
    end

size() click to toggle source

    # File bundler/spec_set.rb, line 187
    def size
      @specs.size
    end

sort!() click to toggle source

    # File bundler/spec_set.rb, line 97
    def sort!
      self
    end

to_a() click to toggle source

    # File bundler/spec_set.rb, line 101
    def to_a
      sorted.dup
    end

to_hash() click to toggle source

    # File bundler/spec_set.rb, line 105
    def to_hash
      lookup.dup
    end

valid?(s) click to toggle source

    # File bundler/spec_set.rb, line 203
    def valid?(s)
      s.matches_current_metadata? && valid_dependencies?(s)
    end

validate_deps(s) click to toggle source

    # File bundler/spec_set.rb, line 69
    def validate_deps(s)
      s.runtime_dependencies.each do |dep|
        next if dep.name == "bundler"

        return :missing unless names.include?(dep.name)
        return :invalid if none? {|spec| dep.matches_spec?(spec) }
      end

      :valid
    end

what_required(spec) click to toggle source

    # File bundler/spec_set.rb, line 172
    def what_required(spec)
      unless req = find {|s| s.runtime_dependencies.any? {|d| d.name == spec.name } }
        return [spec]
      end
      what_required(req) << spec
    end

### Private Instance Methods

all_platforms() click to toggle source

    # File bundler/spec_set.rb, line 272
    def all_platforms
      @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq
    end

complete_platform(platform) click to toggle source

    # File bundler/spec_set.rb, line 245
    def complete_platform(platform)
      new_specs = []

      valid_platform = lookup.all? do |_, specs|
        spec = specs.first
        matching_specs = spec.source.specs.search([spec.name, spec.version])
        platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).find do |s|
          valid?(s)
        end

        if platform_spec
          new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec)
          true
        else
          false
        end
      end

      if valid_platform && new_specs.any?
        @specs.concat(new_specs)

        reset!
      end

      valid_platform
    end

extract_circular_gems(error) click to toggle source

    # File bundler/spec_set.rb, line 292
    def extract_circular_gems(error)
      error.message.scan(/@name="(.*?)"/).flatten
    end

lookup() click to toggle source

    # File bundler/spec_set.rb, line 296
    def lookup
      @lookup ||= begin
        lookup = {}
        @specs.each do |s|
          lookup[s.name] ||= []
          lookup[s.name] << s
        end
        lookup
      end
    end

materialize_dependencies(dependencies, platforms = [nil], skips: []) click to toggle source

    # File bundler/spec_set.rb, line 209
    def materialize_dependencies(dependencies, platforms = [nil], skips: [])
      handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h
      deps = dependencies.product(platforms)
      @materializations = []

      loop do
        break unless dep = deps.shift

        dependency = dep[0]
        platform = dep[1]
        name = dependency.name

        key = [name, platform]
        next if handled.key?(key)

        handled[key] = true

        materialization = Materialization.new(dependency, platform, candidates: lookup[name])

        deps.concat(materialization.dependencies) if materialization.complete?

        @materializations << materialization unless skips.include?(name)
      end

      @materializations
    end

materialized_specs() click to toggle source

    # File bundler/spec_set.rb, line 236
    def materialized_specs
      @materializations.filter_map(&:materialized_spec)
    end

reset!() click to toggle source

    # File bundler/spec_set.rb, line 240
    def reset!
      @sorted = nil
      @lookup = nil
    end

sorted() click to toggle source

    # File bundler/spec_set.rb, line 280
    def sorted
      rake = @specs.find {|s| s.name == "rake" }
      begin
        @sorted ||= ([rake] + tsort).compact.uniq
      rescue TSort::Cyclic => error
        cgems = extract_circular_gems(error)
        raise CyclicDependencyError, "Your bundle requires gems that depend" \
          " on each other, creating an infinite loop. Please remove either" \
          " gem '#{cgems[0]}' or gem '#{cgems[1]}' and try again."
      end
    end

tsort_each_child(s) { |s2| ... } click to toggle source

    # File bundler/spec_set.rb, line 312
    def tsort_each_child(s)
      s.dependencies.sort_by(&:name).each do |d|
        next if d.type == :development

        specs_for_name = lookup[d.name]
        next unless specs_for_name

        specs_for_name.each {|s2| yield s2 }
      end
    end

tsort_each_node() { |s| ... } click to toggle source

    # File bundler/spec_set.rb, line 307
    def tsort_each_node
      # MUST sort by name for backwards compatibility
      @specs.sort_by(&:name).each {|s| yield s }
    end

valid_dependencies?(s) click to toggle source

    # File bundler/spec_set.rb, line 276
    def valid_dependencies?(s)
      validate_deps(s) == :valid
    end