Class: Indexer::Version::Number
- Inherits:
-
Object
- Object
- Indexer::Version::Number
- Includes:
- Comparable, Enumerable
- Defined in:
- lib/indexer/version/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']
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_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.
-
#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.
24 25 26 27 28 29 30 |
# File 'lib/indexer/version/number.rb', line 24 def initialize(*points) @crush = false points.map! do |point| sane_point(point) end @tuple = points.flatten.compact 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"
41 42 43 |
# File 'lib/indexer/version/number.rb', line 41 def self.[](*args) new(*args) end |
.cmp(version1, version2) ⇒ Object
66 67 68 |
# File 'lib/indexer/version/number.rb', line 66 def self.cmp(version1, version2) # TODO: class level compare might be handy end |
Instance Method Details
#<=>(other) ⇒ Object
Compare versions.
251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/indexer/version/number.rb', line 251 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.
269 270 271 272 273 |
# File 'lib/indexer/version/number.rb', line 269 def =~(other) upver = other.bump(:last) #@segments >= other and @segments < upver self >= other and self < upver end |
#[](index) ⇒ Object
Fetch a sepecific segement by index number. In no value is found at that position than zero (0) is returned instead.
v = Version::Number[1,2,0] v[0] #=> 1 v[1] #=> 2 v[3] #=> 0 v[4] #=> 0
Zero is returned instead of +nil+ to make different version numbers easier to compare.
187 188 189 |
# File 'lib/indexer/version/number.rb', line 187 def [](index) @tuple.fetch(index,0) end |
#alpha? ⇒ Boolean
154 155 156 157 |
# File 'lib/indexer/version/number.rb', line 154 def alpha? s = status.dowcase s == 'alpha' or s == 'a' end |
#beta? ⇒ Boolean
160 161 162 163 |
# File 'lib/indexer/version/number.rb', line 160 def beta? s = status.dowcase s == 'beta' or s == 'b' end |
#build ⇒ Object
The build.
86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/indexer/version/number.rb', line 86 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
142 143 144 |
# File 'lib/indexer/version/number.rb', line 142 def build=(point) @tuple = @tuple[0...state_index] + sane_point(point) end |
#build_number ⇒ Object
Return the state revision count. This is the number that occurs after the state.
Version::Number[1,2,0,:rc,4].build_number #=> 4
114 115 116 117 118 119 120 |
# File 'lib/indexer/version/number.rb', line 114 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"
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/indexer/version/number.rb', line 316 def bump(which=:patch) case which.to_sym 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 self.class.new(@tuple.dup.compact) end end |
#bump_build ⇒ Object
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/indexer/version/number.rb', line 370 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
388 389 390 391 392 393 394 395 |
# File 'lib/indexer/version/number.rb', line 388 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
398 399 400 401 |
# File 'lib/indexer/version/number.rb', line 398 def bump_last v = @tuple[0...-1] + [inc(@tuple.last)] self.class.new(v.compact) end |
#bump_major ⇒ Object
338 339 340 |
# File 'lib/indexer/version/number.rb', line 338 def bump_major self.class[inc(major), 0, 0] end |
#bump_minor ⇒ Object
343 344 345 |
# File 'lib/indexer/version/number.rb', line 343 def bump_minor self.class[major, inc(minor), 0] end |
#bump_patch ⇒ Object
348 349 350 |
# File 'lib/indexer/version/number.rb', line 348 def bump_patch self.class[major, minor, inc(patch)] end |
#bump_state ⇒ Object Also known as: bump_status
353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/indexer/version/number.rb', line 353 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?
423 424 425 |
# File 'lib/indexer/version/number.rb', line 423 def crush? @crush end |
#crush_point(string) ⇒ Object (private)
Take a point string rendering of a version and crush it!
465 466 467 |
# File 'lib/indexer/version/number.rb', line 465 def crush_point(string) string.gsub(/(^|\.)(\D+)\.(\d+)(\.|$)/, '\2\3') end |
#each(&block) ⇒ Object
Iterate of each segment of the version. This allows all enumerable methods to be used.
Version::Number[1,2,3].map{|i| i + 1} #=> [2,3,4]
Though keep in mind that the state segment is not a number (and techincally any segment can be a string instead of an integer).
284 285 286 |
# File 'lib/indexer/version/number.rb', line 284 def each(&block) @tuple.each(&block) end |
#inc(val) ⇒ Object (private)
Segement incrementor.
485 486 487 488 489 490 491 |
# File 'lib/indexer/version/number.rb', line 485 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"
225 226 227 |
# File 'lib/indexer/version/number.rb', line 225 def inspect to_s end |
#major ⇒ Object
Major version number
71 72 73 |
# File 'lib/indexer/version/number.rb', line 71 def major (state_index && state_index == 0) ? nil : self[0] end |
#major=(number) ⇒ Object
124 125 126 |
# File 'lib/indexer/version/number.rb', line 124 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. ++
432 433 434 435 436 |
# File 'lib/indexer/version/number.rb', line 432 def match?(*constraints) constraints.all? do |c| Constraint.constraint_lambda(c).call(self) end end |
#minor ⇒ Object
Minor version number
76 77 78 |
# File 'lib/indexer/version/number.rb', line 76 def minor (state_index && state_index <= 1) ? nil : self[1] end |
#minor=(number) ⇒ Object
130 131 132 |
# File 'lib/indexer/version/number.rb', line 130 def minor=(number) @tuple[1] = number.to_i end |
#patch ⇒ Object
Patch version number
81 82 83 |
# File 'lib/indexer/version/number.rb', line 81 def patch (state_index && state_index <= 2) ? nil : self[2] end |
#patch=(number) ⇒ Object
136 137 138 |
# File 'lib/indexer/version/number.rb', line 136 def patch=(number) @tuple[2] = number.to_i end |
#prerelease? ⇒ Boolean
166 167 168 |
# File 'lib/indexer/version/number.rb', line 166 def prerelease? status == 'pre' end |
#release_candidate? ⇒ Boolean
171 172 173 |
# File 'lib/indexer/version/number.rb', line 171 def release_candidate? status == 'rc' end |
#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.
Version::Number[1,2,3].restate(:pre,2).to_s #=> "1.2.3.pre.2"
Version::Number[1,2,3,:pre,2].restate(:rc,4).to_s #=> "1.2.3.rc.4"
412 413 414 415 416 417 418 419 |
# File 'lib/indexer/version/number.rb', line 412 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.
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/indexer/version/number.rb', line 446 def sane_point(point) point = point.to_s if Symbol === point case point when Integer point 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
Return the number of version segements.
Version::Number[1,2,3].size #=> 3
293 294 295 |
# File 'lib/indexer/version/number.rb', line 293 def size @tuple.size end |
#stable? ⇒ Boolean Also known as: stable_release?
147 148 149 |
# File 'lib/indexer/version/number.rb', line 147 def stable? build.nil? end |
#state ⇒ Object Also known as: status
101 102 103 |
# File 'lib/indexer/version/number.rb', line 101 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.
480 481 482 |
# File 'lib/indexer/version/number.rb', line 480 def state_index @tuple.index{ |s| String === s } end |
#to_a ⇒ Object
Returns a duplicate of the underlying version tuple.
193 194 195 |
# File 'lib/indexer/version/number.rb', line 193 def to_a @tuple.dup end |
#to_s ⇒ Object
Converts version to a dot-separated string.
Version::Number[1,2,0].to_s #=> "1.2.0"
TODO: crush
203 204 205 206 207 |
# File 'lib/indexer/version/number.rb', line 203 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"
215 216 217 |
# File 'lib/indexer/version/number.rb', line 215 def to_str to_s end |
#to_yaml(opts = {}) ⇒ String
Converts the version to YAML.
-- TODO: Should this be here? ++
241 242 243 |
# File 'lib/indexer/version/number.rb', line 241 def to_yaml(opts={}) to_s.to_yaml(opts) end |