sem_version 1.0.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/lib/sem_version.rb +153 -0
- metadata +46 -0
data/lib/sem_version.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
class SemVersion
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
VERSION = '1.0.0'
|
5
|
+
# Pattern allows min and patch to be skipped. We have to do extra checking if we want them
|
6
|
+
SEMVER_REGEX = /^(\d+)(?:\.(\d+)(?:\.(\d+)(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?)?)?$/
|
7
|
+
|
8
|
+
attr_reader :major, :minor, :patch, :pre, :build
|
9
|
+
alias_method :prerelease, :pre
|
10
|
+
|
11
|
+
# Format were raw bits are passed in is undocumented, and not validity checked
|
12
|
+
def initialize(string, *args)
|
13
|
+
if args.empty?
|
14
|
+
@major, @minor, @patch, @pre, @build = self.class.parse(string)
|
15
|
+
else
|
16
|
+
@major, @minor, @patch, @pre, @build = [string, *args]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.parse(string)
|
21
|
+
match = string.match(SEMVER_REGEX)
|
22
|
+
raise ArgumentError, "Version string #{string} is not valid" unless match
|
23
|
+
maj, min, pat, pre, bui = match.captures
|
24
|
+
raise ArgumentError, "Version string #{string} is not valid" if min.empty? || pat.empty?
|
25
|
+
[maj.to_i, min.to_i, pat.to_i, pre, bui]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.from_loose_version(string)
|
29
|
+
match = string.match(SEMVER_REGEX)
|
30
|
+
raise ArgumentError, "Version string #{string} is not valid" unless match
|
31
|
+
maj, min, pat, pre, bui = match.captures
|
32
|
+
min = 0 if min.nil? || min.empty?
|
33
|
+
pat = 0 if pat.nil? || pat.empty?
|
34
|
+
new(maj.to_i, min.to_i, pat.to_i, pre, bui)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.valid?(string)
|
38
|
+
matches = string.match(SEMVER_REGEX)
|
39
|
+
matches && !matches[2].nil? && !matches[3].nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
def <=>(other)
|
43
|
+
maj = @major <=> other.major
|
44
|
+
return maj unless maj == 0
|
45
|
+
|
46
|
+
min = @minor <=> other.minor
|
47
|
+
return min unless min == 0
|
48
|
+
|
49
|
+
pat = @patch <=> other.patch
|
50
|
+
return pat unless pat == 0
|
51
|
+
|
52
|
+
pre = compare_sep(@pre, other.pre, true)
|
53
|
+
return pre unless pre == 0
|
54
|
+
|
55
|
+
bui = compare_sep(@build, other.build, false)
|
56
|
+
return bui unless bui == 0
|
57
|
+
|
58
|
+
0
|
59
|
+
end
|
60
|
+
|
61
|
+
def satisfies?(constraint)
|
62
|
+
comparison, version = constraint.strip.split(' ', 2)
|
63
|
+
# Allow pessimistic operator
|
64
|
+
if comparison == '~>'
|
65
|
+
match = version.match(/^(\d+)\.(\d+)\.?(\d*)$/)
|
66
|
+
raise ArgumentError, "Pessimistic constraints must have a version in the form 'x.y' or 'x.y.z'" unless match
|
67
|
+
maj, min, pat = match.captures
|
68
|
+
if pat.empty?
|
69
|
+
lower = "#{maj}.#{min}.0"
|
70
|
+
upper = "#{maj.to_i+1}.0.0"
|
71
|
+
else
|
72
|
+
lower = "#{maj}.#{min}.#{pat}"
|
73
|
+
upper = "#{maj}.#{min.to_i+1}.0"
|
74
|
+
end
|
75
|
+
|
76
|
+
send('>=', SemVersion.new(lower)) && send('<', SemVersion.new(upper))
|
77
|
+
else
|
78
|
+
# Allow '1.0.2' as '== 1.0.2'
|
79
|
+
version, comparison = comparison, '==' if version.nil?
|
80
|
+
# Allow '= 1.0.2' as '== 1.0.2'
|
81
|
+
comparison = '==' if comparison == '='
|
82
|
+
|
83
|
+
semversion = self.class.from_loose_version(version)
|
84
|
+
|
85
|
+
send(comparison, semversion)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def major=(val)
|
90
|
+
raise ArgumentError, "#{val} is not a valid major version (must be an integer >= 0)" unless val.is_a?(Fixnum) && val >= 0
|
91
|
+
@major = val
|
92
|
+
end
|
93
|
+
|
94
|
+
def minor=(val)
|
95
|
+
raise ArgumentError, "#{val} is not a valid minor version (must be an integer >= 0)" unless val.is_a?(Fixnum) && val >= 0
|
96
|
+
@minor = val
|
97
|
+
end
|
98
|
+
|
99
|
+
def patch=(val)
|
100
|
+
raise ArgumentError, "#{val} is not a valid patch version (must be an integer >= 0)" unless val.is_a?(Fixnum) && val >= 0
|
101
|
+
@patch = val
|
102
|
+
end
|
103
|
+
|
104
|
+
def pre=(val)
|
105
|
+
if !val.is_a?(String) || val !~ /^[\dA-Za-z\-]+(\.[\dA-Za-z\-]+)*$/
|
106
|
+
raise ArgumentError, "#{val} is not a valid pre-release version (must be a string following http://semver.org constraints)"
|
107
|
+
end
|
108
|
+
@pre = val
|
109
|
+
end
|
110
|
+
alias_method :prerelease=, :pre=
|
111
|
+
|
112
|
+
def build=(val)
|
113
|
+
if !val.is_a?(String) || val !~ /^[\dA-Za-z\-]+(\.[\dA-Za-z\-]+)*$/
|
114
|
+
raise ArgumentError, "#{val} is not a valid pbuild version (must be a string following http://semver.org constraints)"
|
115
|
+
end
|
116
|
+
@build = val
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
def to_s
|
121
|
+
r = "#{@major}.#{@minor}.#{patch}"
|
122
|
+
r << "-#{@pre}" if @pre
|
123
|
+
r << "+#{@build}" if @build
|
124
|
+
r
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def compare_sep(ours, theirs, nil_wins)
|
130
|
+
# Both nil? They're equal
|
131
|
+
return 0 if ours.nil? && theirs.nil?
|
132
|
+
# One's nil? The winner is determined by precidence
|
133
|
+
return nil_wins ? -1 : 1 if theirs.nil?
|
134
|
+
return nil_wins ? 1 : -1 if ours.nil?
|
135
|
+
|
136
|
+
our_parts = ours.split('.')
|
137
|
+
their_parts = theirs.split('.')
|
138
|
+
|
139
|
+
our_parts.zip(their_parts) do |a,b|
|
140
|
+
# b can be nil, in which case it loses
|
141
|
+
return 1 if b.nil?
|
142
|
+
# If they're both ints, convert to as such
|
143
|
+
# If one's an int and the other isn't, the string version of the int gets correctly compared
|
144
|
+
a, b = a.to_i, b.to_i if a =~ /^\d+$/ && b =~ /^\d+$/
|
145
|
+
|
146
|
+
comp = a <=> b
|
147
|
+
return comp unless comp == 0
|
148
|
+
end
|
149
|
+
|
150
|
+
# If we got this far, either they're equal (same length) or they won
|
151
|
+
return (our_parts.length == their_parts.length) ? 0 : -1
|
152
|
+
end
|
153
|
+
end
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sem_version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Antony Male
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-06 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Allows you to parse and compare semantic versions, as specified by http://semver.org/.
|
15
|
+
Allows constraint checking e.g. >=, <, ~>
|
16
|
+
email: antony dot mail at gmail
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/sem_version.rb
|
22
|
+
homepage: https://github.com/canton7/sem_version
|
23
|
+
licenses: []
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.9.2
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 1.8.23
|
43
|
+
signing_key:
|
44
|
+
specification_version: 3
|
45
|
+
summary: ! 'SemVersion: Semantic version parsing and comparison. See http://semver.org/'
|
46
|
+
test_files: []
|