versus 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|