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



480
481
482
# File 'lib/qb/package/version.rb', line 480

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.



474
475
476
477
# File 'lib/qb/package/version.rb', line 474

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.



389
390
391
392
393
# File 'lib/qb/package/version.rb', line 389

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.



429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
# File 'lib/qb/package/version.rb', line 429

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

#docker_tagString

Docker image tag for the version.

See Util::DockerMixin::ClassMethods#to_docker_tag.

Returns:

  • (String)


402
403
404
# File 'lib/qb/package/version.rb', line 402

def docker_tag
  self.class.to_docker_tag semver
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


521
522
523
# File 'lib/qb/package/version.rb', line 521

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

#hashObject



516
517
518
# File 'lib/qb/package/version.rb', line 516

def hash
  to_a.hash
end

#level?Boolean

Returns:

  • (Boolean)


347
348
349
# File 'lib/qb/package/version.rb', line 347

def level?
  is_a? QB::Package::Version::Leveled
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:



456
457
458
# File 'lib/qb/package/version.rb', line 456

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

#releaseObject

Derived Properties



355
356
357
# File 'lib/qb/package/version.rb', line 355

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:



418
419
420
# File 'lib/qb/package/version.rb', line 418

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).



364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/qb/package/version.rb', line 364

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)


504
505
506
507
508
509
510
511
512
513
# File 'lib/qb/package/version.rb', line 504

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

#to_sObject



526
527
528
# File 'lib/qb/package/version.rb', line 526

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