Class: Dependabot::Python::Version

Inherits:
Version
  • Object
show all
Defined in:
lib/dependabot/python/version.rb

Constant Summary collapse

INFINITY =
1000
NEGATIVE_INFINITY =
-INFINITY
VERSION_PATTERN =
/
  v?
  (?:
    (?:(?<epoch>[0-9]+)!)?                          # epoch
    (?<release>[0-9]+(?:\.[0-9]+)*)                 # release
    (?<pre>                                         # prerelease
      [-_\.]?
      (?<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
      [-_\.]?
      (?<pre_n>[0-9]+)?
    )?
    (?<post>                                        # post release
      (?:-(?<post_n1>[0-9]+))
      |
      (?:
          [-_\.]?
          (?<post_l>post|rev|r)
          [-_\.]?
          (?<post_n2>[0-9]+)?
      )
    )?
    (?<dev>                                          # dev release
      [-_\.]?
      (?<dev_l>dev)
      [-_\.]?
      (?<dev_n>[0-9]+)?
    )?
  )
  (?:\+(?<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?    # local version
/ix
ANCHORED_VERSION_PATTERN =
/\A\s*#{VERSION_PATTERN}\s*\z/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(version) ⇒ Version

Returns a new instance of Version.

Raises:

  • (Dependabot::BadRequirementError)


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/dependabot/python/version.rb', line 75

def initialize(version)
  raise Dependabot::BadRequirementError, "Malformed version string - string is nil" if version.nil?

  @version_string = version.to_s

  raise Dependabot::BadRequirementError, "Malformed version string - string is empty" if @version_string.empty?

  matches = ANCHORED_VERSION_PATTERN.match(@version_string.downcase)

  unless matches
    raise Dependabot::BadRequirementError,
          "Malformed version string - #{@version_string} does not match regex"
  end

  @epoch = matches["epoch"].to_i
  @release_segment = matches["release"]&.split(".")&.map(&:to_i) || []
  @pre = parse_letter_version(matches["pre_l"], matches["pre_n"])
  @post = parse_letter_version(matches["post_l"], matches["post_n1"] || matches["post_n2"])
  @dev = parse_letter_version(matches["dev_l"], matches["dev_n"])
  @local = parse_local_version(matches["local"])
  super(matches["release"] || "")
end

Instance Attribute Details

#devObject (readonly)

Returns the value of attribute dev.



19
20
21
# File 'lib/dependabot/python/version.rb', line 19

def dev
  @dev
end

#epochObject (readonly)

Returns the value of attribute epoch.



13
14
15
# File 'lib/dependabot/python/version.rb', line 13

def epoch
  @epoch
end

#localObject (readonly)

Returns the value of attribute local.



28
29
30
# File 'lib/dependabot/python/version.rb', line 28

def local
  @local
end

#postObject (readonly)

Returns the value of attribute post.



25
26
27
# File 'lib/dependabot/python/version.rb', line 25

def post
  @post
end

#preObject (readonly)

Returns the value of attribute pre.



22
23
24
# File 'lib/dependabot/python/version.rb', line 22

def pre
  @pre
end

#release_segmentObject (readonly)

Returns the value of attribute release_segment.



16
17
18
# File 'lib/dependabot/python/version.rb', line 16

def release_segment
  @release_segment
end

Class Method Details

.correct?(version) ⇒ Boolean

Returns:

  • (Boolean)


68
69
70
71
72
# File 'lib/dependabot/python/version.rb', line 68

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

  version.to_s.match?(ANCHORED_VERSION_PATTERN)
end

.new(version) ⇒ Object



99
100
101
# File 'lib/dependabot/python/version.rb', line 99

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

Instance Method Details

#<=>(other) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/dependabot/python/version.rb', line 124

def <=>(other)
  other = Dependabot::Python::Version.new(other.to_s) unless other.is_a?(Dependabot::Python::Version)
  other = T.cast(other, Dependabot::Python::Version)

  epoch_comparison = epoch <=> other.epoch
  return epoch_comparison unless epoch_comparison.zero?

  release_comparison = release_version_comparison(other)
  return release_comparison unless release_comparison.zero?

  pre_comparison = compare_keys(pre_cmp_key, other.pre_cmp_key)
  return pre_comparison unless pre_comparison.zero?

  post_comparison = compare_keys(post_cmp_key, other.post_cmp_key)
  return post_comparison unless post_comparison.zero?

  dev_comparison = compare_keys(dev_cmp_key, other.dev_cmp_key)
  return dev_comparison unless dev_comparison.zero?

  compare_keys(local_cmp_key, other.local_cmp_key)
end

#compare_keys(key, other_key) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
# File 'lib/dependabot/python/version.rb', line 152

def compare_keys(key, other_key)
  if key.is_a?(Integer) && other_key.is_a?(Integer)
    key <=> other_key
  elsif key.is_a?(Array) && other_key.is_a?(Array)
    key <=> other_key
  elsif key.is_a?(Integer)
    key == NEGATIVE_INFINITY ? -1 : 1
  elsif other_key.is_a?(Integer)
    other_key == NEGATIVE_INFINITY ? 1 : -1
  end
end

#dev_cmp_keyObject



205
206
207
208
209
210
# File 'lib/dependabot/python/version.rb', line 205

def dev_cmp_key
  # Versions without a dev segment should sort after those with one.
  return INFINITY if dev.nil?

  T.must(dev)
end

#ignored_major_versionsObject



241
242
243
244
245
246
247
# File 'lib/dependabot/python/version.rb', line 241

def ignored_major_versions
  version_parts = release_segment # e.g [1,2,3] if version is 1.2.3-alpha3
  lower_parts = [version_parts[0].to_i + 1] + [lowest_prerelease_suffix] # earliest next major version prerelease
  lower_bound = ">= #{lower_parts.join('.')}"

  [lower_bound]
end

#ignored_minor_versionsObject



229
230
231
232
233
234
235
236
237
238
# File 'lib/dependabot/python/version.rb', line 229

def ignored_minor_versions
  parts = release_segment # e.g [1,2,3] if version is 1.2.3-alpha3
  version_parts = parts.fill(0, parts.length...2)
  lower_parts = version_parts.first(1) + [version_parts[1].to_i + 1] + [lowest_prerelease_suffix]
  upper_parts = version_parts.first(0) + [version_parts[0].to_i + 1] + [lowest_prerelease_suffix]
  lower_bound = ">= #{lower_parts.join('.')}"
  upper_bound = "< #{upper_parts.join('.')}"

  ["#{lower_bound}, #{upper_bound}"]
end

#ignored_patch_versionsObject



218
219
220
221
222
223
224
225
226
# File 'lib/dependabot/python/version.rb', line 218

def ignored_patch_versions
  parts = release_segment # e.g [1,2,3] if version is 1.2.3-alpha3
  version_parts = parts.fill(0, parts.length...2)
  upper_parts = version_parts.first(1) + [version_parts[1].to_i + 1] + [lowest_prerelease_suffix]
  lower_bound = "> #{self}"
  upper_bound = "< #{upper_parts.join('.')}"

  ["#{lower_bound}, #{upper_bound}"]
end

#inspectObject

:nodoc:



109
110
111
# File 'lib/dependabot/python/version.rb', line 109

def inspect # :nodoc:
  "#<#{self.class} #{@version_string}>"
end

#local_cmp_keyObject



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/dependabot/python/version.rb', line 176

def local_cmp_key
  if local.nil?
    # Versions without a local segment should sort before those with one.
    NEGATIVE_INFINITY
  else
    # According to PEP440.
    # - Alphanumeric segments sort before numeric segments
    # - Alphanumeric segments sort lexicographically
    # - Numeric segments sort numerically
    # - Shorter versions sort before longer versions when the prefixes match exactly
    local&.map do |token|
      if token.is_a?(Integer)
        [token, ""]
      else
        [NEGATIVE_INFINITY, token]
      end
    end
  end
end

#lowest_prerelease_suffixObject



213
214
215
# File 'lib/dependabot/python/version.rb', line 213

def lowest_prerelease_suffix
  "dev0"
end

#post_cmp_keyObject



197
198
199
200
201
202
# File 'lib/dependabot/python/version.rb', line 197

def post_cmp_key
  # Versions without a post segment should sort before those with one.
  return NEGATIVE_INFINITY if post.nil?

  T.must(post)
end

#pre_cmp_keyObject



165
166
167
168
169
170
171
172
173
# File 'lib/dependabot/python/version.rb', line 165

def pre_cmp_key
  if pre.nil? && post.nil? && dev # sort 1.0.dev0 before 1.0a0
    NEGATIVE_INFINITY
  elsif pre.nil?
    INFINITY # versions without a pre-release should sort after those with one.
  else
    T.must(pre)
  end
end

#prerelease?Boolean

Returns:

  • (Boolean)


114
115
116
# File 'lib/dependabot/python/version.rb', line 114

def prerelease?
  !!(pre || dev)
end

#releaseObject



119
120
121
# File 'lib/dependabot/python/version.rb', line 119

def release
  Dependabot::Python::Version.new(release_segment.join("."))
end

#to_sObject



104
105
106
# File 'lib/dependabot/python/version.rb', line 104

def to_s
  @version_string
end