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.
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: []