semantic 1.0.0 → 1.6.1

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