Class: Dependabot::Conda::Version

Inherits:
Version
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/dependabot/conda/version.rb

Overview

Conda version handling based on conda’s version specification See: docs.conda.io/projects/conda/en/stable/user-guide/concepts/pkg-specs.html

Version format: [epoch!]version

Components:

  • Epoch (optional): Integer prefix with ! separator (e.g., “1!2.0”)

  • Version: Main version identifier with segments separated by . or _

  • Local version (optional): Build metadata with + prefix (e.g., “1.0+abc.7”)

Special handling:

  • “dev” pre-releases sort before all other pre-releases

  • “post” releases sort after the main version

  • Underscores are normalized to dots

  • Case-insensitive string comparison

  • Fillvalue 0 insertion for missing segments

  • Integer < String in mixed-type segment comparison (numeric before pre-release)

Constant Summary collapse

VERSION_PATTERN =
/\A[a-z0-9_.!+\-]+\z/i

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(version) ⇒ Version

Returns a new instance of Version.

Raises:

  • (ArgumentError)


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/dependabot/conda/version.rb', line 57

def initialize(version)
  @version_string = T.let(version.to_s, String)

  raise ArgumentError, "Malformed version string #{version}" unless self.class.correct?(version)

  # Validate no empty segments
  validate_version!(@version_string)

  # Parse epoch, main version, and local version
  parts = parse_epoch_and_local(@version_string)

  @epoch = T.let(parts.epoch.to_i, Integer)
  @version_parts = T.let(parse_components(parts.main), T::Array[T.any(Integer, String)])
  @local_parts = T.let(
    parts.local ? parse_components(parts.local) : nil,
    T.nilable(T::Array[T.any(Integer, String)])
  )

  super
end

Instance Attribute Details

#epochObject (readonly)

Returns the value of attribute epoch.



45
46
47
# File 'lib/dependabot/conda/version.rb', line 45

def epoch
  @epoch
end

#local_partsObject (readonly)

Returns the value of attribute local_parts.



51
52
53
# File 'lib/dependabot/conda/version.rb', line 51

def local_parts
  @local_parts
end

#version_partsObject (readonly)

Returns the value of attribute version_parts.



48
49
50
# File 'lib/dependabot/conda/version.rb', line 48

def version_parts
  @version_parts
end

Class Method Details

.correct?(version) ⇒ Boolean

Returns:

  • (Boolean)


33
34
35
36
37
# File 'lib/dependabot/conda/version.rb', line 33

def self.correct?(version)
  return false if version.nil? || version.to_s.empty?

  version.to_s.match?(VERSION_PATTERN)
end

.new(version) ⇒ Object



40
41
42
# File 'lib/dependabot/conda/version.rb', line 40

def self.new(version)
  T.cast(super, Dependabot::Conda::Version)
end

Instance Method Details

#<=>(other) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/dependabot/conda/version.rb', line 79

def <=>(other)
  return nil unless other.is_a?(Dependabot::Conda::Version)

  # Step 1: Compare epochs (numerically)
  epoch_comparison = @epoch <=> other.epoch
  return epoch_comparison unless epoch_comparison.zero?

  # Step 2: Compare version parts (segment by segment with fillvalue)
  version_comparison = compare_parts(@version_parts, other.version_parts)
  return version_comparison unless version_comparison.zero?

  # Step 3: Compare local parts (if present)
  compare_local_parts(@local_parts, other.local_parts)
end