versus 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.index +45 -0
- data/.yardopts +7 -0
- data/HISTORY.md +11 -0
- data/Index.yml +37 -0
- data/LICENSE.txt +23 -0
- data/README.md +46 -0
- data/demo/applique/ae.rb +5 -0
- data/demo/applique/main.rb +1 -0
- data/demo/constraint/02_initialize.md +44 -0
- data/demo/constraint/04_to_proc.md +11 -0
- data/demo/constraint/09_to_gem_version.md +10 -0
- data/demo/number/02_initialize.md +14 -0
- data/demo/number/03_parse.md +23 -0
- data/demo/number/04_crush.md +17 -0
- data/demo/number/05_build.md +23 -0
- data/demo/number/06_cmp.md +100 -0
- data/demo/number/07_segments.md +51 -0
- data/demo/number/08_bump.md +46 -0
- data/demo/number/09_stable_release.md +23 -0
- data/demo/number/10_prerelease.md +19 -0
- data/demo/number/11_release_candidate.md +15 -0
- data/demo/number/19_match.md +10 -0
- data/demo/number/20_to_str.md +13 -0
- data/demo/resolver/01_initialize.md +23 -0
- data/demo/resolver/02_add.md +11 -0
- data/demo/resolver/03_libraries.md +24 -0
- data/demo/resolver/04_requirements.md +13 -0
- data/demo/resolver/05_possibilities.md +13 -0
- data/demo/resolver/06_resolve.md +42 -0
- data/lib/versus.rb +5 -0
- data/lib/versus/constraint.rb +130 -0
- data/lib/versus/core_ext.rb +4 -0
- data/lib/versus/core_ext/array.rb +11 -0
- data/lib/versus/core_ext/kernel.rb +19 -0
- data/lib/versus/core_ext/string.rb +10 -0
- data/lib/versus/exceptions.rb +8 -0
- data/lib/versus/file.rb +157 -0
- data/lib/versus/file/jeweler_format.rb +49 -0
- data/lib/versus/file/plain_format.rb +39 -0
- data/lib/versus/number.rb +516 -0
- data/lib/versus/resolver.rb +303 -0
- metadata +124 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
## Version::Number#bump
|
2
|
+
|
3
|
+
A version number can be *bumped*, which means various segments
|
4
|
+
can be incremented. Bumping is handled by the #bump method which
|
5
|
+
is passed a symbol describing the type of bump to effect.
|
6
|
+
|
7
|
+
### Bump major number
|
8
|
+
|
9
|
+
v = Version::Number[1,0,0]
|
10
|
+
v.bump(:major).to_s == '2.0.0'
|
11
|
+
|
12
|
+
### Bump minor number
|
13
|
+
|
14
|
+
v = Version::Number[1,0,0]
|
15
|
+
v.bump(:minor).to_s == '1.1.0'
|
16
|
+
|
17
|
+
### Bump patch number
|
18
|
+
|
19
|
+
v = Version::Number[1,0,0]
|
20
|
+
v.bump(:patch).to_s == '1.0.1'
|
21
|
+
|
22
|
+
### Bump build number
|
23
|
+
|
24
|
+
v = Version::Number[1,0,0,0]
|
25
|
+
v.bump(:build).to_s == '1.0.0.1'
|
26
|
+
|
27
|
+
### Bump build number with state
|
28
|
+
|
29
|
+
v = Version::Number[1,0,0,'pre',1]
|
30
|
+
v.bump(:build).to_s == '1.0.0.pre.2'
|
31
|
+
|
32
|
+
### Bump state segment
|
33
|
+
|
34
|
+
v = Version::Number[1,0,0,'pre',2]
|
35
|
+
v.bump(:state).to_s == '1.0.0.rc.1'
|
36
|
+
|
37
|
+
### Bump last segment
|
38
|
+
|
39
|
+
v = Version::Number[1,0,0,'pre',3]
|
40
|
+
v.bump(:last).to_s == '1.0.0.pre.4'
|
41
|
+
|
42
|
+
### Reset State
|
43
|
+
|
44
|
+
v = Version::Number[1,0,0,'pre',2]
|
45
|
+
v.restate(:beta).to_s == '1.0.0.beta.1'
|
46
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
## Version::Number#stable?
|
2
|
+
|
3
|
+
The `stable?` method returns `true` if the build is `nil`,
|
4
|
+
otherwise `false`.
|
5
|
+
|
6
|
+
v = Version::Number[1,2,3]
|
7
|
+
|
8
|
+
v.assert.stable?
|
9
|
+
|
10
|
+
v = Version::Number[1,2,3,'pre',4]
|
11
|
+
|
12
|
+
v.refute.stable?
|
13
|
+
|
14
|
+
|
15
|
+
## Version::Number#stable_release?
|
16
|
+
|
17
|
+
v = Version::Number[1,2,3]
|
18
|
+
|
19
|
+
v.assert.stable_release?
|
20
|
+
|
21
|
+
v = Version::Number[1,2,3,'pre',4]
|
22
|
+
|
23
|
+
v.refute.stable_release?
|
@@ -0,0 +1,19 @@
|
|
1
|
+
## Version::Number#prerelease?
|
2
|
+
|
3
|
+
The `prerelease?` method returns `true` if the build is `pre`,
|
4
|
+
otherwise `false`.
|
5
|
+
|
6
|
+
v = Version::Number[1,2,3,'pre',4]
|
7
|
+
|
8
|
+
v.assert.prerelease?
|
9
|
+
|
10
|
+
|
11
|
+
v = Version::Number[1,2,3]
|
12
|
+
|
13
|
+
v.refute.prerelease?
|
14
|
+
|
15
|
+
|
16
|
+
v = Version::Number[1,2,3,'alpha']
|
17
|
+
|
18
|
+
v.refute.prerelease?
|
19
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
## Version::Number#release_candidate?
|
2
|
+
|
3
|
+
The `release_candidate?` method returns `true` if the build
|
4
|
+
is `rc`, otherwise `false`.
|
5
|
+
|
6
|
+
check do |v|
|
7
|
+
v = Version::Number.parse(v)
|
8
|
+
v.release_candidate?
|
9
|
+
end
|
10
|
+
|
11
|
+
ok [1,2,3,'rc',1]
|
12
|
+
no [1,2,3]
|
13
|
+
no [1,2,3,'alpha']
|
14
|
+
|
15
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
## Version::Number#to_str
|
2
|
+
|
3
|
+
The Version::Number class can be thought of as a String.
|
4
|
+
|
5
|
+
check do |v, s|
|
6
|
+
v = Version::Number.parse(v)
|
7
|
+
v.to_str.assert == s
|
8
|
+
end
|
9
|
+
|
10
|
+
ok [1,2,3], '1.2.3'
|
11
|
+
ok [1,2,3,'rc',1], '1.2.3.rc.1'
|
12
|
+
ok [1,2,3,'alpha'], '1.2.3.alpha'
|
13
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Version::Resolver#initialize
|
2
|
+
|
3
|
+
The Resolver class provides a means for resolving versioned
|
4
|
+
|
5
|
+
resolver = Version::Resolver.new
|
6
|
+
|
7
|
+
A new Resolver can take a list of dependent entries. These are supplied as
|
8
|
+
a list of three-element arrays containing name, version number and requiremnets.
|
9
|
+
Where requirements are themselves a list of names and version constraints.
|
10
|
+
|
11
|
+
resolver = Version::Resolver.new(
|
12
|
+
['foo', '1.0.0', {'bar' => '> 1.0'}],
|
13
|
+
['bar', '2.0.0', {}]
|
14
|
+
)
|
15
|
+
|
16
|
+
If the requirements list is left out of an entry, it should still initialize
|
17
|
+
without issue.
|
18
|
+
|
19
|
+
resolver = Version::Resolver.new(
|
20
|
+
['foo', '1.0.0', {'bar' => '> 1.0'}],
|
21
|
+
['bar', '2.0.0']
|
22
|
+
)
|
23
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Version::Resolver.add
|
2
|
+
|
3
|
+
Rather then passing dependencies to the constructor, a Resolver can be
|
4
|
+
initialized without arguments and then passed dependencies one at a time
|
5
|
+
using the `#add` method.
|
6
|
+
|
7
|
+
resolver = Version::Resolver.new
|
8
|
+
|
9
|
+
resolver.add('foo', '1.0.0', 'bar'=>'> 1.0')
|
10
|
+
resolver.add('bar', '2.0.0')
|
11
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Version::Resolver#libraries
|
2
|
+
|
3
|
+
Adding entries to the Resolver build up a map of "libraries".
|
4
|
+
|
5
|
+
resolver = Version::Resolver.new
|
6
|
+
|
7
|
+
resolver.add('foo', '1.0.0', 'bar'=>'> 1.0')
|
8
|
+
resolver.add('bar', '2.0.0')
|
9
|
+
|
10
|
+
resolver.libraries.assert.is_a?(Hash)
|
11
|
+
|
12
|
+
The hash is made up of the libraries added to the reolver, just organized
|
13
|
+
into two-tier hash of `name => version-number => requirements`.
|
14
|
+
|
15
|
+
resolver.libraries['foo'].assert.is_a?(Hash)
|
16
|
+
|
17
|
+
But the version has version-number is converted into a Version::Number
|
18
|
+
instance, and the requirement's version constraint is converted into
|
19
|
+
a Version::Constraint instance.
|
20
|
+
|
21
|
+
version = Version::Number.parse('1.0.0')
|
22
|
+
|
23
|
+
resolver.libraries['foo'][version].assert.is_a?(Hash)
|
24
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Version::Resolver#requirements
|
2
|
+
|
3
|
+
Requiremnets can be looked-up using the `#requirements` method.
|
4
|
+
|
5
|
+
resolver = Version::Resolver.new
|
6
|
+
|
7
|
+
resolver.add('foo', '1.0.0', 'bar'=>'> 1.0')
|
8
|
+
resolver.add('bar', '2.0.0')
|
9
|
+
|
10
|
+
requires = resolver.requirements('foo', '1.0.0')
|
11
|
+
|
12
|
+
requires.keys.assert == ['bar']
|
13
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Version::Resolver#possibilities
|
2
|
+
|
3
|
+
Requiremnets can be looked-up using the `#requirements` method.
|
4
|
+
|
5
|
+
resolver = Version::Resolver.new
|
6
|
+
|
7
|
+
resolver.add('foo', '1.0.0', 'bar'=>'> 1.0')
|
8
|
+
resolver.add('bar', '2.0.0')
|
9
|
+
|
10
|
+
potents = resolver.possibilities('foo', '= 1.0.0')
|
11
|
+
|
12
|
+
potents.first.first.assert == 'foo'
|
13
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Version::Resolver#resolve
|
2
|
+
|
3
|
+
Given a Resolver and a set of entries,
|
4
|
+
|
5
|
+
resolver = Version::Resolver.new
|
6
|
+
|
7
|
+
resolver.add('foo', '1.0.0', 'bar'=>'> 1.0')
|
8
|
+
resolver.add('bar', '1.0.0')
|
9
|
+
resolver.add('bar', '2.0.0')
|
10
|
+
|
11
|
+
We can resolve the requirements
|
12
|
+
|
13
|
+
result = resolver.resolve('foo', '1.0.0')
|
14
|
+
|
15
|
+
result.assert == {'foo'=>Version['1.0.0'], 'bar'=>Version['2.0.0']}
|
16
|
+
|
17
|
+
If there are not sufficient requirements then no resolution will be returned.
|
18
|
+
|
19
|
+
resolver = Version::Resolver.new
|
20
|
+
|
21
|
+
resolver.add('foo', '1.0.0', 'bar'=>'> 1.0')
|
22
|
+
resolver.add('bar', '1.0.0')
|
23
|
+
|
24
|
+
result = resolver.resolve('foo', '1.0.0')
|
25
|
+
|
26
|
+
result.assert == nil
|
27
|
+
|
28
|
+
Let try a more complex example to be sure of our algorithm.
|
29
|
+
|
30
|
+
resolver.add('foo', '1.0.0', 'bar'=>'> 1.0', 'baz'=>'> 2.0')
|
31
|
+
resolver.add('bar', '1.0.0', 'baz'=>'= 3.1')
|
32
|
+
resolver.add('bar', '2.0.0', 'baz'=>'= 3.1')
|
33
|
+
resolver.add('baz', '2.9.0')
|
34
|
+
resolver.add('baz', '3.1.0')
|
35
|
+
resolver.add('baz', '3.2.0')
|
36
|
+
|
37
|
+
result = resolver.resolve('foo', '1.0.0')
|
38
|
+
|
39
|
+
result.assert == { 'foo'=>Version['1.0.0'],
|
40
|
+
'bar'=>Version['2.0.0'],
|
41
|
+
'baz'=>Version['3.1.0'] }
|
42
|
+
|
data/lib/versus.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
module Version
|
2
|
+
|
3
|
+
# The Constraint class models a single version equality or inequality.
|
4
|
+
# It consists of the operator and the version number.
|
5
|
+
#--
|
6
|
+
# TODO: Please improve me!
|
7
|
+
#
|
8
|
+
# TODO: This should ultimately replace the class methods of Version::Number.
|
9
|
+
#
|
10
|
+
# TODO: Do we need to support version "from-to" spans ?
|
11
|
+
#++
|
12
|
+
class Constraint
|
13
|
+
|
14
|
+
#
|
15
|
+
def self.parse(constraint)
|
16
|
+
new(constraint)
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
def self.[](operator, number)
|
21
|
+
new([operator, number])
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
def initialize(constraint)
|
26
|
+
@operator, @number = parse(constraint || '0+')
|
27
|
+
|
28
|
+
case constraint
|
29
|
+
when Array
|
30
|
+
@stamp = "%s %s" % [@operator, @number]
|
31
|
+
when String
|
32
|
+
@stamp = constraint || '0+'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Constraint operator.
|
37
|
+
attr :operator
|
38
|
+
|
39
|
+
# Verison number.
|
40
|
+
attr :number
|
41
|
+
|
42
|
+
#
|
43
|
+
def to_s
|
44
|
+
@stamp
|
45
|
+
end
|
46
|
+
|
47
|
+
# Converts the version into a constraint string recognizable
|
48
|
+
# by RubyGems.
|
49
|
+
#--
|
50
|
+
# TODO: Better name Constraint#to_s2.
|
51
|
+
#++
|
52
|
+
def to_gem_version
|
53
|
+
op = (operator == '=~' ? '~>' : operator)
|
54
|
+
"%s %s" % [op, number]
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Convert constraint to Proc object which can be
|
59
|
+
# used to test a version number.
|
60
|
+
#
|
61
|
+
def to_proc
|
62
|
+
lambda do |v|
|
63
|
+
n = Version::Number.parse(v)
|
64
|
+
n.send(operator, number)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
def call(v)
|
70
|
+
n = Version::Number.parse(v)
|
71
|
+
n.send(operator, number)
|
72
|
+
end
|
73
|
+
|
74
|
+
# better name?
|
75
|
+
alias :match? :call
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
#
|
80
|
+
def parse(constraint)
|
81
|
+
case constraint
|
82
|
+
when Constraint
|
83
|
+
op, val = constraint.operator, constraint.number
|
84
|
+
when Array
|
85
|
+
op, num = constraint
|
86
|
+
when /^(.*?)\~$/
|
87
|
+
op, val = "=~", $1.strip
|
88
|
+
when /^(.*?)\+$/
|
89
|
+
op, val = ">=", $1.strip
|
90
|
+
when /^(.*?)\-$/
|
91
|
+
op, val = "<", $1
|
92
|
+
when /^(=~|~>|<=|>=|==|=|<|>)?\s*(\d+(:?[-.]\w+)*)$/
|
93
|
+
if op = $1
|
94
|
+
op = '=~' if op == '~>'
|
95
|
+
op = '==' if op == '='
|
96
|
+
val = $2.split(/\W+/)
|
97
|
+
else
|
98
|
+
op = '=='
|
99
|
+
val = constraint.split(/\W+/)
|
100
|
+
end
|
101
|
+
else
|
102
|
+
raise ArgumentError #constraint.split(/\s+/)
|
103
|
+
end
|
104
|
+
return op, Version::Number.new(*val)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Parse package entry into name and version constraint.
|
108
|
+
#def parse(package)
|
109
|
+
# parts = package.strip.split(/\s+/)
|
110
|
+
# name = parts.shift
|
111
|
+
# vers = parts.empty? ? nil : parts.join(' ')
|
112
|
+
# [name, vers]
|
113
|
+
#end
|
114
|
+
|
115
|
+
public
|
116
|
+
|
117
|
+
# Parses a string constraint returning the operation as a lambda.
|
118
|
+
def self.constraint_lambda(constraint)
|
119
|
+
new(constraint).to_proc
|
120
|
+
end
|
121
|
+
|
122
|
+
# Parses a string constraint returning the operator and value.
|
123
|
+
def self.parse_constraint(constraint)
|
124
|
+
c = new(constraint)
|
125
|
+
return c.operator, c.number
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'versus'
|
2
|
+
|
3
|
+
module Kernel
|
4
|
+
private
|
5
|
+
|
6
|
+
#
|
7
|
+
# If an arbitrary object need to be converted to a `Version::Number`, this is
|
8
|
+
# a good way to do it.
|
9
|
+
#
|
10
|
+
# The capitalize method follows the Ruby conventions of `Array()` and `String()`,
|
11
|
+
# etc. Though in this case `Version()` actually creates a `Version::Number` object,
|
12
|
+
# that is far an away the typical use case for the Version module.
|
13
|
+
#
|
14
|
+
def Version(version)
|
15
|
+
Version::Number.parse(version)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|