semantic 1.0.0 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 49f4f8185e5b08f5e55c52e84b9e97514734e773
4
+ data.tar.gz: d0348d4f5c518868f35a68fc17730e65b6b19a41
5
+ SHA512:
6
+ metadata.gz: e8b5397c167716fec08c08c156cd83adc8feaf97865311cd761bc344dfbeac4dc88aad60c2b4b771e4e69ffae217bdefd875715d05222ea6a486f01fb516419e
7
+ data.tar.gz: 4ac7c975674f02f07cbffbd5829532305f998ce74922866a413d6182041cf2cad3e0b8272d3546cab7793752657b1a60d026db175408f69a91411e70a290c7e3
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  Semantic
2
2
  ========
3
+ [![BuildStatus](https://travis-ci.org/jlindsey/semantic.svg?branch=master)](https://travis-ci.org/jlindsey/semantic)
3
4
 
4
5
  A small Ruby utility class to aid in the storage, parsing, and comparison of SemVer-style Version strings.
5
6
 
@@ -26,6 +27,21 @@ newer_version <=> version # => 1
26
27
  complex_version = Semantic::Version.new '3.7.9-pre.1+revision.15723'
27
28
  complex_version.pre # => "pre.1"
28
29
  complex_version.build # => "revision.15623"
30
+
31
+ # semantic supports Pessimistic Operator
32
+ version.satisfies? '~> 1.5' # => true
33
+ version.satisfies? '~> 1.6.0' # => true
34
+
35
+ # incrementing version numbers
36
+ version = Semantic::Version.new('0.1.0')
37
+ new_version = version.increment!(:major) # 1.1.0
38
+ new_version = version.increment!(:minor) # 0.2.0
39
+ new_version = version.increment!(:patch) # 0.1.1
40
+
41
+ new_version = verstion.major! # 1.1.0
42
+ new_version = verstion.minor! # 0.2.0
43
+ new_version = verstion.patch! # 0.1.1
44
+ # (note: increment! & friends return a copy and leave the original unchanged)
29
45
  ```
30
46
 
31
47
  There is also a set of core extensions as an optional require:
@@ -39,5 +55,5 @@ require 'semantic/core_ext'
39
55
 
40
56
  License
41
57
  -------
42
- Copyright (c) 2012 Josh Lindsey. See LICENSE for details.
58
+ Copyright (c) 2012 Josh Lindsey. See [LICENSE](LICENSE) for details.
43
59
 
@@ -2,4 +2,8 @@ class String
2
2
  def to_version
3
3
  Semantic::Version.new self
4
4
  end
5
+
6
+ def is_version?
7
+ (match Semantic::Version::SemVerRegexp) ? true : false
8
+ end
5
9
  end
@@ -1,85 +1,180 @@
1
1
  # See: http://semver.org
2
- class Semantic::Version
3
- SemVerRegexp = /^(\d+\.\d+\.\d+)(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?(\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$/
4
- attr_accessor :major, :minor, :patch, :pre, :build
2
+ module Semantic
3
+ class Version
4
+ include Comparable
5
5
 
6
- def initialize version_str
7
- raise ArgumentError.new("Not a valid SemVer Version (http://semver.org)") unless version_str =~ SemVerRegexp
6
+ SemVerRegexp = /\A(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][a-zA-Z0-9-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][a-zA-Z0-9-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?\Z/
8
7
 
9
- version, parts = version_str.split '-'
10
- if not parts.nil? and parts.include? '+'
11
- @pre, @build = parts.split '+'
12
- elsif version.include? '+'
13
- version, @build = version.split '+'
14
- else
15
- @pre = parts
8
+
9
+ attr_accessor :major, :minor, :patch, :pre
10
+ attr_reader :build
11
+
12
+ def initialize version_str
13
+ v = version_str.match(SemVerRegexp)
14
+
15
+ raise ArgumentError.new("#{version_str} is not a valid SemVer Version (http://semver.org)") if v.nil?
16
+ @major = v[1].to_i
17
+ @minor = v[2].to_i
18
+ @patch = v[3].to_i
19
+ @pre = v[4]
20
+ @build = v[5]
21
+ @version = version_str
16
22
  end
17
23
 
18
24
 
19
- @major, @minor, @patch = version.split('.').map &:to_i
20
- end
25
+ def build=(b)
26
+ @build = (!b.nil? && b.empty?) ? nil : b
27
+ end
21
28
 
22
- def to_a
23
- [@major, @minor, @patch, @pre, @build]
24
- end
29
+ def identifiers(pre)
30
+ array = pre.split(/[\.\-]/)
31
+ array.each_with_index {|e,i| array[i] = Integer(e) if /\A\d+\z/.match(e)}
32
+ return array
33
+ end
25
34
 
26
- def to_s
27
- str = [@major, @minor, @patch].join '.'
28
- str << '-' << @pre unless @pre.nil?
29
- str << '+' << @build unless @build.nil?
35
+ def compare_pre(prea, preb)
36
+ if prea.nil? || preb.nil?
37
+ return 0 if prea.nil? && preb.nil?
38
+ return 1 if prea.nil?
39
+ return -1 if preb.nil?
40
+ end
41
+ a = identifiers(prea)
42
+ b = identifiers(preb)
43
+ smallest = a.size < b.size ? a : b
44
+ smallest.each_with_index do |e, i|
45
+ c = a[i] <=> b[i]
46
+ if c.nil?
47
+ return a[i].is_a?(Integer) ? -1 : 1
48
+ elsif c != 0
49
+ return c
50
+ end
51
+ end
52
+ return a.size <=> b.size
53
+ end
30
54
 
31
- str
32
- end
55
+ def to_a
56
+ [@major, @minor, @patch, @pre, @build]
57
+ end
33
58
 
34
- def to_h
35
- keys = [:major, :minor, :patch, :pre, :build]
36
- Hash[keys.zip(self.to_a)]
37
- end
59
+ def to_s
60
+ str = [@major, @minor, @patch].join '.'
61
+ str << '-' << @pre unless @pre.nil?
62
+ str << '+' << @build unless @build.nil?
63
+ str
64
+ end
38
65
 
39
- alias to_hash to_h
40
- alias to_array to_a
41
- alias to_string to_s
66
+ def to_h
67
+ keys = [:major, :minor, :patch, :pre, :build]
68
+ Hash[keys.zip(self.to_a)]
69
+ end
42
70
 
43
- def <=> other_version
44
- other_version = Version.new(other_version) if other_version.is_a? String
45
- compare_recursively self.to_a.dup, other_version.to_a.dup
46
- end
71
+ alias to_hash to_h
72
+ alias to_array to_a
73
+ alias to_string to_s
47
74
 
48
- def > other_version
49
- if (self <=> other_version) == 1 then true else false end
50
- end
75
+ def hash
76
+ to_a.hash
77
+ end
51
78
 
52
- def < other_version
53
- if (self <=> other_version) == -1 then true else false end
54
- end
79
+ def eql? other_version
80
+ self.hash == other_version.hash
81
+ end
55
82
 
56
- private
83
+ def <=> other_version
84
+ other_version = Version.new(other_version) if other_version.is_a? String
85
+ [:major, :minor, :patch].each do |part|
86
+ c = (self.send(part) <=> other_version.send(part))
87
+ if c != 0
88
+ return c
89
+ end
90
+ end
91
+ return compare_pre(self.pre, other_version.pre)
92
+ end
57
93
 
58
- def compare_recursively ary1, ary2
59
- # Short-circuit the recursion entirely if they're just equal
60
- return 0 if ary1 == ary2
94
+ def satisfies? other_version
95
+ return true if other_version.strip == '*'
96
+ parts = other_version.split(/(\d(.+)?)/, 2)
97
+ comparator, other_version_string = parts[0].strip, parts[1].strip
98
+
99
+ begin
100
+ Version.new other_version_string
101
+ comparator.empty? && comparator = '=='
102
+ satisfies_comparator? comparator, other_version_string
103
+ rescue ArgumentError
104
+ if ['<', '>', '<=', '>='].include?(comparator)
105
+ satisfies_comparator? comparator, pad_version_string(other_version_string)
106
+ elsif comparator == '~>'
107
+ pessimistic_match? other_version_string
108
+ else
109
+ tilde_matches? other_version_string
110
+ end
111
+ end
112
+ end
61
113
 
62
- a = ary1.shift; b = ary2.shift
114
+ def satisfied_by? versions
115
+ raise ArgumentError.new("Versions #{versions} should be an array of versions") unless versions.is_a? Array
116
+ versions.all? { |version| satisfies?(version) }
117
+ end
63
118
 
64
- # Reached the end of the arrays, equal all the way down
65
- return 0 if a.nil? and b.nil?
119
+ [:major, :minor, :patch].each do |term|
120
+ define_method("#{term}!") { increment!(term) }
121
+ end
66
122
 
67
- # Mismatched types (ie. one has a build and the other doesn't)
68
- if a.nil? and not b.nil?
69
- return -1
70
- elsif not a.nil? and b.nil?
71
- return 1
123
+ def increment!(term)
124
+ term = term.to_sym
125
+ new_version = clone
126
+ new_value = send(term) + 1
127
+
128
+ new_version.send("#{term}=", new_value)
129
+ new_version.minor = 0 if term == :major
130
+ new_version.patch = 0 if term == :major || term == :minor
131
+ new_version.build = new_version.pre = nil
132
+
133
+ new_version
72
134
  end
73
135
 
74
- # Less or greater than
75
- if a > b
76
- return 1
77
- elsif a < b
78
- return -1
136
+ private
137
+
138
+ def pad_version_string version_string
139
+ parts = version_string.split('.').reject {|x| x == '*'}
140
+ while parts.length < 3
141
+ parts << '0'
142
+ end
143
+ parts.join '.'
144
+ end
145
+
146
+ def tilde_matches? other_version_string
147
+ this_parts = to_a.collect(&:to_s)
148
+ other_parts = other_version_string.split('.').reject {|x| x == '*'}
149
+ other_parts == this_parts[0..other_parts.length-1]
150
+ end
151
+
152
+ def pessimistic_match? other_version_string
153
+ other_parts = other_version_string.split('.')
154
+ unless other_parts.size == 2 || other_parts.size == 3
155
+ raise ArgumentError.new("Version #{other_version_string} should not be applied with a pessimistic operator")
156
+ end
157
+ other_parts.pop
158
+ other_parts << (other_parts.pop.to_i + 1).to_s
159
+ satisfies_comparator?('>=', semverified(other_version_string)) && satisfies_comparator?('<', semverified(other_parts.join('.')))
160
+ end
161
+
162
+ def satisfies_comparator? comparator, other_version_string
163
+ if comparator == '~'
164
+ tilde_matches? other_version_string
165
+ elsif comparator == '~>'
166
+ pessimistic_match? other_version_string
167
+ else
168
+ self.send comparator, other_version_string
169
+ end
170
+ end
171
+
172
+ def semverified version_string
173
+ parts = version_string.split('.')
174
+ raise ArgumentError.new("Version #{version_string} not supported by semverified") if parts.size > 3
175
+ (3 - parts.size).times { parts << '0' }
176
+ parts.join('.')
79
177
  end
80
178
 
81
- # Recurse down to the next part if equal
82
- compare_recursively ary1, ary2
83
179
  end
84
180
  end
85
-
data/lib/semantic.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  module Semantic
2
- GEM_VERSION = '1.0.0'
2
+ GEM_VERSION = '1.6.1'
3
3
  autoload :Version, 'semantic/version'
4
4
  end
5
-
@@ -1,8 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'semantic/core_ext'
3
3
 
4
+ # rubocop:disable Metrics/BlockLength
4
5
  describe 'Core Extensions' do
5
- context "String#to_version" do
6
+ context 'String#to_version' do
6
7
  before(:each) do
7
8
  @test_versions = [
8
9
  '1.0.0',
@@ -23,20 +24,39 @@ describe 'Core Extensions' do
23
24
  ]
24
25
  end
25
26
 
26
- it "extends String with a #to_version method" do
27
- String.new.should respond_to(:to_version)
27
+ it 'extends String with a #to_version method' do
28
+ expect('').to respond_to(:to_version)
28
29
  end
29
30
 
30
- it "converts the String into a Version object" do
31
+ it 'converts the String into a Version object' do
31
32
  @test_versions.each do |v|
32
- expect { v.to_version }.to_not raise_error(ArgumentError)
33
- v.to_version.should be_a(Semantic::Version)
33
+ expect { v.to_version }.to_not raise_error
34
+ expect(v.to_version).to be_a(Semantic::Version)
34
35
  end
35
36
  end
36
37
 
37
- it "raises an error on invalid strings" do
38
+ it 'raises an error on invalid strings' do
38
39
  @bad_versions.each do |v|
39
- expect { v.to_version }.to raise_error(ArgumentError)
40
+ expect { v.to_version }.to raise_error(
41
+ ArgumentError,
42
+ /not a valid SemVer/
43
+ )
44
+ end
45
+ end
46
+
47
+ it 'extends String with a #is_version? method' do
48
+ expect('').to respond_to(:is_version?)
49
+ end
50
+
51
+ it 'detects valid semantic version strings' do
52
+ @test_versions.each do |v|
53
+ expect(v.is_version?).to be true
54
+ end
55
+ end
56
+
57
+ it 'detects invalid semantic version strings' do
58
+ @bad_versions.each do |v|
59
+ expect(v.is_version?).to be false
40
60
  end
41
61
  end
42
62
  end
data/spec/spec_helper.rb CHANGED
@@ -8,7 +8,6 @@ RSpec.configure do |config|
8
8
  require 'semantic'
9
9
 
10
10
  config.mock_framework = :rspec
11
- config.treat_symbols_as_metadata_keys_with_true_values = true
12
11
  config.run_all_when_everything_filtered = true
13
12
  config.filter_run :focus
14
13
 
data/spec/version_spec.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
-
2
+ # rubocop:disable Metrics/BlockLength, Style/VariableNumber
3
3
  describe Semantic::Version do
4
4
  before(:each) do
5
5
  @test_versions = [
@@ -17,111 +17,342 @@ describe Semantic::Version do
17
17
  '1.a.3',
18
18
  'a.3.4',
19
19
  '5.2.a',
20
- 'pre3-1.5.3'
20
+ 'pre3-1.5.3',
21
+ "I am not a valid semver\n0.0.0\nbut I still pass"
21
22
  ]
22
23
  end
23
24
 
24
- context "parsing" do
25
- it "parses valid SemVer versions" do
25
+ context 'parsing' do
26
+ it 'parses valid SemVer versions' do
26
27
  @test_versions.each do |v|
27
- expect { Semantic::Version.new v }.to_not raise_error(ArgumentError)
28
+ expect { Semantic::Version.new v }.not_to raise_error
28
29
  end
29
30
  end
30
31
 
31
- it "raises an error on invalid versions" do
32
+ it 'raises an error on invalid versions' do
32
33
  @bad_versions.each do |v|
33
- expect { Semantic::Version.new v }.to raise_error(ArgumentError)
34
+ expect { Semantic::Version.new v }.to raise_error(
35
+ ArgumentError,
36
+ /not a valid SemVer/
37
+ )
34
38
  end
35
39
  end
36
40
 
37
- it "stores parsed versions in member variables" do
41
+ it 'stores parsed versions in member variables' do
38
42
  v1 = Semantic::Version.new '1.5.9'
39
- v1.major.should == 1
40
- v1.minor.should == 5
41
- v1.patch.should == 9
42
- v1.pre.should be_nil
43
- v1.build.should be_nil
43
+ expect(v1.major).to eq(1)
44
+ expect(v1.minor).to eq(5)
45
+ expect(v1.patch).to eq(9)
46
+ expect(v1.pre).to be_nil
47
+ expect(v1.build).to be_nil
44
48
 
45
49
  v2 = Semantic::Version.new '0.0.1-pre.1'
46
- v2.major.should == 0
47
- v2.minor.should == 0
48
- v2.patch.should == 1
49
- v2.pre.should == 'pre.1'
50
- v2.build.should be_nil
50
+ expect(v2.major).to eq(0)
51
+ expect(v2.minor).to eq(0)
52
+ expect(v2.patch).to eq(1)
53
+ expect(v2.pre).to eq('pre.1')
54
+ expect(v2.build).to be_nil
51
55
 
52
56
  v3 = Semantic::Version.new '1.0.1-pre.5+build.123.5'
53
- v3.major.should == 1
54
- v3.minor.should == 0
55
- v3.patch.should == 1
56
- v3.pre.should == 'pre.5'
57
- v3.build.should == 'build.123.5'
57
+ expect(v3.major).to eq(1)
58
+ expect(v3.minor).to eq(0)
59
+ expect(v3.patch).to eq(1)
60
+ expect(v3.pre).to eq('pre.5')
61
+ expect(v3.build).to eq('build.123.5')
58
62
 
59
63
  v4 = Semantic::Version.new '0.0.0+hello'
60
- v4.major.should == 0
61
- v4.minor.should == 0
62
- v4.patch.should == 0
63
- v4.pre.should be_nil
64
- v4.build.should == 'hello'
64
+ expect(v4.major).to eq(0)
65
+ expect(v4.minor).to eq(0)
66
+ expect(v4.patch).to eq(0)
67
+ expect(v4.pre).to be_nil
68
+ expect(v4.build).to eq('hello')
69
+ end
70
+
71
+ it 'provides round-trip fidelity for an empty build parameter' do
72
+ v = Semantic::Version.new('1.2.3')
73
+ v.build = ''
74
+ expect(Semantic::Version.new(v.to_s).build).to eq(v.build)
75
+ end
76
+
77
+ it 'provides round-trip fidelity for a nil build parameter' do
78
+ v = Semantic::Version.new('1.2.3+build')
79
+ v.build = nil
80
+ expect(Semantic::Version.new(v.to_s).build).to eq(v.build)
65
81
  end
66
82
  end
67
83
 
68
- context "comparisons" do
84
+ context 'comparisons' do
69
85
  before(:each) do
70
- @v1 = Semantic::Version.new '1.5.9'
71
- @v2 = Semantic::Version.new '1.6.0'
72
- @v3 = Semantic::Version.new '1.5.9-pre.1'
73
- @v4 = Semantic::Version.new '1.5.9-pre.1+build.5127'
86
+ # These three are all semantically equivalent, according to the spec.
87
+ @v1_5_9_pre_1 = Semantic::Version.new '1.5.9-pre.1'
88
+ @v1_5_9_pre_1_build_5127 = Semantic::Version.new '1.5.9-pre.1+build.5127'
89
+ @v1_5_9_pre_1_build_4352 = Semantic::Version.new '1.5.9-pre.1+build.4352'
90
+ # more pre syntax testing: "-"
91
+ @v3_13_0_75_generic = Semantic::Version.new '3.13.0-75-generic'
92
+ @v3_13_0_141_generic = Semantic::Version.new '3.13.0-141-generic'
93
+
94
+ @v1_5_9 = Semantic::Version.new '1.5.9'
95
+ @v1_6_0 = Semantic::Version.new '1.6.0'
96
+
97
+ @v1_6_0_alpha = Semantic::Version.new '1.6.0-alpha'
98
+ @v1_6_0_alpha_1 = Semantic::Version.new '1.6.0-alpha.1'
99
+ @v1_6_0_alpha_beta = Semantic::Version.new '1.6.0-alpha.beta'
100
+ @v1_6_0_beta = Semantic::Version.new '1.6.0-beta'
101
+ @v1_6_0_beta_2 = Semantic::Version.new '1.6.0-beta.2'
102
+ @v1_6_0_beta_11 = Semantic::Version.new '1.6.0-beta.11'
103
+ @v1_6_0_rc_1 = Semantic::Version.new '1.6.0-rc.1'
104
+
105
+ # expected order:
106
+ # 1.6.0-alpha < 1.6.0-alpha.1 < 1.6.0-alpha.beta < 1.6.0-beta
107
+ # < 1.6.0-beta.2 < 1.6.0-beta.11 < 1.6.0-rc.1 < 1.6.0.
108
+ end
109
+
110
+ it 'determines sort order' do
111
+ # The second parameter here can be a string, so we want to ensure that
112
+ # this kind of comparison works also.
113
+ expect((@v1_5_9_pre_1 <=> @v1_5_9_pre_1.to_s)).to eq(0)
114
+
115
+ expect((@v1_5_9_pre_1 <=> @v1_5_9_pre_1_build_5127)).to eq(0)
116
+ expect((@v1_5_9_pre_1 <=> @v1_5_9)).to eq(-1)
117
+ expect((@v1_5_9_pre_1_build_5127 <=> @v1_5_9)).to eq(-1)
118
+
119
+ expect(@v1_5_9_pre_1_build_5127.build).to eq('build.5127')
120
+
121
+ expect((@v1_5_9 <=> @v1_6_0)).to eq(-1)
122
+ expect((@v1_6_0 <=> @v1_5_9)).to eq(1)
123
+ expect((@v1_6_0 <=> @v1_5_9_pre_1)).to eq(1)
124
+ expect((@v1_5_9_pre_1 <=> @v1_6_0)).to eq(-1)
125
+
126
+ expect([@v1_5_9_pre_1, @v1_5_9_pre_1_build_5127, @v1_5_9, @v1_6_0]
127
+ .reverse.sort).to \
128
+ eq([@v1_5_9_pre_1, @v1_5_9_pre_1_build_5127, @v1_5_9, @v1_6_0])
129
+ end
130
+
131
+ it 'determines sort order pre' do
132
+ ary = [@v1_6_0_alpha, @v1_6_0_alpha_1, @v1_6_0_alpha_beta,
133
+ @v1_6_0_beta, @v1_6_0_beta_2, @v1_6_0_beta_11, @v1_6_0_rc_1,
134
+ @v1_6_0]
135
+ expect(ary.shuffle.sort).to eq(ary)
136
+ end
137
+
138
+ it 'determine alternate char sep works in pre' do
139
+ expect((@v3_13_0_75_generic <=> @v3_13_0_141_generic.to_s)).to eq(-1)
140
+ expect((@v3_13_0_75_generic <=> @v3_13_0_141_generic)).to eq(-1)
141
+ expect((@v3_13_0_75_generic <=> '3.13.0-75-generic')).to eq(0)
142
+ expect((@v3_13_0_75_generic <=> '3.13.0-141-generic')).to eq(-1)
143
+ expect((@v3_13_0_141_generic <=> '3.13.0-75-generic')).to eq(1)
144
+ end
145
+
146
+ it 'determines whether it is greater than another instance' do
147
+ # These should be equal, since "Build metadata SHOULD be ignored
148
+ # when determining version precedence".
149
+ # (SemVer 2.0.0-rc.2, paragraph 10 - http://www.semver.org)
150
+ expect(@v1_5_9_pre_1).not_to be > @v1_5_9_pre_1_build_5127
151
+ expect(@v1_5_9_pre_1).not_to be < @v1_5_9_pre_1_build_5127
152
+
153
+ expect(@v1_6_0).to be > @v1_5_9
154
+ expect(@v1_5_9).not_to be > @v1_6_0
155
+ expect(@v1_5_9).to be > @v1_5_9_pre_1_build_5127
156
+ expect(@v1_5_9).to be > @v1_5_9_pre_1
157
+ end
158
+
159
+ it 'determines whether it is less than another instance' do
160
+ expect(@v1_5_9_pre_1).not_to be < @v1_5_9_pre_1_build_5127
161
+ expect(@v1_5_9_pre_1_build_5127).not_to be < @v1_5_9_pre_1
162
+ expect(@v1_5_9_pre_1).to be < @v1_5_9
163
+ expect(@v1_5_9_pre_1).to be < @v1_6_0
164
+ expect(@v1_5_9_pre_1_build_5127).to be < @v1_6_0
165
+ expect(@v1_5_9).to be < @v1_6_0
166
+ end
167
+
168
+ it 'determines whether it is greater than or equal to another instance' do
169
+ expect(@v1_5_9_pre_1).to be >= @v1_5_9_pre_1
170
+ expect(@v1_5_9_pre_1).to be >= @v1_5_9_pre_1_build_5127
171
+ expect(@v1_5_9_pre_1_build_5127).to be >= @v1_5_9_pre_1
172
+ expect(@v1_5_9).to be >= @v1_5_9_pre_1
173
+ expect(@v1_6_0).to be >= @v1_5_9
174
+ expect(@v1_5_9_pre_1_build_5127).not_to be >= @v1_6_0
175
+ end
176
+
177
+ it 'determines whether it is less than or equal to another instance' do
178
+ expect(@v1_5_9_pre_1).to be <= @v1_5_9_pre_1_build_5127
179
+ expect(@v1_6_0).not_to be <= @v1_5_9
180
+ expect(@v1_5_9_pre_1_build_5127).to be <= @v1_5_9_pre_1_build_5127
181
+ expect(@v1_5_9).not_to be <= @v1_5_9_pre_1
182
+ end
183
+
184
+ it 'determines whether it is semantically equal to another instance' do
185
+ expect(@v1_5_9_pre_1).to eq(@v1_5_9_pre_1.dup)
186
+ expect(@v1_5_9_pre_1_build_5127).to eq(@v1_5_9_pre_1_build_5127.dup)
187
+
188
+ # "Semantically equal" is the keyword here; these are by definition
189
+ # not "equal" (different build), but should be treated as
190
+ # equal according to the spec.
191
+ expect(@v1_5_9_pre_1_build_4352).to eq(@v1_5_9_pre_1_build_5127)
192
+ expect(@v1_5_9_pre_1_build_4352).to eq(@v1_5_9_pre_1)
193
+ end
194
+
195
+ it 'determines whether it is between two others instance' do
196
+ expect(@v1_5_9).to be_between @v1_5_9_pre_1, @v1_6_0
197
+ expect(@v1_5_9).to_not be_between @v1_6_0, @v1_6_0_beta
198
+ end
199
+
200
+ it 'determines whether it satisfies >= style specifications' do
201
+ expect(@v1_6_0.satisfies?('>=1.6.0')).to be true
202
+ expect(@v1_6_0.satisfies?('<=1.6.0')).to be true
203
+ expect(@v1_6_0.satisfies?('>=1.5.0')).to be true
204
+ expect(@v1_6_0.satisfies?('<=1.5.0')).not_to be true
205
+
206
+ # partial / non-semver numbers after comparator are extremely common in
207
+ # version specifications in the wild
208
+
209
+ expect(@v1_6_0.satisfies?('>1.5')).to be true
210
+ expect(@v1_6_0.satisfies?('<1')).not_to be true
74
211
  end
75
212
 
76
- it "determines sort order" do
77
- (@v1 <=> @v2).should == -1
78
- (@v3 <=> @v1).should == 1
79
- (@v3 <=> @v4).should == -1
80
- (@v4 <=> @v4).should == 0
81
- (@v4 <=> @v1).should == 1
213
+ it 'determines whether it satisfies * style specifications' do
214
+ expect(@v1_6_0.satisfies?('1.*')).to be true
215
+ expect(@v1_6_0.satisfies?('1.6.*')).to be true
216
+ expect(@v1_6_0.satisfies?('2.*')).not_to be true
217
+ expect(@v1_6_0.satisfies?('1.5.*')).not_to be true
218
+ end
82
219
 
83
- [@v3, @v1, @v2, @v4].sort.should == [@v1, @v3, @v4, @v2]
220
+ it 'determines whether it satisfies ~ style specifications' do
221
+ expect(@v1_6_0.satisfies?('~1.6')).to be true
222
+ expect(@v1_5_9_pre_1.satisfies?('~1.5')).to be true
223
+ expect(@v1_6_0.satisfies?('~1.5')).not_to be true
84
224
  end
85
225
 
86
- it "determines whether it is greater than another instance" do
87
- @v1.should_not > @v2
88
- @v4.should > @v3
89
- @v2.should > @v4
90
- @v3.should_not > @v4
226
+ it 'determines whether it satisfies ~> style specifications' do
227
+ expect(@v1_5_9_pre_1_build_5127.satisfies?('~> 1.4')).to be true
228
+ expect(@v1_5_9_pre_1_build_4352.satisfies?('~> 1.5.2')).to be true
229
+ expect(@v1_6_0_alpha_1.satisfies?('~> 1.4')).to be true
230
+
231
+ expect(@v1_5_9.satisfies?('~> 1.0')).to be true
232
+ expect(@v1_5_9.satisfies?('~> 1.4')).to be true
233
+ expect(Semantic::Version.new('1.99.1').satisfies?('~> 1.5')).to be true
234
+ expect(@v1_5_9.satisfies?('~> 1.5')).to be true
235
+ expect(@v1_5_9.satisfies?('~> 1.5.0')).to be true
236
+ expect(@v1_5_9.satisfies?('~> 1.5.8')).to be true
237
+ expect(@v1_5_9.satisfies?('~> 1.5.9')).to be true
238
+ expect(Semantic::Version.new('1.5.99').satisfies?('~> 1.5.9')).to be true
239
+ expect(@v1_5_9.satisfies?('~> 1.6.0')).to be false
240
+ expect(@v1_5_9.satisfies?('~> 1.6')).to be false
241
+ expect(@v1_5_9.satisfies?('~> 1.7')).to be false
91
242
  end
92
243
 
93
- it "determines whether it is less than another insance" do
94
- @v1.should < @v2
95
- @v2.should_not < @v4
96
- @v4.should < @v2
97
- @v3.should < @v4
244
+ it 'determines whether version is satisfies by range of bound versions' do
245
+ v5_2_1 = Semantic::Version.new('5.2.1')
246
+ v5_3_0 = Semantic::Version.new('5.3.0')
247
+ v6_0_1 = Semantic::Version.new('6.0.1')
248
+ range = [
249
+ ">= 5.2.1",
250
+ "<= 6.0.0"
251
+ ]
252
+
253
+ expect(v5_2_1.satisfied_by?(range)).to be true
254
+ expect(v5_3_0.satisfied_by?(range)).to be true
255
+ expect(v6_0_1.satisfied_by?(range)).to be false
256
+ end
257
+
258
+ it 'raises error if the input is not an array of versions' do
259
+ v5_2_1 = Semantic::Version.new('5.2.1')
260
+ range = ">= 5.2.1 <= 6.0.0"
261
+ expect { v5_2_1.satisfied_by?(range) }.to raise_error(
262
+ ArgumentError,
263
+ /should be an array of versions/
264
+ )
98
265
  end
99
266
  end
100
267
 
101
- context "type coercions" do
102
- it "converts to a string" do
268
+ context 'type coercions' do
269
+ it 'converts to a string' do
103
270
  @test_versions.each do |v|
104
- Semantic::Version.new(v).to_s.should == v
271
+ expect(Semantic::Version.new(v).to_s).to be == v
105
272
  end
106
273
  end
107
274
 
108
- it "converts to an array" do
109
- Semantic::Version.new('1.0.0').to_a.should == [1, 0, 0, nil, nil]
110
- Semantic::Version.new('6.1.4-pre.5').to_a.should == [6, 1, 4, 'pre.5', nil]
111
- Semantic::Version.new('91.6.0+build.17').to_a.should == [91, 6, 0, nil, 'build.17']
112
- Semantic::Version.new('0.1.5-pre.7+build191').to_a.should == [0, 1, 5, 'pre.7', 'build191']
275
+ it 'converts to an array' do
276
+ expect(Semantic::Version.new('1.0.0').to_a).to \
277
+ eq([1, 0, 0, nil, nil])
278
+ expect(Semantic::Version.new('6.1.4-pre.5').to_a).to \
279
+ eq([6, 1, 4, 'pre.5', nil])
280
+ expect(Semantic::Version.new('91.6.0+build.17').to_a).to \
281
+ eq([91, 6, 0, nil, 'build.17'])
282
+ expect(Semantic::Version.new('0.1.5-pre.7+build191').to_a).to \
283
+ eq([0, 1, 5, 'pre.7', 'build191'])
113
284
  end
114
285
 
115
- it "converts to a hash" do
116
- Semantic::Version.new('1.0.0').to_h.should == { major: 1, minor: 0, patch: 0, pre: nil, build: nil }
117
- Semantic::Version.new('6.1.4-pre.5').to_h.should == { major: 6, minor: 1, patch: 4, pre: 'pre.5', build: nil }
118
- Semantic::Version.new('91.6.0+build.17').to_h.should == { major: 91, minor: 6, patch: 0, pre: nil, build: 'build.17' }
119
- Semantic::Version.new('0.1.5-pre.7+build191').to_h.should == { major: 0, minor: 1, patch: 5, pre: 'pre.7', build: 'build191' }
286
+ it 'converts to a hash' do
287
+ expect(Semantic::Version.new('1.0.0').to_h).to \
288
+ eq(major: 1, minor: 0, patch: 0, pre: nil, build: nil)
289
+ expect(Semantic::Version.new('6.1.4-pre.5').to_h).to \
290
+ eq(major: 6, minor: 1, patch: 4, pre: 'pre.5', build: nil)
291
+ expect(Semantic::Version.new('91.6.0+build.17').to_h).to \
292
+ eq(major: 91, minor: 6, patch: 0, pre: nil, build: 'build.17')
293
+ expect(Semantic::Version.new('0.1.5-pre.7+build191').to_h).to \
294
+ eq(major: 0, minor: 1, patch: 5, pre: 'pre.7', build: 'build191')
120
295
  end
121
296
 
122
- it "aliases conversion methods" do
297
+ it 'aliases conversion methods' do
123
298
  v = Semantic::Version.new('0.0.0')
124
- [:to_hash, :to_array, :to_string].each { |sym| v.should respond_to(sym) }
299
+ [:to_hash, :to_array, :to_string].each do |sym|
300
+ expect(v).to respond_to(sym)
301
+ end
302
+ end
303
+ end
304
+
305
+ it 'as hash key' do
306
+ hash = {}
307
+ hash[Semantic::Version.new('1.2.3-pre1+build2')] = 'semantic'
308
+ expect(hash[Semantic::Version.new('1.2.3-pre1+build2')]).to eq('semantic')
309
+ end
310
+
311
+ describe '#major!' do
312
+ subject { described_class.new('1.2.3-pre1+build2') }
313
+
314
+ context 'changing the major term' do
315
+ it 'changes the major version and resets the others' do
316
+ expect(subject.major!).to eq('2.0.0')
317
+ end
318
+ end
319
+ end
320
+
321
+ describe '#minor!' do
322
+ subject { described_class.new('1.2.3-pre1+build2') }
323
+
324
+ context 'changing the minor term' do
325
+ it 'changes minor term and resets patch, pre and build' do
326
+ expect(subject.minor!).to eq('1.3.0')
327
+ end
328
+ end
329
+ end
330
+
331
+ describe '#patch!' do
332
+ subject { described_class.new('1.2.3-pre1+build2') }
333
+
334
+ context 'changing the patch term' do
335
+ it 'changes the patch term and resets the pre and build' do
336
+ expect(subject.patch!).to eq('1.2.4')
337
+ end
338
+ end
339
+ end
340
+
341
+ describe '#increment!' do
342
+ subject { described_class.new('1.2.3-pre1+build2') }
343
+
344
+ context 'changing the minor term' do
345
+ context 'with a string' do
346
+ it 'changes the minor term and resets the path, pre and build' do
347
+ expect(subject.increment!('minor')).to eq('1.3.0')
348
+ end
349
+ end
350
+
351
+ context 'with a symbol' do
352
+ it 'changes the minor term and resets the path, pre and build' do
353
+ expect(subject.increment!(:minor)).to eq('1.3.0')
354
+ end
355
+ end
125
356
  end
126
357
  end
127
358
  end
metadata CHANGED
@@ -1,91 +1,84 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semantic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
5
- prerelease:
4
+ version: 1.6.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Josh Lindsey
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-07-23 00:00:00.000000000 Z
11
+ date: 2018-02-14 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rake
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
- version: 0.9.2.2
19
+ version: '11'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: 0.9.2.2
26
+ version: '11'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rspec
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ~>
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
- version: 2.11.0
33
+ version: '3'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ~>
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
- version: 2.11.0
46
- description: ! 'Semantic Version utility class for parsing, storing, and comparing
47
- versions. See: http://semver.org'
40
+ version: '3'
41
+ description: 'Semantic Version utility class for parsing, storing, and comparing versions.
42
+ See: http://semver.org'
48
43
  email:
49
- - josh@core-apps.com
44
+ - joshua.s.lindsey@gmail.com
50
45
  executables: []
51
46
  extensions: []
52
47
  extra_rdoc_files: []
53
48
  files:
54
- - lib/semantic/core_ext.rb
55
- - lib/semantic/version.rb
56
- - lib/semantic.rb
57
49
  - LICENSE
58
50
  - README.md
51
+ - lib/semantic.rb
52
+ - lib/semantic/core_ext.rb
53
+ - lib/semantic/version.rb
59
54
  - spec/core_ext_spec.rb
60
55
  - spec/spec_helper.rb
61
56
  - spec/version_spec.rb
62
57
  homepage: https://github.com/jlindsey/semantic
63
58
  licenses:
64
59
  - MIT
60
+ metadata: {}
65
61
  post_install_message:
66
62
  rdoc_options: []
67
63
  require_paths:
68
64
  - lib
69
65
  required_ruby_version: !ruby/object:Gem::Requirement
70
- none: false
71
66
  requirements:
72
- - - ! '>='
67
+ - - ">="
73
68
  - !ruby/object:Gem::Version
74
69
  version: '0'
75
70
  required_rubygems_version: !ruby/object:Gem::Requirement
76
- none: false
77
71
  requirements:
78
- - - ! '>='
72
+ - - ">="
79
73
  - !ruby/object:Gem::Version
80
74
  version: '0'
81
75
  requirements: []
82
76
  rubyforge_project:
83
- rubygems_version: 1.8.23
77
+ rubygems_version: 2.6.13
84
78
  signing_key:
85
- specification_version: 3
79
+ specification_version: 4
86
80
  summary: Semantic Version utility class
87
81
  test_files:
88
82
  - spec/core_ext_spec.rb
89
83
  - spec/spec_helper.rb
90
84
  - spec/version_spec.rb
91
- has_rdoc: