semver_stringer 0.1.1 → 0.2.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.
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: