sem_version 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/sem_version.rb +153 -0
  2. metadata +46 -0
@@ -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: []