Class: Version::Number
- Inherits:
-
Object
- Object
- Version::Number
- Includes:
- Comparable, Enumerable
- Defined in:
- lib/versus/number.rb
Overview
Represents a versiou number. Developer SHOULD use three point SemVer standard, but this class is mildly flexible in it’s support for variations.
Constant Summary collapse
- STATES =
Recognized build states in order of completion. This is only used when by #bump_state.
['alpha', 'beta', 'pre', 'rc']
Instance Attribute Summary collapse
-
#tuple ⇒ Object
readonly
Return the undelying segments array.
Class Method Summary collapse
-
.[](*args) ⇒ Object
Shortcut for creating a new verison number given segmented elements.
- .cmp(version1, version2) ⇒ Object
-
.parse(version) ⇒ Version
Parses a version string.
Instance Method Summary collapse
-
#<=>(other) ⇒ Object
Compare versions.
-
#=~(other) ⇒ Object
For pessimistic constraint (like ‘~>’ in gems).
-
#[](index) ⇒ Object
Fetch a sepecific segement by index number.
- #alpha? ⇒ Boolean
- #beta? ⇒ Boolean
-
#build ⇒ Object
The build.
- #build=(point) ⇒ Object
-
#build_number ⇒ Object
Return the state revision count.
-
#bump(which = :patch) ⇒ Object
Bump the version returning a new version number object.
- #bump_at(index) ⇒ Object
- #bump_build ⇒ Object
-
#bump_build_number ⇒ Object
revision.
- #bump_last ⇒ Object
- #bump_major ⇒ Object
- #bump_minor ⇒ Object
- #bump_patch ⇒ Object
- #bump_state ⇒ Object (also: #bump_status)
-
#crush? ⇒ Boolean
Does the version string representation compact string segments with the subsequent number segement?.
-
#crush_point(string) ⇒ Object
private
Take a point string rendering of a version and crush it!.
-
#each(&block) ⇒ Object
Iterate of each segment of the version.
-
#eql?(other) ⇒ Boolean
Strict equality.
- #hash ⇒ Object
-
#inc(val) ⇒ Object
private
Segement incrementor.
-
#initialize(*points) ⇒ Number
constructor
Creates a new version.
-
#inspect ⇒ Object
Returns a String detaling the version number.
-
#major ⇒ Object
Major version number.
- #major=(number) ⇒ Object
-
#match?(*constraints) ⇒ Boolean
Does this version match a given constraint? The constraint is a String in the form of “operator number”.
-
#minor ⇒ Object
Minor version number.
- #minor=(number) ⇒ Object
-
#patch ⇒ Object
Patch version number.
- #patch=(number) ⇒ Object
- #prerelease? ⇒ Boolean
- #release_candidate? ⇒ Boolean
-
#restate(state, revision = 1) ⇒ Object
Return a new version have the same major, minor and patch levels, but with a new state and revision count.
-
#sane_point(point) ⇒ Object
private
Convert a segment into an integer or string.
-
#size ⇒ Object
Return the number of version segements.
- #stable? ⇒ Boolean (also: #stable_release?)
- #state ⇒ Object (also: #status)
-
#state_index ⇒ Object
private
Return the index of the first recognized state.
-
#to_a ⇒ Object
Returns a duplicate of the underlying version tuple.
-
#to_s ⇒ Object
Converts version to a dot-separated string.
-
#to_str ⇒ Object
This method is the same as #to_s.
-
#to_yaml(opts = {}) ⇒ String
Converts the version to YAML.
Constructor Details
#initialize(*points) ⇒ Number
Creates a new version.
29 30 31 32 33 34 35 |
# File 'lib/versus/number.rb', line 29 def initialize(*points) @crush = false points.map! do |point| sane_point(point) end @tuple = points.flatten.compact end |
Instance Attribute Details
#tuple ⇒ Object (readonly)
Return the undelying segments array.
479 480 481 |
# File 'lib/versus/number.rb', line 479 def tuple @tuple end |
Class Method Details
.[](*args) ⇒ Object
Shortcut for creating a new verison number given segmented elements.
VersionNumber[1,0,0].to_s
#=> "1.0.0"
VersionNumber[1,0,0,:pre,2].to_s
#=> "1.0.0.pre.2"
53 54 55 |
# File 'lib/versus/number.rb', line 53 def self.[](*args) new(*args) end |
.cmp(version1, version2) ⇒ Object
78 79 80 |
# File 'lib/versus/number.rb', line 78 def self.cmp(version1, version2) # TODO: class level compare might be handy end |
Instance Method Details
#<=>(other) ⇒ Object
Compare versions.
270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/versus/number.rb', line 270 def <=>(other) [@tuple.size, other.size].max.times do |i| p1, p2 = (@tuple[i] || 0), (other[i] || 0) # this is bit tricky, basically a string < integer. if p1.class != p2.class cmp = p2.to_s <=> p1.to_s else cmp = p1 <=> p2 end return cmp unless cmp == 0 end #(@tuple.size <=> other.size) * -1 return 0 end |
#=~(other) ⇒ Object
For pessimistic constraint (like ‘~>’ in gems).
FIXME: Ensure it can handle trailing state.
288 289 290 291 292 293 294 295 296 |
# File 'lib/versus/number.rb', line 288 def =~(other) upver = other.bump(:last) if other.size > 1 upver = other.bump(-2) else end self >= other and self < upver end |
#[](index) ⇒ Object
199 200 201 |
# File 'lib/versus/number.rb', line 199 def [](index) @tuple.fetch(index,0) end |
#alpha? ⇒ Boolean
166 167 168 169 |
# File 'lib/versus/number.rb', line 166 def alpha? s = status.dowcase s == 'alpha' or s == 'a' end |
#beta? ⇒ Boolean
172 173 174 175 |
# File 'lib/versus/number.rb', line 172 def beta? s = status.dowcase s == 'beta' or s == 'b' end |
#build ⇒ Object
The build.
98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/versus/number.rb', line 98 def build if b = state_index str = @tuple[b..-1].join('.') str = crush_point(str) if crush? str elsif @tuple[3].nil? nil else str = @tuple[3..-1].join('.') str = crush_point(str) if crush? str end end |
#build=(point) ⇒ Object
154 155 156 |
# File 'lib/versus/number.rb', line 154 def build=(point) @tuple = @tuple[0...state_index] + sane_point(point) end |
#build_number ⇒ Object
126 127 128 129 130 131 132 |
# File 'lib/versus/number.rb', line 126 def build_number #revision if i = state_index self[i+1] || 0 else nil end end |
#bump(which = :patch) ⇒ Object
Bump the version returning a new version number object. Select which
segement to bump by name: major
, minor
, patch
, state
, build
and also last
.
Version::Number[1,2,0].bump(:patch).to_s
#=> "1.2.1"
Version::Number[1,2,1].bump(:minor).to_s
#=> "1.3.0"
Version::Number[1,3,0].bump(:major).to_s
#=> "2.0.0"
Version::Number[1,3,0,:pre,1].bump(:build).to_s
#=> "1.3.0.pre.2"
Version::Number[1,3,0,:pre,2].bump(:state).to_s
#=> "1.3.0.rc.1"
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
# File 'lib/versus/number.rb', line 339 def bump(which=:patch) which = which.to_sym unless Integer === which case which when Integer bump_at(which) when :major, :first bump_major when :minor bump_minor when :patch bump_patch when :state, :status bump_state when :build bump_build when :revision bump_revision when :last bump_last else # TODO: why is this not an error? self.class.new(@tuple.dup.compact) end end |
#bump_at(index) ⇒ Object
381 382 383 384 385 386 387 388 |
# File 'lib/versus/number.rb', line 381 def bump_at(index) i = index if n = inc(@tuple[i]) v = @tuple[0...i] + [n] + (@tuple[i+1] ? [1] : []) else v = @tuple[0...i] end end |
#bump_build ⇒ Object
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
# File 'lib/versus/number.rb', line 408 def bump_build if i = state_index if i == @tuple.size - 1 v = @tuple + [1] else v = @tuple[0...-1] + [inc(@tuple.last)] end else if @tuple.size <= 3 v = @tuple + [1] else v = @tuple[0...-1] + [inc(@tuple.last)] end end self.class.new(v.compact) end |
#bump_build_number ⇒ Object
revision
426 427 428 429 430 431 432 433 |
# File 'lib/versus/number.rb', line 426 def bump_build_number #revision if i = state_index v = @tuple[0...-1] + [inc(@tuple.last)] else v = @tuple[0..2] + ['alpha', 1] end self.class.new(v.compact) end |
#bump_last ⇒ Object
436 437 438 439 |
# File 'lib/versus/number.rb', line 436 def bump_last v = @tuple[0...-1] + [inc(@tuple.last)] self.class.new(v.compact) end |
#bump_major ⇒ Object
366 367 368 |
# File 'lib/versus/number.rb', line 366 def bump_major self.class[inc(major), 0, 0] end |
#bump_minor ⇒ Object
371 372 373 |
# File 'lib/versus/number.rb', line 371 def bump_minor self.class[major, inc(minor), 0] end |
#bump_patch ⇒ Object
376 377 378 |
# File 'lib/versus/number.rb', line 376 def bump_patch self.class[major, minor, inc(patch)] end |
#bump_state ⇒ Object Also known as: bump_status
391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/versus/number.rb', line 391 def bump_state if i = state_index if n = inc(@tuple[i]) v = @tuple[0...i] + [n] + (@tuple[i+1] ? [1] : []) else v = @tuple[0...i] end else v = @tuple.dup end self.class.new(v.compact) end |
#crush? ⇒ Boolean
Does the version string representation compact string segments with the subsequent number segement?
461 462 463 |
# File 'lib/versus/number.rb', line 461 def crush? @crush end |
#crush_point(string) ⇒ Object (private)
Take a point string rendering of a version and crush it!
505 506 507 |
# File 'lib/versus/number.rb', line 505 def crush_point(string) string.gsub(/(^|\.)(\D+)\.(\d+)(\.|$)/, '\2\3') end |
#each(&block) ⇒ Object
307 308 309 |
# File 'lib/versus/number.rb', line 307 def each(&block) @tuple.each(&block) end |
#eql?(other) ⇒ Boolean
Strict equality.
260 261 262 |
# File 'lib/versus/number.rb', line 260 def eql?(other) @tuple = other.tuple end |
#hash ⇒ Object
40 41 42 |
# File 'lib/versus/number.rb', line 40 def hash @tuple.hash end |
#inc(val) ⇒ Object (private)
Segement incrementor.
525 526 527 528 529 530 531 |
# File 'lib/versus/number.rb', line 525 def inc(val) if i = STATES.index(val.to_s) STATES[i+1] else val.succ end end |
#inspect ⇒ Object
Returns a String detaling the version number. Essentially it is the same as #to_s.
VersionNumber[1,2,0].inspect
#=> "1.2.0"
237 238 239 |
# File 'lib/versus/number.rb', line 237 def inspect to_s end |
#major ⇒ Object
Major version number
83 84 85 |
# File 'lib/versus/number.rb', line 83 def major (state_index && state_index == 0) ? nil : self[0] end |
#major=(number) ⇒ Object
136 137 138 |
# File 'lib/versus/number.rb', line 136 def major=(number) @tuple[0] = number.to_i end |
#match?(*constraints) ⇒ Boolean
Does this version match a given constraint? The constraint is a String in the form of “operator number”. – TODO: match? will change as Constraint class is improved. ++
470 471 472 473 474 |
# File 'lib/versus/number.rb', line 470 def match?(*constraints) constraints.all? do |c| Constraint.constraint_lambda(c).call(self) end end |
#minor ⇒ Object
Minor version number
88 89 90 |
# File 'lib/versus/number.rb', line 88 def minor (state_index && state_index <= 1) ? nil : self[1] end |
#minor=(number) ⇒ Object
142 143 144 |
# File 'lib/versus/number.rb', line 142 def minor=(number) @tuple[1] = number.to_i end |
#patch ⇒ Object
Patch version number
93 94 95 |
# File 'lib/versus/number.rb', line 93 def patch (state_index && state_index <= 2) ? nil : self[2] end |
#patch=(number) ⇒ Object
148 149 150 |
# File 'lib/versus/number.rb', line 148 def patch=(number) @tuple[2] = number.to_i end |
#prerelease? ⇒ Boolean
178 179 180 |
# File 'lib/versus/number.rb', line 178 def prerelease? status == 'pre' end |
#release_candidate? ⇒ Boolean
183 184 185 |
# File 'lib/versus/number.rb', line 183 def release_candidate? status == 'rc' end |
#restate(state, revision = 1) ⇒ Object
450 451 452 453 454 455 456 457 |
# File 'lib/versus/number.rb', line 450 def restate(state, revision=1) if i = state_index v = @tuple[0...i] + [state.to_s] + [revision] else v = @tuple[0...3] + [state.to_s] + [revision] end self.class.new(v) end |
#sane_point(point) ⇒ Object (private)
Convert a segment into an integer or string.
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/versus/number.rb', line 484 def sane_point(point) point = point.to_s if Symbol === point case point when Integer point when /[.]/ point.split('.').map{ |p| sane_point(p) } when /^\d+$/ point.to_i when /^(\d+)(\w+)(\d+)$/ @crush = true [$1.to_i, $2, $3.to_i] when /^(\w+)(\d+)$/ @crush = true [$1, $2.to_i] else point end end |
#size ⇒ Object
316 317 318 |
# File 'lib/versus/number.rb', line 316 def size @tuple.size end |
#stable? ⇒ Boolean Also known as: stable_release?
159 160 161 |
# File 'lib/versus/number.rb', line 159 def stable? build.nil? end |
#state ⇒ Object Also known as: status
113 114 115 |
# File 'lib/versus/number.rb', line 113 def state state_index ? @tuple[state_index] : nil end |
#state_index ⇒ Object (private)
Return the index of the first recognized state.
VersionNumber[1,2,3,'pre',3].state_index
#=> 3
You might ask why this is needed, since the state position should always be 3. However, there isn’t always a state entry, which means this method will return nil
, and we also leave open the potential for extra-long version numbers –though we do not recommend the idea, it is possible.
520 521 522 |
# File 'lib/versus/number.rb', line 520 def state_index @tuple.index{ |s| String === s } end |
#to_a ⇒ Object
Returns a duplicate of the underlying version tuple.
205 206 207 |
# File 'lib/versus/number.rb', line 205 def to_a @tuple.dup end |
#to_s ⇒ Object
215 216 217 218 219 |
# File 'lib/versus/number.rb', line 215 def to_s str = @tuple.compact.join('.') str = crush_point(str) if crush? return str end |
#to_str ⇒ Object
This method is the same as #to_s. It is here becuase ‘File.join` calls it instead of #to_s.
VersionNumber[1,2,0].to_str
#=> "1.2.0"
227 228 229 |
# File 'lib/versus/number.rb', line 227 def to_str to_s end |
#to_yaml(opts = {}) ⇒ String
Converts the version to YAML.
– TODO: Should this be here? ++
253 254 255 |
# File 'lib/versus/number.rb', line 253 def to_yaml(opts={}) to_s.to_yaml(opts) end |