Module: Philiprehberger::VersionCompare

Defined in:
lib/philiprehberger/version_compare.rb,
lib/philiprehberger/version_compare/version.rb

Defined Under Namespace

Classes: Error, SemanticVersion

Constant Summary collapse

VERSION =
'0.5.0'

Class Method Summary collapse

Class Method Details

.compatible?(baseline, candidate) ⇒ Boolean

Check whether two versions are API-compatible per SemVer.

Two versions are considered compatible when:

  • both share the same major component, AND

  • the candidate is greater than or equal to the baseline (so it has every API the baseline expects)

When the baseline is pre-1.0.0 (major == 0), SemVer considers every minor bump potentially breaking; in that regime compatibility additionally requires the same minor component, matching the ‘~>` (pessimistic) constraint behavior.

Parameters:

Returns:

  • (Boolean)

    true when ‘candidate` is API-compatible with `baseline`



242
243
244
245
246
247
248
249
250
# File 'lib/philiprehberger/version_compare.rb', line 242

def self.compatible?(baseline, candidate)
  base = baseline.is_a?(SemanticVersion) ? baseline : parse(baseline)
  cand = candidate.is_a?(SemanticVersion) ? candidate : parse(candidate)

  return false unless base.major == cand.major
  return false if cand < base

  base.major.zero? ? base.minor == cand.minor : true
end

.filter(versions, constraint) ⇒ Array<String>

Filter an array of version strings by a constraint

Parameters:

  • versions (Array<String>)

    version strings to filter

  • constraint (String)

    constraint like “>= 1.0.0”, “~> 2.1”

Returns:

  • (Array<String>)

    versions that satisfy the constraint



224
225
226
# File 'lib/philiprehberger/version_compare.rb', line 224

def self.filter(versions, constraint)
  versions.select { |v| parse(v).satisfies?(constraint) }
end

.highest_satisfying(versions, constraint) ⇒ String?

Return the highest version from an array that satisfies a constraint

Performs a single pass over versions, tracking the maximum parsed version whose parsed form satisfies the constraint. Pre-release and stable resolution follow the same precedence used by sort and latest (pre-release versions rank lower than their stable counterparts per SemVer).

Parameters:

  • versions (Array<String>)

    version strings to search

  • constraint (String)

    constraint like “>= 1.0.0”, “~> 2.1”

Returns:

  • (String, nil)

    the highest version string that satisfies the constraint, or nil if versions is empty or nothing matches



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/philiprehberger/version_compare.rb', line 264

def self.highest_satisfying(versions, constraint)
  best_raw = nil
  best_parsed = nil

  versions.each do |v|
    parsed = parse(v)
    next unless parsed.satisfies?(constraint)

    if best_parsed.nil? || parsed > best_parsed
      best_parsed = parsed
      best_raw = v
    end
  end

  best_raw
end

.latest(versions) ⇒ String

Return the latest version from an array of version strings

Parameters:

  • versions (Array<String>)

    version strings

Returns:

  • (String)

    the latest version string

Raises:

  • (Error)

    if the array is empty



195
196
197
198
199
# File 'lib/philiprehberger/version_compare.rb', line 195

def self.latest(versions)
  raise Error, 'no versions provided' if versions.empty?

  versions.max_by { |v| parse(v) }
end

.max(versions) ⇒ SemanticVersion?

Return the highest version from an array of versions

Parameters:

Returns:



214
215
216
217
# File 'lib/philiprehberger/version_compare.rb', line 214

def self.max(versions)
  parsed = versions.map { |v| v.is_a?(SemanticVersion) ? v : parse(v) }
  parsed.max
end

.min(versions) ⇒ SemanticVersion?

Return the lowest version from an array of versions

Parameters:

Returns:



205
206
207
208
# File 'lib/philiprehberger/version_compare.rb', line 205

def self.min(versions)
  parsed = versions.map { |v| v.is_a?(SemanticVersion) ? v : parse(v) }
  parsed.min
end

.parse(str) ⇒ SemanticVersion

Parse a version string into a SemanticVersion

Parameters:

  • str (String)

    version string like “1.2.3”, “1.2.3-beta.1”, or “1.2.3+build.123”

Returns:

Raises:

  • (Error)

    if the string is not a valid version



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/philiprehberger/version_compare.rb', line 166

def self.parse(str)
  str = str.to_s.strip
  str = str.sub(/\Av/, '')

  match = str.match(/\A(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([a-zA-Z0-9.]+))?(?:\+([a-zA-Z0-9.]+))?\z/)
  raise Error, "invalid version: #{str}" unless match

  SemanticVersion.new(
    match[1].to_i,
    (match[2] || '0').to_i,
    (match[3] || '0').to_i,
    pre_release: match[4],
    build_metadata: match[5]
  )
end

.sort(versions) ⇒ Array<String>

Sort an array of version strings

Parameters:

  • versions (Array<String>)

    version strings to sort

Returns:

  • (Array<String>)

    sorted version strings (ascending)



186
187
188
# File 'lib/philiprehberger/version_compare.rb', line 186

def self.sort(versions)
  versions.sort_by { |v| parse(v) }
end