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 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
- class Semver
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
- def initialize(params={})
13
- @major, @minor, @patch = get_version_numbers_from params
14
- @build = get_build_string_from params
15
- @pre = get_pre_string_from params
16
- end
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
- def to_s
25
- version = "#{@major}.#{@minor}.#{@patch}"
26
- version << "-#{@pre}" unless @pre == nil
27
- version << "+#{@build}" unless @build == nil
28
- version
29
- end
30
-
31
- private
32
- def raise_if_invalid_version_number(hash, key)
33
- if hash.has_key? key
34
- raise ArgumentError.new("Positive integers only") if hash[key] < 0
35
- raise ArgumentError.new("Integral numbers only") if ! hash[key].integer?
36
- end
37
- end
38
-
39
- private
40
- def get_valid_version_number(hash, key)
41
- raise_if_invalid_version_number(hash, key)
42
- (hash.has_key? key) ? hash[key] : 0
43
- end
44
-
45
- private
46
- def get_version_numbers_from(params)
47
- if (params.has_key? :major) || (params.has_key? :minor) || (params.has_key? :patch)
48
- major = get_valid_version_number(params, :major)
49
- minor = get_valid_version_number(params, :minor)
50
- patch = get_valid_version_number(params, :patch)
51
- else
52
- major = minor = 0
53
- patch = 1
54
- end
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
@@ -1,3 +1,3 @@
1
1
  module SemverStringer
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  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.1.1
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-02-29 00:00:00.000000000 Z
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: &70278852677040 !ruby/object:Gem::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: *70278852677040
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: