Class: QB::Package::Version

Inherits:
Util::Resource show all
Includes:
Comparable, Util::DockerMixin
Defined in:
lib/qb/package/version.rb

Direct Known Subclasses

Leveled

Defined Under Namespace

Modules: From Classes: Leveled

Constant Summary collapse

NUMBER_IDENTIFIER_RE =

Pattern to match string identifiers that are version "numlets" (the non-negative integer number part of version "numbers").

Returns:

  • (Regexp)
/\A(?:0|(?:[1-9]\d*))\z/
IDENTIFIER_SEPARATOR =

What separates identifiers (the base undivided values).

Returns:

  • (String)
'.'
NUMBER_SEGMENT =
t.non_neg_int
NAME_SEGMENT =
t.str & /\A[0-9A-Za-z\-]+\z/
MIXED_SEGMENT =
t.xor NUMBER_SEGMENT, NAME_SEGMENT
POSSIBLE_VERSION_RE =

Reasonably simple regular expression to extract things that might be versions from strings.

Intended for use on reasonably short strings like git tag output or what-not... probably not well suited for sifting through mountains of text.

Structure:

  1. The major version number, matched by a digit 1-9 followed by any number of digits.
  2. A separator to the next segment, which is:
    1. . separating to the minor version number
    2. - separating to the prerelease
    3. + separating to the build
  3. One or more of a-z, A-Z, 0-9, ., -, _, +
  4. Ends with one of those that is not ., _ or +, so a-z, A-Z, 0-9.

This will match many strings that are not versions, but it should not miss any that are. It cold obviously be refined and improve to reduce false positives at the cost of additional complexity, but I wanted to start simple and complicate it as needed.

Returns:

  • (Regexp)
/(?:0|[1-9]\d*)[\.\-\+][a-zA-Z0-9\.\-\_\+]*[a-zA-Z0-9\-]+/

Constants included from Util::DockerMixin

Util::DockerMixin::DOCKER_TAG_MAX_CHARACTERS, Util::DockerMixin::DOCKER_TAG_VALID_RE

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::DockerMixin

included

Methods inherited from Util::Resource

#initialize

Constructor Details

This class inherits a constructor from QB::Util::Resource

Class Method Details

.extract(string) ⇒ Array<QB::Package::Version] Any versions extracted from the string.

Extract version number from a string.

Parameters:

  • string (String)

    String containing versions.

Returns:



285
286
287
288
289
290
291
292
293
# File 'lib/qb/package/version.rb', line 285

def self.extract string
  string.scan( POSSIBLE_VERSION_RE ).map { |possible_version_string|
    begin
      from possible_version_string
    rescue
      nil
    end
  }.compact
end

.from(object) ⇒ Object

Utilities



251
252
253
# File 'lib/qb/package/version.rb', line 251

def self.from object
  QB::Package::Version::From.object object
end

.from_string(string) ⇒ Object



258
259
260
# File 'lib/qb/package/version.rb', line 258

def self.from_string string
  QB::Package::Version::From.string string
end

.to_time_segment(time) ⇒ String

Time formatted to be stuck in a version segment per Semver spec. We also strip out '-' to avoid possible parsing weirdness.

Returns:

  • (String)


272
273
274
# File 'lib/qb/package/version.rb', line 272

def self.to_time_segment time
  time.utc.iso8601.gsub /[^0-9A-Za-z]/, ''
end

Instance Method Details

#<=>(other) ⇒ Object



468
469
470
# File 'lib/qb/package/version.rb', line 468

def <=> other
  to_a <=> other.to_a
end

#==(other) ⇒ Boolean

Test for equality.

Compares classes then #to_a results.

Parameters:

  • other (Object)

    Object to compare to self.

Returns:

  • (Boolean)

    True if self and other are considered equal.



462
463
464
465
# File 'lib/qb/package/version.rb', line 462

def == other
  other.class == self.class &&
  other.to_a == self.to_a
end

#build?Boolean

"Gem" version format, so this will always be false when loading a Gem version.

Returns:

  • (Boolean)

    True if any build segments are present (stuff after '+' character in SemVer / "NPM" format). Tests if @build is empty.

    As of writing, we don't have a way to convey build segments in



329
330
331
# File 'lib/qb/package/version.rb', line 329

def build?
  !build.empty?
end

#build_commitreturn_type

TODO:

Document commit method.

Returns @todo Document return value.

Parameters:

  • arg_name (type)

    @todo Add name param description.

Returns:

  • (return_type)

    @todo Document return value.



384
385
386
387
388
# File 'lib/qb/package/version.rb', line 384

def build_commit
  if build?
    build.find { |seg| seg =~ /[0-9a-f]{7}/ }
  end
end

#build_dirty?Boolean Also known as: dirty?

Is the build "dirty"?

Returns:

  • (Boolean)


338
339
340
341
342
# File 'lib/qb/package/version.rb', line 338

def build_dirty?
  if build?
    build.any? { |seg| seg.is_a?( String ) && seg.include?( 'dirty' ) }
  end
end

#build_version(*build, branch: nil, ref: nil, time: nil, dirty: nil) ⇒ QB::Package::Version

Return a new QB::Package::Version with build information added.



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
# File 'lib/qb/package/version.rb', line 422

def build_version *build, branch: nil, ref: nil, time: nil, dirty: nil
  
  repo_segments = [
    branch,
    ref,
    ('dirty' if dirty),
    (self.class.to_time_segment(time) if dirty && time),
  ].compact
  
  if repo_segments.empty?
    raise ArgumentError,
          "Need to provide at least one of branch, ref, dirty."
  end
  
  merge raw: nil, build: [*build, repo_segments.join( '-' )]
end

#docker_tagString

Docker image tag for the version.

See Util::DockerMixin::ClassMethods#to_docker_tag.

Returns:

  • (String)


397
398
399
# File 'lib/qb/package/version.rb', line 397

def docker_tag
  self.class.to_docker_tag semver
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


509
510
511
# File 'lib/qb/package/version.rb', line 509

def eql? other
  self == other && self.hash == other.hash
end

#hashObject



504
505
506
# File 'lib/qb/package/version.rb', line 504

def hash
  to_a.hash
end

#prerelease?Boolean

Returns True if any prerelease segments are present (stuff after '-' in SemVer / "NPM" format, or the first string segment and anything following it in "Gem" format). Tests if @prerelease is not empty.

Returns:

  • (Boolean)

    True if any prerelease segments are present (stuff after '-' in SemVer / "NPM" format, or the first string segment and anything following it in "Gem" format). Tests if @prerelease is not empty.



316
317
318
# File 'lib/qb/package/version.rb', line 316

def prerelease?
  !prerelease.empty?
end

#prerelease_versionQB::Package::Version

Returns A new QB::Package::Version created from #release and #prerelease data, but without any build information.

Returns:



444
445
446
# File 'lib/qb/package/version.rb', line 444

def prerelease_version
  merge raw: nil, build: []
end

#releaseObject

Derived Properties



350
351
352
# File 'lib/qb/package/version.rb', line 350

def release
  [major, minor, patch, *revision].join '.'
end

#release?Boolean

Returns True if this version is a release (no prerelease or build values).

Returns:

  • (Boolean)

    True if this version is a release (no prerelease or build values).



305
306
307
# File 'lib/qb/package/version.rb', line 305

def release?
  prerelease.empty? && build.empty?
end

#release_versionQB::Package::Version

Returns A new QB::Package::Version created from #release. Even if self is a release version already, still returns a new instance.

Returns:



413
414
415
# File 'lib/qb/package/version.rb', line 413

def release_version
  self.class.from release
end

#semverString Also known as: normalized

Returns The Semver version string (Major.minor.patch-prerelease+build format).

Returns:

  • (String)

    The Semver version string (Major.minor.patch-prerelease+build format).



359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/qb/package/version.rb', line 359

def semver
  result = release
  
  unless prerelease.empty?
    result += "-#{ prerelease.join '.' }"
  end
  
  unless build.empty?
    result += "+#{ build.join '.' }"
  end
  
  result
end

#to_aArray

Return array of the version elements in order from greatest to least precedence.

This is considered the representative structure for the object's data, from which all other values are dependently derived, and is used in #==, #hash and #eql?.

Examples:


version = QB::Package::Version.from "0.1.2-rc.10+master.0ab1c3d"

version.to_a
# => [0, 1, 2, ['rc', 10], ['master', '0ab1c3d']]

QB::Package::Version.from( '1' ).to_a
# => [1, nil, nil, [], []]

Returns:

  • (Array)


492
493
494
495
496
497
498
499
500
501
# File 'lib/qb/package/version.rb', line 492

def to_a
  [
    major,
    minor,
    patch,
    revision,
    prerelease,
    build,
  ]
end

#to_sObject



514
515
516
# File 'lib/qb/package/version.rb', line 514

def to_s
  "#<QB::Package::Version semver=#{ semver } raw=#{ @raw }>"
end