Class: QB::Package::Version

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

Overview

An attempt to unify NPM and Gem version schemes to a reasonable extend, and hopefully cover whatever else the cat may drag in.

Intended to be immutable for practical purposes.

Direct Known Subclasses

Leveled

Defined Under Namespace

Modules: From Classes: Leveled

Constant Summary collapse

NUMBER_SEGMENT =

Constants

t.non_neg_int
NAME_SEGMENT =
t.str
MIXED_SEGMENT =
t.union 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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util::DockerMixin

included

Instance Attribute Details

#releaseObject (readonly)

Derived Properties



112
113
114
# File 'lib/qb/package/version.rb', line 112

def release
  @release
end

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:



155
156
157
158
159
160
161
162
163
# File 'lib/qb/package/version.rb', line 155

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



121
122
123
# File 'lib/qb/package/version.rb', line 121

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

.from_string(string) ⇒ Object



128
129
130
# File 'lib/qb/package/version.rb', line 128

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)


142
143
144
# File 'lib/qb/package/version.rb', line 142

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

Instance Method Details

#<=>(other) ⇒ Object



341
342
343
# File 'lib/qb/package/version.rb', line 341

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.



335
336
337
338
# File 'lib/qb/package/version.rb', line 335

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



199
200
201
# File 'lib/qb/package/version.rb', line 199

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.



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

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

#build_dirty?return_type

TODO:

Document build_dirty? method.

Returns @todo Document return value.

Parameters:

  • arg_name (type)

    @todo Add name param description.

Returns:

  • (return_type)

    @todo Document return value.



212
213
214
215
216
# File 'lib/qb/package/version.rb', line 212

def build_dirty?
  if build?
    build.include? 'dirty'
  end
end

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

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



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/qb/package/version.rb', line 294

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

#docker_tagString

Docker image tag for the version.

See Util::DockerMixin::ClassMethods#to_docker_tag.

Returns:

  • (String)


269
270
271
# File 'lib/qb/package/version.rb', line 269

def docker_tag
  self.class.to_docker_tag semver
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


381
382
383
# File 'lib/qb/package/version.rb', line 381

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

#hashObject



376
377
378
# File 'lib/qb/package/version.rb', line 376

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.



186
187
188
# File 'lib/qb/package/version.rb', line 186

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:



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

def prerelease_version
  merge raw: nil, build: []
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).



175
176
177
# File 'lib/qb/package/version.rb', line 175

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:



285
286
287
# File 'lib/qb/package/version.rb', line 285

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



231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/qb/package/version.rb', line 231

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)


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

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

#to_sObject



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

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