Module: Tap::Root::Versions

Included in:
Utils
Defined in:
lib/tap/root/versions.rb

Overview

Version provides methods for adding, removing, and incrementing versions at the end of paths. Versions are all formatted like: ‘path-version.extension’.

Instance Method Summary collapse

Instance Method Details

#compare_versions(a, b) ⇒ Object

A <=> comparison for versions. compare_versions can take strings, integers, or even arrays representing the parts of a version.

compare_versions("1.0.0", "0.9.9")          # => 1
compare_versions(1.1, 1.1)                  # => 0
compare_versions([0,9], [0,9,1])            # => -1


73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/tap/root/versions.rb', line 73

def compare_versions(a,b)
  a, b = [a,b].collect {|item| to_integer_array(item) }

  # equalize the lengths of the integer arrays
  d = b.length - a.length
  case 
  when d < 0 then b.concat Array.new(-d, 0)
  when d > 0 then a.concat Array.new(d, 0)
  end 
    
  a <=> b
end

#deversion(path) ⇒ Object

Splits the version from the input path, then returns the path and version. If no version is specified, then the returned version will be nil.

deversion("path/to/file-1.0.txt")           # => ["path/to/file.txt", "1.0"]
deversion("path/to/file.txt")               # => ["path/to/file.txt", nil]


61
62
63
64
65
# File 'lib/tap/root/versions.rb', line 61

def deversion(path)
  extname = File.extname(path)
  extname = '' if extname =~ /^\.\d+$/
  path =~ /^(.*)-(\d(\.?\d)*)#{extname}$/ ? [$1 + extname, $2] : [path, nil]
end

#increment(path, increment) ⇒ Object

Increments the version of the path by the specified increment.

increment("path/to/file-1.0.txt", "0.0.1")  # => "path/to/file-1.0.1.txt"
increment("path/to/file.txt", 1.0)          # => "path/to/file-1.0.txt"


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/tap/root/versions.rb', line 30

def increment(path, increment)
  path, version = deversion(path)

  # split the version and increment into integer arrays of equal length
  increment, version = [increment, version].collect do |vstr| 
    begin
      vstr.to_s.split(/\./).collect {|v| v.to_i}
    rescue
      raise "Bad version or increment: #{vstr}"
    end
  end

  if increment.length > version.length
    version.concat Array.new(increment.length - version.length, 0)
  end

  # add the increment to version
  0.upto(version.length-1) do |i|
    version[i] += (increment[i] || 0)
  end

  self.version(path, version.join("."))
end

#version(path, version) ⇒ Object

Adds a version to the path. Versioned paths follow the format: ‘path-version.extension’. If no version is specified, then the path is returned.

version("path/to/file.txt", 1.0)            # => "path/to/file-1.0.txt"


15
16
17
18
19
20
21
22
23
# File 'lib/tap/root/versions.rb', line 15

def version(path, version)
  version = version.to_s.strip
  if version.empty? 
    path
  else
    extname = File.extname(path)
    path.chomp(extname) + '-' + version + extname
  end
end

#vniq(array, earliest = false, preserve_order = true) ⇒ Object

Version unique. Select the latest or earliest versions of each file in the array. For paths that have no version, vniq considers any version to beat no version. The order of paths is preserved by default, but the extra sort doing so may be turned off.

paths = [
 "/path/to/two-0.0.1.txt",
 "/path/to/one-0.0.1.txt",
 "/path/to/one.txt",
 "/path/to/two-1.0.1.txt",
 "/path/to/three.txt"]

vniq(paths)
# => [
# "/path/to/one-0.0.1.txt",
# "/path/to/two-1.0.1.txt",
# "/path/to/three.txt"]


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/tap/root/versions.rb', line 104

def vniq(array, earliest=false, preserve_order=true)
  unique = {}
  array.sort.each do |path|
    base, version = deversion(path)
    (unique[base] ||= []) << version
  end

  results = []
  unique.each_pair do |base, versions|
    versions = versions.sort {|a, b| compare_versions(a,b) }
    winner = earliest ? versions.shift : versions.pop
    results << version(base, winner)
  end

  results = results.sort_by do |path|
    array.index(path)
  end if preserve_order

  results
end