versus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.index +45 -0
  2. data/.yardopts +7 -0
  3. data/HISTORY.md +11 -0
  4. data/Index.yml +37 -0
  5. data/LICENSE.txt +23 -0
  6. data/README.md +46 -0
  7. data/demo/applique/ae.rb +5 -0
  8. data/demo/applique/main.rb +1 -0
  9. data/demo/constraint/02_initialize.md +44 -0
  10. data/demo/constraint/04_to_proc.md +11 -0
  11. data/demo/constraint/09_to_gem_version.md +10 -0
  12. data/demo/number/02_initialize.md +14 -0
  13. data/demo/number/03_parse.md +23 -0
  14. data/demo/number/04_crush.md +17 -0
  15. data/demo/number/05_build.md +23 -0
  16. data/demo/number/06_cmp.md +100 -0
  17. data/demo/number/07_segments.md +51 -0
  18. data/demo/number/08_bump.md +46 -0
  19. data/demo/number/09_stable_release.md +23 -0
  20. data/demo/number/10_prerelease.md +19 -0
  21. data/demo/number/11_release_candidate.md +15 -0
  22. data/demo/number/19_match.md +10 -0
  23. data/demo/number/20_to_str.md +13 -0
  24. data/demo/resolver/01_initialize.md +23 -0
  25. data/demo/resolver/02_add.md +11 -0
  26. data/demo/resolver/03_libraries.md +24 -0
  27. data/demo/resolver/04_requirements.md +13 -0
  28. data/demo/resolver/05_possibilities.md +13 -0
  29. data/demo/resolver/06_resolve.md +42 -0
  30. data/lib/versus.rb +5 -0
  31. data/lib/versus/constraint.rb +130 -0
  32. data/lib/versus/core_ext.rb +4 -0
  33. data/lib/versus/core_ext/array.rb +11 -0
  34. data/lib/versus/core_ext/kernel.rb +19 -0
  35. data/lib/versus/core_ext/string.rb +10 -0
  36. data/lib/versus/exceptions.rb +8 -0
  37. data/lib/versus/file.rb +157 -0
  38. data/lib/versus/file/jeweler_format.rb +49 -0
  39. data/lib/versus/file/plain_format.rb +39 -0
  40. data/lib/versus/number.rb +516 -0
  41. data/lib/versus/resolver.rb +303 -0
  42. 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,10 @@
1
+ ## Version::Number#match?
2
+
3
+ The `match?` method
4
+
5
+ v = Version::Number[1,2,3]
6
+
7
+ v.assert.match?('> 1.2')
8
+ v.assert.match?('< 2.0')
9
+ v.assert.match?('> 1.2', '< 2.0')
10
+
@@ -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
+
@@ -0,0 +1,5 @@
1
+ require 'versus/exceptions'
2
+ require 'versus/number'
3
+ require 'versus/constraint'
4
+ require 'versus/resolver'
5
+ require 'versus/file'
@@ -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,4 @@
1
+ require 'versus/core_ext/array'
2
+ require 'versus/core_ext/kernel'
3
+ require 'versus/core_ext/string'
4
+
@@ -0,0 +1,11 @@
1
+ require 'versus'
2
+
3
+ class Array
4
+ #
5
+ # Converts the Array into a version number.
6
+ #
7
+ def to_version
8
+ Version::Number.new(*self)
9
+ end
10
+ end
11
+
@@ -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
+