semver_stringer 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +13 -1
- data/lib/semver_stringer/semver.rb +160 -74
- data/lib/semver_stringer/version.rb +1 -1
- data/spec/semver_spec.rb +143 -0
- metadata +4 -4
data/README.md
CHANGED
@@ -19,7 +19,19 @@ Gives you a little help with your [semver](http://semver.org/) strings.
|
|
19
19
|
semver = SemverStringer::Semver.new version_info
|
20
20
|
semver.to_s # => "2.1.13-alpha.1+2134"
|
21
21
|
|
22
|
+
### SemVer comparisons
|
23
|
+
|
24
|
+
`Semver` implements the comparable module, so it's easy to compare
|
25
|
+
one Semver with another. The rules for comparisons are taken from
|
26
|
+
the spec at semver.org. Example:
|
27
|
+
|
28
|
+
version1 = SemverStringer::Semver.new :major=>1, :minor=>0, :patch=>0
|
29
|
+
version2alpha = SemverStringer::Semver.new :major=>2, :minor=0, :patch=>0, :pre=>"alpha"
|
30
|
+
version2 = SemverStringer::Semver.new :major=>2, :minor=0, :patch=>0
|
31
|
+
|
32
|
+
version1 < version2alpha #=> true
|
33
|
+
version2alpha < version2 #=> true
|
34
|
+
|
22
35
|
## TODO
|
23
36
|
|
24
|
-
* Comparison operators to implement the ordering as laid out in the semver spec.
|
25
37
|
* Constructor taking string parameter for parsing and initialization
|
@@ -1,5 +1,56 @@
|
|
1
1
|
module SemverStringer
|
2
|
-
|
2
|
+
|
3
|
+
class Semver
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
class Substring
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
def initialize(s)
|
10
|
+
@str = s
|
11
|
+
end
|
12
|
+
|
13
|
+
def <=>(other)
|
14
|
+
other_str = other.instance_variable_get('@str')
|
15
|
+
return Substring::compareVersionStrings @str, other_str
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.compareVersionStrings(first, second)
|
19
|
+
first_components = first.split('.')
|
20
|
+
second_components = second.split('.')
|
21
|
+
|
22
|
+
first_head = first_components.shift
|
23
|
+
second_head = second_components.shift
|
24
|
+
|
25
|
+
head_comparison = compare_version_atoms first_head, second_head
|
26
|
+
if head_comparison == 0
|
27
|
+
if first_components.length > 0 or second_components.length > 0
|
28
|
+
return Substring::compareVersionStrings first_components.join('.'), second_components.join('.')
|
29
|
+
else
|
30
|
+
return 0
|
31
|
+
end
|
32
|
+
else
|
33
|
+
return head_comparison
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.compare_version_atoms(first, second)
|
38
|
+
if first == nil and second == nil
|
39
|
+
return nil
|
40
|
+
elsif first != nil and second == nil
|
41
|
+
return 1
|
42
|
+
elsif first == nil and second != nil
|
43
|
+
return -1
|
44
|
+
else
|
45
|
+
unless first.match /[^0-9]/ or second.match /[^0-9]/
|
46
|
+
return first.to_i <=> second.to_i
|
47
|
+
else
|
48
|
+
return first <=> second
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
3
54
|
|
4
55
|
# Creates a new Semver instance.
|
5
56
|
#
|
@@ -9,11 +60,53 @@ module SemverStringer
|
|
9
60
|
# @option params [Integer] :patch Patch version number
|
10
61
|
# @option params [String, Integer, Array<String, Integer>] :pre Pre-release identifier(s)
|
11
62
|
# @option params [String, Integer, Array<String, Integer>] :build Build number identifier(s)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
63
|
+
def initialize(params={})
|
64
|
+
@major, @minor, @patch = get_version_numbers_from params
|
65
|
+
@build = get_build_string_from params
|
66
|
+
@pre = get_pre_string_from params
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# All the semver.org comparison rules are expressed by this operator
|
71
|
+
def <=>(other)
|
72
|
+
|
73
|
+
versionComparison = Substring.new(get_version_string) <=> Substring.new(other.get_version_string)
|
74
|
+
(return versionComparison) if versionComparison != 0
|
75
|
+
|
76
|
+
other_pre = other.instance_variable_get('@pre')
|
77
|
+
if @pre != nil and other_pre == nil
|
78
|
+
return -1
|
79
|
+
elsif @pre == nil and other_pre != nil
|
80
|
+
return 1
|
81
|
+
elsif @pre != nil and other_pre != nil
|
82
|
+
pre_comparison = Substring.new(@pre) <=> Substring.new(other_pre)
|
83
|
+
(return pre_comparison) if pre_comparison != 0
|
84
|
+
end
|
85
|
+
|
86
|
+
other_build = other.instance_variable_get('@build')
|
87
|
+
if @build == nil and other_build != nil
|
88
|
+
return -1
|
89
|
+
elsif @build != nil and other_build == nil
|
90
|
+
return 1
|
91
|
+
elsif @build != nil and other_build != nil
|
92
|
+
build_comparison = Substring.new(@build) <=> Substring.new(other_build)
|
93
|
+
(return build_comparison) if build_comparison != 0
|
94
|
+
end
|
95
|
+
|
96
|
+
return 0
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_version_string
|
100
|
+
"#{@major}.#{@minor}.#{@patch}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def get_pre_string
|
104
|
+
@pre
|
105
|
+
end
|
106
|
+
|
107
|
+
def get_build_string
|
108
|
+
@build
|
109
|
+
end
|
17
110
|
|
18
111
|
# Returns a string representation of the SemVer
|
19
112
|
#
|
@@ -21,72 +114,65 @@ module SemverStringer
|
|
21
114
|
# SemverStringer::Semver.new(:major=>2, :pre=>"alpha").to_s #=> "2.0.0-alpha"
|
22
115
|
#
|
23
116
|
# @return [String]
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
[major, minor, patch]
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
def get_pre_string_from(params)
|
61
|
-
return get_optional_string_from params, :pre
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
def get_build_string_from(params)
|
66
|
-
return get_optional_string_from params, :build
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
def get_optional_string_from(params, type)
|
71
|
-
disallowed_chars = /[^0-9A-Za-z-]/
|
72
|
-
|
73
|
-
if params.has_key? type
|
74
|
-
identifiers = scalar_to_array params[type]
|
75
|
-
|
76
|
-
identifiers.each do |param|
|
77
|
-
raise ArgumentError.new("Characters in #{type} ID are not allowed") if disallowed_chars.match param.to_s
|
78
|
-
end
|
79
|
-
|
80
|
-
return identifiers.join "."
|
81
|
-
else
|
82
|
-
return nil
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
def scalar_to_array(scalar)
|
88
|
-
(scalar.is_a? Array) ? scalar : Array.new(1, scalar)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
117
|
+
def to_s
|
118
|
+
version = get_version_string
|
119
|
+
version << "-#{get_pre_string}" unless @pre == nil
|
120
|
+
version << "+#{get_build_string}" unless @build == nil
|
121
|
+
version
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
def raise_if_invalid_version_number(hash, key)
|
126
|
+
if hash.has_key? key
|
127
|
+
raise ArgumentError.new("Positive integers only") if hash[key] < 0
|
128
|
+
raise ArgumentError.new("Integral numbers only") if ! hash[key].integer?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def get_valid_version_number(hash, key)
|
133
|
+
raise_if_invalid_version_number(hash, key)
|
134
|
+
(hash.has_key? key) ? hash[key] : 0
|
135
|
+
end
|
136
|
+
|
137
|
+
def get_version_numbers_from(params)
|
138
|
+
if (params.has_key? :major) || (params.has_key? :minor) || (params.has_key? :patch)
|
139
|
+
major = get_valid_version_number(params, :major)
|
140
|
+
minor = get_valid_version_number(params, :minor)
|
141
|
+
patch = get_valid_version_number(params, :patch)
|
142
|
+
else
|
143
|
+
major = minor = 0
|
144
|
+
patch = 1
|
145
|
+
end
|
146
|
+
|
147
|
+
[major, minor, patch]
|
148
|
+
end
|
92
149
|
|
150
|
+
def get_pre_string_from(params)
|
151
|
+
return get_optional_string_from params, :pre
|
152
|
+
end
|
153
|
+
|
154
|
+
def get_build_string_from(params)
|
155
|
+
return get_optional_string_from params, :build
|
156
|
+
end
|
157
|
+
|
158
|
+
def get_optional_string_from(params, type)
|
159
|
+
disallowed_chars = /[^0-9A-Za-z-]/
|
160
|
+
|
161
|
+
if params.has_key? type
|
162
|
+
identifiers = scalar_to_array params[type]
|
163
|
+
|
164
|
+
identifiers.each do |param|
|
165
|
+
raise ArgumentError.new("Characters in #{type} ID are not allowed") if disallowed_chars.match param.to_s
|
166
|
+
end
|
167
|
+
|
168
|
+
return identifiers.join "."
|
169
|
+
else
|
170
|
+
return nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def scalar_to_array(scalar)
|
175
|
+
(scalar.is_a? Array) ? scalar : Array.new(1, scalar)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
data/spec/semver_spec.rb
CHANGED
@@ -103,4 +103,147 @@ describe SemverStringer::Semver do
|
|
103
103
|
semver.to_s.should == "1.2.303-beta+build.1234"
|
104
104
|
end
|
105
105
|
end
|
106
|
+
|
107
|
+
describe "semver comparson operator" do
|
108
|
+
|
109
|
+
RSpec::Matchers.define :be_higher_than do |lower|
|
110
|
+
match do |higher|
|
111
|
+
(higher <=> lower) == 1 and
|
112
|
+
(higher < lower) == false and
|
113
|
+
(higher == lower) == false and
|
114
|
+
(higher > lower) == true and
|
115
|
+
(lower <=> higher) == -1 and
|
116
|
+
(lower < higher) == true and
|
117
|
+
(lower == higher) == false and
|
118
|
+
(lower > higher) == false
|
119
|
+
end
|
120
|
+
|
121
|
+
failure_message_for_should do |higher|
|
122
|
+
"expected that #{higher} would be higher than #{lower} (<=> got #{higher<=>lower})"
|
123
|
+
end
|
124
|
+
|
125
|
+
failure_message_for_should_not do |higher|
|
126
|
+
"expected that #{higher} would not be higher than #{lower} (<=> got #{higher<=>lower})"
|
127
|
+
end
|
128
|
+
|
129
|
+
description do
|
130
|
+
"be higher than #{lower}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "is equal if version numbers are all identical" do
|
135
|
+
semver1 = SemverStringer::Semver.new :major=>2, :minor=>5, :patch=>9
|
136
|
+
semver2 = SemverStringer::Semver.new :major=>2, :minor=>5, :patch=>9
|
137
|
+
|
138
|
+
(semver1 <=> semver2).should == 0
|
139
|
+
(semver1 < semver2).should == false
|
140
|
+
(semver1 == semver2).should == true
|
141
|
+
(semver1 > semver2).should == false
|
142
|
+
|
143
|
+
(semver2 <=> semver1).should == 0
|
144
|
+
(semver2 < semver1).should == false
|
145
|
+
(semver2 == semver1).should == true
|
146
|
+
(semver2 > semver1).should == false
|
147
|
+
end
|
148
|
+
|
149
|
+
it "gives highest precedence to major" do
|
150
|
+
higher = SemverStringer::Semver.new :major=>3, :minor=>1, :patch=>1
|
151
|
+
lower = SemverStringer::Semver.new :major=>2, :minor=>50, :patch=>50
|
152
|
+
|
153
|
+
higher.should be_higher_than lower
|
154
|
+
end
|
155
|
+
|
156
|
+
it "gives second precedence to minor" do
|
157
|
+
higher = SemverStringer::Semver.new :major=>2, :minor=>6, :patch=>1
|
158
|
+
lower = SemverStringer::Semver.new :major=>2, :minor=>2, :patch=>900
|
159
|
+
|
160
|
+
higher.should be_higher_than lower
|
161
|
+
end
|
162
|
+
|
163
|
+
it "considers pre-release semvers lower than non-pre-release semvers" do
|
164
|
+
higher = SemverStringer::Semver.new
|
165
|
+
lower = SemverStringer::Semver.new :pre=>1
|
166
|
+
|
167
|
+
higher.should be_higher_than lower
|
168
|
+
end
|
169
|
+
|
170
|
+
it "compares pre numbers as integers" do
|
171
|
+
higher = SemverStringer::Semver.new :pre=>11
|
172
|
+
lower = SemverStringer::Semver.new :pre=>"2"
|
173
|
+
|
174
|
+
higher.should be_higher_than lower
|
175
|
+
end
|
176
|
+
|
177
|
+
it "compares pre numbers with chars or - as strings" do
|
178
|
+
higher = SemverStringer::Semver.new :pre=>"a"
|
179
|
+
lower = SemverStringer::Semver.new :pre=>1
|
180
|
+
|
181
|
+
higher.should be_higher_than lower
|
182
|
+
end
|
183
|
+
|
184
|
+
it "considers build-numbered semvers higher than non-build numbered semvers" do
|
185
|
+
higher = SemverStringer::Semver.new :build=>1
|
186
|
+
lower = SemverStringer::Semver.new
|
187
|
+
|
188
|
+
higher.should be_higher_than lower
|
189
|
+
end
|
190
|
+
|
191
|
+
it "ignores build numbers if the main versions are different" do
|
192
|
+
higher = SemverStringer::Semver.new :major=>2, :minor=>6, :patch=>1
|
193
|
+
lower = SemverStringer::Semver.new :major=>2, :minor=>5, :patch=>1, :build=>9
|
194
|
+
|
195
|
+
higher.should be_higher_than lower
|
196
|
+
end
|
197
|
+
|
198
|
+
it "compares integer build numbers as integers" do
|
199
|
+
higher = SemverStringer::Semver.new :build=>11
|
200
|
+
lower = SemverStringer::Semver.new :build=>"2"
|
201
|
+
|
202
|
+
higher.should be_higher_than lower
|
203
|
+
end
|
204
|
+
|
205
|
+
it "compares build numbers with chars or - as strings" do
|
206
|
+
higher = SemverStringer::Semver.new :build=>"a"
|
207
|
+
lower = SemverStringer::Semver.new :build=>1
|
208
|
+
|
209
|
+
higher.should be_higher_than lower
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "Semver::Substring comparator" do
|
213
|
+
it "compares equal numbers as integers" do
|
214
|
+
first = SemverStringer::Semver::Substring.new "4"
|
215
|
+
second = SemverStringer::Semver::Substring.new "4"
|
216
|
+
|
217
|
+
(first <=> second).should be 0
|
218
|
+
end
|
219
|
+
|
220
|
+
it "compares numbers as integers" do
|
221
|
+
higher = SemverStringer::Semver::Substring.new "12"
|
222
|
+
lower = SemverStringer::Semver::Substring.new "4"
|
223
|
+
|
224
|
+
higher.should be_higher_than lower
|
225
|
+
end
|
226
|
+
|
227
|
+
it "compares period-delimeted sub-numbers with each other" do
|
228
|
+
first = SemverStringer::Semver::Substring.new "a.b.2"
|
229
|
+
second = SemverStringer::Semver::Substring.new "a.b.2"
|
230
|
+
(first <=> second).should be 0
|
231
|
+
|
232
|
+
higher = SemverStringer::Semver::Substring.new "4.beta"
|
233
|
+
lower = SemverStringer::Semver::Substring.new "4.alpha"
|
234
|
+
higher.should be_higher_than lower
|
235
|
+
|
236
|
+
higher = SemverStringer::Semver::Substring.new "alpha.11"
|
237
|
+
lower = SemverStringer::Semver::Substring.new "alpha.2"
|
238
|
+
higher.should be_higher_than lower
|
239
|
+
end
|
240
|
+
|
241
|
+
it "compares a number with an extra segment higher than one without" do
|
242
|
+
higher = SemverStringer::Semver::Substring.new "alpha.2.a"
|
243
|
+
lower = SemverStringer::Semver::Substring.new "alpha.2"
|
244
|
+
higher.should be_higher_than lower
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
end
|
106
249
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: semver_stringer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70277379840900 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '2.8'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70277379840900
|
25
25
|
description: See semver.org for the rules, or https://github.com/iantruslove/SemverStringer#readme
|
26
26
|
for a little documentation.
|
27
27
|
email:
|