semantic_range 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 40689a4a60d1676915d3c80166fa016fed599e9e
4
- data.tar.gz: a6797c03b699280fbb46196f83b6b9d29de102e3
3
+ metadata.gz: 713091878f31485514b30d0ab9e9f7281576a260
4
+ data.tar.gz: 0f6bf36a44b5e9b4a6e61c5e3f42dbd4aeb2f60c
5
5
  SHA512:
6
- metadata.gz: 227c788ef4eab62cb0458ce01d21d31e392f17d5b5eba966d9269cd14d2e8a669d5d9df99d9afad7da4c08525f10729768a13a45ee22e6d5ed30f7af68db2da1
7
- data.tar.gz: 8de84d61c1823fddc13d53ce579e5838289675c7e3f8cac392ab9ea479bdc25b16dd7d79a445e0f956be1ecb94f035ca97e074b1a4e530bf45f55c6aa33682bb
6
+ metadata.gz: 201e862b74b02896c79356d61ee4128ae31b35d7ebbd2e2548d028d0fe2294389bcb5b699fdf0e0e70630db19cc21b8f45c535ada00f3ab2bda9111f90c409aa
7
+ data.tar.gz: 1c16363476186d8d54f0d2c229f805f962af5afd43eb3cd4de8c7cc954c858b85c08612289d6fc621843124f23280d6c0e9af2d97c8d81a6c0a35ff58f197ca1
@@ -1,41 +1,22 @@
1
1
  module SemanticRange
2
2
  class Comparator
3
+ attr_reader :semver, :operator, :value
3
4
  def initialize(comp, loose)
4
- @loose = loose
5
-
6
5
  if comp.is_a?(Comparator)
7
- if comp.loose == loose
8
- return comp
9
- else
10
- @comp = comp.value
11
- end
6
+ return comp if comp.loose == loose
7
+ @comp = comp.value
12
8
  end
13
9
 
10
+ @loose = loose
14
11
  parse(comp)
15
12
 
16
- if @semver == ANY
17
- @value = ''
18
- else
19
- @value = @operator + @semver.version
20
- end
21
- end
22
-
23
- def semver
24
- @semver
25
- end
26
-
27
- def operator
28
- @operator
13
+ @value = @semver == ANY ? '' : @operator + @semver.version
29
14
  end
30
15
 
31
16
  def to_s
32
17
  @value
33
18
  end
34
19
 
35
- def value
36
- @value
37
- end
38
-
39
20
  def test(version)
40
21
  return true if @semver == ANY
41
22
  version = Version.new(version, @loose) if version.is_a?(String)
@@ -44,16 +25,12 @@ module SemanticRange
44
25
 
45
26
  def parse(comp)
46
27
  m = comp.match(@loose ? COMPARATORLOOSE : COMPARATOR)
47
- raise 'Invalid comparator: ' + comp unless m
28
+ raise "Invalid comparator: #{comp}" unless m
48
29
 
49
30
  @operator = m[1]
50
31
  @operator = '' if @operator == '='
51
32
 
52
- if !m[2]
53
- @semver = ANY
54
- else
55
- @semver = Version.new(m[2], @loose)
56
- end
33
+ @semver = !m[2] ? ANY : Version.new(m[2], @loose)
57
34
  end
58
35
  end
59
36
  end
@@ -0,0 +1,64 @@
1
+ module SemanticRange
2
+ class PreRelease
3
+ attr_reader :parts
4
+
5
+ def initialize(input)
6
+ @parts = parse(input)
7
+ end
8
+
9
+ def parse(str)
10
+ str.to_s.split('.').map { |id| convert(id) }
11
+ end
12
+
13
+ def convert(str)
14
+ str.match(/^[0-9]+$/) ? str.to_i : str
15
+ end
16
+
17
+ def length
18
+ parts.length
19
+ end
20
+
21
+ def empty?
22
+ parts.empty?
23
+ end
24
+
25
+ def to_s
26
+ parts.join '.'
27
+ end
28
+
29
+ def clear!
30
+ @parts = []
31
+ end
32
+
33
+ def zero!
34
+ @parts = [0]
35
+ end
36
+
37
+ def <=>(other)
38
+ return unless other.is_a?(self.class)
39
+
40
+ return -1 if parts.any? && !other.parts.any?
41
+ return 1 if !parts.any? && other.parts.any?
42
+ return 0 if !parts.any? && !other.parts.any?
43
+
44
+ i = 0
45
+ while true
46
+ a = parts[i]
47
+ b = other.parts[i]
48
+
49
+ if a.nil? && b.nil?
50
+ return 0
51
+ elsif b.nil?
52
+ return 1
53
+ elsif a.nil?
54
+ return -1
55
+ elsif a == b
56
+
57
+ else
58
+ return Version.compare_identifiers(a, b)
59
+ end
60
+ i += 1
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,5 +1,7 @@
1
1
  module SemanticRange
2
2
  class Range
3
+ attr_reader :loose, :raw, :range, :set
4
+
3
5
  def initialize(range, loose)
4
6
  range = range.raw if range.is_a?(Range)
5
7
 
@@ -8,27 +10,13 @@ module SemanticRange
8
10
  split = range.split(/\s*\|\|\s*/)
9
11
  split = ['', ''] if range == '||'
10
12
  split = [''] if split == []
11
- @set = split.map do |range|
12
- parse_range(range.strip)
13
- end
13
+ @set = split.map {|range| parse_range(range.strip) }
14
14
 
15
- raise 'Invalid SemVer Range: ' + range if @set.empty?
15
+ raise 'Invalid SemVer Range: ' + range if @set.empty? || @set == [[]]
16
16
 
17
17
  format
18
18
  end
19
19
 
20
- def loose
21
- @loose
22
- end
23
-
24
- def raw
25
- @raw
26
- end
27
-
28
- def range
29
- @range
30
- end
31
-
32
20
  def format
33
21
  @range = @set.map do |comps|
34
22
  comps.join(' ').strip
@@ -36,23 +24,14 @@ module SemanticRange
36
24
  @range
37
25
  end
38
26
 
39
- def set
40
- @set
41
- end
42
-
43
27
  def test(version)
44
28
  return false if !version
45
29
  version = Version.new(version, @loose) if version.is_a?(String)
46
- @set.each do |s|
47
- return true if test_set(s, version)
48
- end
49
- false
30
+ @set.any?{|s| test_set(s, version) }
50
31
  end
51
32
 
52
33
  def test_set(set, version)
53
- set.each do |comp|
54
- return false if !comp.test(version)
55
- end
34
+ return false if set.any? {|comp| !comp.test(version) }
56
35
  if version.prerelease.length > 0
57
36
  set.each do |comp|
58
37
  next if comp.semver == ANY
@@ -119,14 +98,14 @@ module SemanticRange
119
98
  pr = match[4]
120
99
 
121
100
  if isX(mj)
122
- ret = ''
101
+ ''
123
102
  elsif isX(m)
124
- ret = ">=#{mj}.0.0 <#{(mj.to_i + 1)}.0.0"
103
+ ">=#{mj}.0.0 <#{(mj.to_i + 1)}.0.0"
125
104
  elsif isX(p)
126
105
  if mj == '0'
127
- ret = ">=#{mj}.#{m}.0 <#{mj}.#{(m.to_i + 1)}.0"
106
+ ">=#{mj}.#{m}.0 <#{mj}.#{(m.to_i + 1)}.0"
128
107
  else
129
- ret = ">=#{mj}.#{m}.0 <#{(mj.to_i + 1)}.0.0"
108
+ ">=#{mj}.#{m}.0 <#{(mj.to_i + 1)}.0.0"
130
109
  end
131
110
  elsif pr
132
111
  if pr[0] != '-'
@@ -134,25 +113,24 @@ module SemanticRange
134
113
  end
135
114
  if mj == '0'
136
115
  if m == '0'
137
- ret = ">=#{mj}.#{m}.#{p}#{pr} <#{mj}.#{m}.#{(p.to_i + 1)}"
116
+ ">=#{mj}.#{m}.#{p}#{pr} <#{mj}.#{m}.#{(p.to_i + 1)}"
138
117
  else
139
- ret = ">=#{mj}.#{m}.#{p}#{pr} <#{mj}.#{(m.to_i + 1)}.0"
118
+ ">=#{mj}.#{m}.#{p}#{pr} <#{mj}.#{(m.to_i + 1)}.0"
140
119
  end
141
120
  else
142
- ret = ">=#{mj}.#{m}.#{p}#{pr} <#{(mj.to_i + 1)}.0.0"
121
+ ">=#{mj}.#{m}.#{p}#{pr} <#{(mj.to_i + 1)}.0.0"
143
122
  end
144
123
  else
145
124
  if mj == '0'
146
125
  if m == '0'
147
- ret = ">=#{mj}.#{m}.#{p} <#{mj}.#{m}.#{(p.to_i + 1)}"
126
+ ">=#{mj}.#{m}.#{p} <#{mj}.#{m}.#{(p.to_i + 1)}"
148
127
  else
149
- ret = ">=#{mj}.#{m}.#{p} <#{mj}.#{(m.to_i + 1)}.0"
128
+ ">=#{mj}.#{m}.#{p} <#{mj}.#{(m.to_i + 1)}.0"
150
129
  end
151
130
  else
152
- ret = ">=#{mj}.#{m}.#{p} <#{(mj.to_i + 1)}.0.0"
131
+ ">=#{mj}.#{m}.#{p} <#{(mj.to_i + 1)}.0.0"
153
132
  end
154
133
  end
155
- ret
156
134
  end
157
135
  end
158
136
 
@@ -171,18 +149,17 @@ module SemanticRange
171
149
  pr = match[4]
172
150
 
173
151
  if isX(mj)
174
- ret = ''
152
+ ''
175
153
  elsif isX(m)
176
- ret = ">=#{mj}.0.0 <#{(mj.to_i + 1)}.0.0"
154
+ ">=#{mj}.0.0 <#{(mj.to_i + 1)}.0.0"
177
155
  elsif isX(p)
178
- ret = ">=#{mj}.#{m}.0 <#{mj}.#{(m.to_i + 1)}.0"
156
+ ">=#{mj}.#{m}.0 <#{mj}.#{(m.to_i + 1)}.0"
179
157
  elsif pr
180
158
  pr = '-' + pr if (pr[0] != '-')
181
- ret = ">=#{mj}.#{m}.#{p}#{pr} <#{mj}.#{(m.to_i + 1)}.0"
159
+ ">=#{mj}.#{m}.#{p}#{pr} <#{mj}.#{(m.to_i + 1)}.0"
182
160
  else
183
- ret = ">=#{mj}.#{m}.#{p} <#{mj}.#{(m.to_i + 1)}.0"
161
+ ">=#{mj}.#{m}.#{p} <#{mj}.#{(m.to_i + 1)}.0"
184
162
  end
185
- ret
186
163
  end
187
164
  end
188
165
 
@@ -212,9 +189,9 @@ module SemanticRange
212
189
 
213
190
  if xM
214
191
  if gtlt == '>' || gtlt == '<'
215
- ret = '<0.0.0'
192
+ '<0.0.0'
216
193
  else
217
- ret = '*'
194
+ '*'
218
195
  end
219
196
  elsif !gtlt.nil? && gtlt != '' && anyX
220
197
  m = 0 if xm
@@ -239,14 +216,14 @@ module SemanticRange
239
216
  end
240
217
  end
241
218
 
242
- ret = "#{gtlt}#{mj}.#{m}.#{p}"
219
+ "#{gtlt}#{mj}.#{m}.#{p}"
243
220
  elsif xm
244
- ret = ">=#{mj}.0.0 <#{(mj.to_i + 1)}.0.0"
221
+ ">=#{mj}.0.0 <#{(mj.to_i + 1)}.0.0"
245
222
  elsif xp
246
- ret = ">=#{mj}.#{m}.0 <#{mj}.#{(m.to_i + 1)}.0"
223
+ ">=#{mj}.#{m}.0 <#{mj}.#{(m.to_i + 1)}.0"
224
+ else
225
+ ret
247
226
  end
248
-
249
- ret
250
227
  end
251
228
  end
252
229
 
@@ -1,77 +1,45 @@
1
1
  module SemanticRange
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
 
4
4
  class Version
5
- def initialize(version, loose)
5
+ attr_reader :major, :minor, :patch, :prerelease
6
+
7
+ def initialize(version, loose = false)
6
8
  @raw = version
7
9
  @loose = loose
8
10
 
9
- if version.is_a?(Version)
10
- @raw = version = version.raw
11
- end
11
+ @raw = version.raw if version.is_a?(Version)
12
12
 
13
- match = version.strip.match(loose ? LOOSE : FULL)
14
- # TODO error handling
13
+ match = @raw.strip.match(loose ? LOOSE : FULL)
14
+
15
+ raise NoMatchFound.new(version) if match.nil?
15
16
 
16
17
  @major = match[1] ? match[1].to_i : 0
17
18
  @minor = match[2] ? match[2].to_i : 0
18
19
  @patch = match[3] ? match[3].to_i : 0
19
20
 
20
- # TODO error handling
21
-
22
- if !match[4]
23
- @prerelease = []
24
- else
25
- @prerelease = match[4].split('.').map do |id|
26
- if /^[0-9]+$/.match(id)
27
- num = id.to_i
28
- # TODO error handling
29
- else
30
- id
31
- end
32
- end
33
- end
21
+ @prerelease = PreRelease.new match[4]
34
22
 
35
23
  @build = match[5] ? match[5].split('.') : []
36
- @version = format
37
- end
38
-
39
- def version
40
- @version
41
- end
42
-
43
- def raw
44
- @raw
45
- end
46
-
47
- def major
48
- @major
49
- end
50
-
51
- def minor
52
- @minor
53
- end
54
-
55
- def patch
56
- @patch
57
- end
58
-
59
- def prerelease
60
- @prerelease
61
24
  end
62
25
 
63
26
  def format
64
27
  v = "#{@major}.#{@minor}.#{@patch}"
65
- if @prerelease.length > 0
66
- v += '-' + @prerelease.join('.')
67
- end
68
- v
28
+ prerelease.length > 0 ? "#{v}-#{prerelease}" : v
69
29
  end
70
30
 
71
31
  def to_s
72
32
  @version
73
33
  end
74
34
 
35
+ def version
36
+ format
37
+ end
38
+
39
+ def raw
40
+ version
41
+ end
42
+
75
43
  def compare(other)
76
44
  other = Version.new(other, @loose) unless other.is_a?(Version)
77
45
  res = truthy(compare_main(other)) || truthy(compare_pre(other))
@@ -80,7 +48,9 @@ module SemanticRange
80
48
 
81
49
  def compare_main(other)
82
50
  other = Version.new(other, @loose) unless other.is_a?(Version)
83
- truthy(compare_identifiers(@major, other.major)) || truthy(compare_identifiers(@minor, other.minor)) || truthy(compare_identifiers(@patch, other.patch))
51
+ truthy(self.class.compare_identifiers(@major, other.major)) ||
52
+ truthy(self.class.compare_identifiers(@minor, other.minor)) ||
53
+ truthy(self.class.compare_identifiers(@patch, other.patch))
84
54
  end
85
55
 
86
56
  def truthy(val)
@@ -89,35 +59,10 @@ module SemanticRange
89
59
  end
90
60
 
91
61
  def compare_pre(other)
92
- other = Version.new(other, @loose) unless other.is_a?(Version)
93
-
94
- return -1 if truthy(@prerelease.length) && !truthy(other.prerelease.length)
95
-
96
- return 1 if !truthy(@prerelease.length) && truthy(other.prerelease.length)
97
-
98
- return 0 if !truthy(@prerelease.length) && !truthy(other.prerelease.length)
99
-
100
- i = 0
101
- while true
102
- a = @prerelease[i]
103
- b = other.prerelease[i]
104
-
105
- if a.nil? && b.nil?
106
- return 0
107
- elsif b.nil?
108
- return 1
109
- elsif a.nil?
110
- return -1
111
- elsif a == b
112
-
113
- else
114
- return compare_identifiers(a, b)
115
- end
116
- i += 1
117
- end
62
+ prerelease <=> other.prerelease
118
63
  end
119
64
 
120
- def compare_identifiers(a,b)
65
+ def self.compare_identifiers(a,b)
121
66
  anum = /^[0-9]+$/.match(a.to_s)
122
67
  bnum = /^[0-9]+$/.match(b.to_s)
123
68
 
@@ -132,5 +77,103 @@ module SemanticRange
132
77
  a > b ? 1 :
133
78
  0;
134
79
  end
80
+
81
+ def increment!(release, identifier)
82
+ case release
83
+ when 'premajor'
84
+ @prerelease.clear!
85
+ @patch = 0
86
+ @minor = 0
87
+ @major = @major + 1
88
+ increment! 'pre', identifier
89
+ when 'preminor'
90
+ @prerelease.clear!
91
+ @patch = 0
92
+ @minor = @minor + 1
93
+ increment! 'pre', identifier
94
+ when 'prepatch'
95
+ # If this is already a prerelease, it will bump to the next version
96
+ # drop any prereleases that might already exist, since they are not
97
+ # relevant at this point.
98
+ @prerelease.clear!
99
+ increment! 'patch', identifier
100
+ increment! 'pre', identifier
101
+
102
+ # If the input is a non-prerelease version, this acts the same as
103
+ # prepatch.
104
+ when 'prerelease'
105
+ if @prerelease.empty?
106
+ increment! 'patch', identifier
107
+ end
108
+ increment! 'pre', identifier
109
+ when 'major'
110
+ # If this is a pre-major version, bump up to the same major version.
111
+ # Otherwise increment major.
112
+ # 1.0.0-5 bumps to 1.0.0
113
+ # 1.1.0 bumps to 2.0.0
114
+ if @minor != 0 || @patch != 0 || @prerelease.empty?
115
+ @major = @major + 1
116
+ end
117
+ @minor = 0
118
+ @patch = 0
119
+ @prerelease.clear!
120
+ when 'minor'
121
+ # If this is a pre-minor version, bump up to the same minor version.
122
+ # Otherwise increment minor.
123
+ # 1.2.0-5 bumps to 1.2.0
124
+ # 1.2.1 bumps to 1.3.0
125
+ if @patch != 0 || @prerelease.empty?
126
+ @minor = @minor + 1
127
+ end
128
+ @patch = 0
129
+ @prerelease.clear!
130
+ when 'patch'
131
+ # If this is not a pre-release version, it will increment the patch.
132
+ # If it is a pre-release it will bump up to the same patch version.
133
+ # 1.2.0-5 patches to 1.2.0
134
+ # 1.2.0 patches to 1.2.1
135
+ if @prerelease.empty?
136
+ @patch = @patch + 1
137
+ end
138
+ @prerelease.clear!
139
+
140
+ # This probably shouldn't be used publicly.
141
+ # 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
142
+ when 'pre'
143
+ if @prerelease.empty?
144
+ @prerelease.zero!
145
+ else
146
+ parts = @prerelease.parts
147
+ i = parts.length
148
+ while i >= 0
149
+ if parts[i].is_a?(Fixnum)
150
+ parts[i] += 1
151
+ i = -2
152
+ else
153
+ i = i-1
154
+ end
155
+ end
156
+ if i == -1 # didn't increment anything
157
+ parts << 0
158
+ end
159
+ @prerelease = PreRelease.new(parts.join("."))
160
+ end
161
+ if identifier
162
+ # 1.2.0-beta.1 bumps to 1.2.0-beta.2,
163
+ # 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
164
+ if @prerelease.parts[0] == identifier
165
+ unless @prerelease.parts[1].kind_of?(Fixnum)
166
+ @prerelease = PreRelease.new([identifier, 0].join('.'))
167
+ end
168
+ else
169
+ @prerelease = PreRelease.new([identifier, 0].join('.'))
170
+ end
171
+ end
172
+ else
173
+ raise InvalidIncrement.new release
174
+ end
175
+
176
+ self
177
+ end
135
178
  end
136
179
  end
@@ -1,4 +1,5 @@
1
1
  require "semantic_range/version"
2
+ require "semantic_range/pre_release"
2
3
  require "semantic_range/range"
3
4
  require "semantic_range/comparator"
4
5
 
@@ -44,6 +45,9 @@ module SemanticRange
44
45
 
45
46
  MAX_LENGTH = 256
46
47
 
48
+ class InvalidIncrement < StandardError; end
49
+ class NoMatchFound < StandardError; end
50
+
47
51
  def self.ltr(version, range, loose = false)
48
52
  outside(version, range, '<', loose)
49
53
  end
@@ -143,6 +147,7 @@ module SemanticRange
143
147
  end
144
148
 
145
149
  def self.satisfies(version, range, loose = false)
150
+ return false if !valid_range(range, loose)
146
151
  Range.new(range, loose).test(version)
147
152
  end
148
153
 
@@ -232,4 +237,26 @@ module SemanticRange
232
237
  nil
233
238
  end
234
239
  end
240
+
241
+ def self.increment!(version, release, loose, identifier)
242
+ if loose.is_a? String
243
+ identifier = loose
244
+ loose = false
245
+ end
246
+
247
+ Version.new(version, loose).increment!(release, identifier).version
248
+ rescue InvalidIncrement, NoMatchFound
249
+ nil
250
+ end
251
+
252
+ def self.diff(a, b)
253
+ a = Version.new(a, false) unless a.kind_of?(Version)
254
+ b = Version.new(b, false) unless b.kind_of?(Version)
255
+ pre_diff = a.prerelease.to_s != b.prerelease.to_s
256
+ pre = pre_diff ? 'pre' : ''
257
+ return "#{pre}major" if a.major != b.major
258
+ return "#{pre}minor" if a.minor != b.minor
259
+ return "#{pre}patch" if a.patch != b.patch
260
+ return "prerelease" if pre_diff
261
+ end
235
262
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semantic_range
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-11-13 00:00:00.000000000 Z
11
+ date: 2015-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -72,6 +72,7 @@ files:
72
72
  - bin/setup
73
73
  - lib/semantic_range.rb
74
74
  - lib/semantic_range/comparator.rb
75
+ - lib/semantic_range/pre_release.rb
75
76
  - lib/semantic_range/range.rb
76
77
  - lib/semantic_range/version.rb
77
78
  - semantic_range.gemspec