123456789_123456789_123456789_123456789_123456789_

Class: Bundler::GemVersionPromoter

Relationships & Source Files
Inherits: Object
Defined in: lib/bundler/gem_version_promoter.rb

Overview

This class contains all of the logic for determining the next version of a ::Gem to update to based on the requested level (patch, minor, major). Primarily designed to work with Resolver which will provide it the list of available dependency versions as found in its index, before returning it to to the resolution engine to select the best version.

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.newGemVersionPromoter

Creates a GemVersionPromoter instance.

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 29

def initialize
  @level = :major
  @strict = false
  @pre = false
end

Instance Attribute Details

#level (rw)

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 10

attr_reader :level

#level=(value) (rw)

Parameters:

  • value (Symbol)

    One of three Symbols: :major, :minor or :patch.

Raises:

  • (ArgumentError)
[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 36

def level=(value)
  v = case value
      when String, Symbol
        value.to_sym
  end

  raise ArgumentError, "Unexpected level #{v}. Must be :major, :minor or :patch" unless [:major, :minor, :patch].include?(v)
  @level = v
end

#major?bool (readonly)

Returns:

  • (bool)

    Convenience method for testing value of level variable.

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 62

def major?
  level == :major
end

#minor?bool (readonly)

Returns:

  • (bool)

    Convenience method for testing value of level variable.

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 67

def minor?
  level == :minor
end

#pre (rw)

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 11

attr_accessor :pre

#pre?bool (rw)

Returns:

  • (bool)

    Convenience method for testing value of pre variable.

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 72

def pre?
  pre == true
end

#strict (rw)

By default, strict is false, meaning every available version of a gem is returned from sort_versions. The order gives preference to the requested level (:patch, :minor, :major) but in complicated requirement cases some gems will by necessity be promoted past the requested level, or even reverted to older versions.

If strict is set to true, the results from sort_versions will be truncated, eliminating any version outside the current level scope. This can lead to unexpected outcomes or even VersionConflict exceptions that report a version of a gem not existing for versions that indeed do existing in the referenced source.

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 24

attr_accessor :strict

Instance Method Details

#either_version_older_than_locked?(a, b, locked_version) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 119

def either_version_older_than_locked?(a, b, locked_version)
  locked_version && (a.version < locked_version || b.version < locked_version)
end

#filter_dep_specs(specs, package) (private)

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 78

def filter_dep_specs(specs, package)
  locked_version = package.locked_version
  return specs if locked_version.nil? || major?

  specs.select do |spec|
    gsv = spec.version

    must_match = minor? ? [0] : [0, 1]

    all_match = must_match.all? {|idx| gsv.segments[idx] == locked_version.segments[idx] }
    all_match && gsv >= locked_version
  end
end

#move_version_to_end(result, version) (private)

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 140

def move_version_to_end(result, version)
  move, keep = result.partition {|s| s.version.to_s == version.to_s }
  keep.concat(move)
end

#post_sort(result, unlock, locked_version) (private)

Specific version moves can’t always reliably be done during sorting as not all elements are compared against each other.

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 130

def post_sort(result, unlock, locked_version)
  # default :major behavior in Bundler does not do this
  return result if major?
  if unlock || locked_version.nil?
    result
  else
    move_version_to_end(result, locked_version)
  end
end

#segments_do_not_match?(a, b, level) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 123

def segments_do_not_match?(a, b, level)
  index = [:major, :minor].index(level)
  a.segments[index] != b.segments[index]
end

#sort_dep_specs(specs, package) (private)

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 92

def sort_dep_specs(specs, package)
  locked_version = package.locked_version

  result = specs.sort do |a, b|
    unless package.prerelease_specified? || pre?
      a_pre = a.prerelease?
      b_pre = b.prerelease?

      next -1 if a_pre && !b_pre
      next  1 if b_pre && !a_pre
    end

    if major?
      a <=> b
    elsif either_version_older_than_locked?(a, b, locked_version)
      a <=> b
    elsif segments_do_not_match?(a, b, :major)
      b <=> a
    elsif !minor? && segments_do_not_match?(a, b, :minor)
      b <=> a
    else
      a <=> b
    end
  end
  post_sort(result, package.unlock?, locked_version)
end

#sort_versions(package, specs) ⇒ Specification

Given a Resolver::Package and an Array of Specifications of available versions for a gem, this method will return the Array of Specifications sorted (and possibly truncated if strict is true) in an order to give preference to the current level (:major, :minor or :patch) when resolution is deciding what versions best resolve all dependencies in the bundle.

Parameters:

  • package (Resolver::Package)

    The package being resolved.

  • specs (Specification)

    An array of Specifications for the package.

Returns:

  • (Specification)

    A new instance of the Specification Array sorted and possibly filtered.

[ GitHub ]

  
# File 'lib/bundler/gem_version_promoter.rb', line 55

def sort_versions(package, specs)
  specs = filter_dep_specs(specs, package) if strict

  sort_dep_specs(specs, package)
end