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.
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
+