sem_version 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (C) 2012 Antony Male
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,146 @@
1
+ SemVersion
2
+ ==========
3
+
4
+ SemVersion is a gem to help parse, validate, modify, and compare [Semantic Versions](http://semver.org).
5
+
6
+ Parsing
7
+ -------
8
+
9
+ Parsing is easy:
10
+
11
+ ```ruby
12
+ v = SemVersion.new('1.2.3-pre.4+build.5')
13
+
14
+ v.major # => 1
15
+ v.minor # => 2
16
+ v.patch # => 3
17
+
18
+ v.pre # => 'pre.4'
19
+ v.prerelease # => 'pre.4'
20
+ v.build # => 'build.5'
21
+
22
+ v.to_s # => '1.2.3-pre.4+build.5'
23
+ ```
24
+
25
+ You can pass any valid semantic version string, as specified by [Semantic Versions](http://semver.org).
26
+ Invalid versions will raise an ArgumentError.
27
+
28
+ You can also create a new SemVersion from an array or a hash, and serialise back to arrays and hashes.
29
+
30
+ ```ruby
31
+ v1 = SemVersion.new([1, 2, 3, 'pre.4', 'build.5'])
32
+ v1.to_s # => '1.2.3-pre.4+build.5'
33
+ v1.to_a # => [1, 2, 3, 'pre.4', 'build.5']
34
+
35
+ v2 = SemVersion.new(1, 2, 3, nil, 'build.5')
36
+ v2.to_s # => '1.2.3+build.5'
37
+ v2.to_a # => [1, 2, 3, nil, 'build.5']
38
+
39
+ v3 = SemVersion.new(:major => 1, :minor => 2, :patch => 3, :pre => 'pre.4', :build => 'build.5')
40
+ v.to_s # => '1.2.3-pre.4+build.5'
41
+ v.to_h # => {:major => 1, :minor => 2, :patch => 3, :pre => 'pre.4', :build => 'build.5'}
42
+
43
+ v4 = SemVersion.new(:major => 1, :minor => 2, :patch => 3, :build => 'build.6')
44
+ v4.to_h # => {:major => 1, :minor => 2, :patch => 3, :build => 'build.6'}
45
+ ```
46
+
47
+ You can also use `SemVersion()` as an alias for `SemVersion.new()`.
48
+
49
+
50
+ Validating
51
+ ----------
52
+
53
+ Validating is easier:
54
+
55
+ ```ruby
56
+ SemVersion.valid?('1.2.3') # => true
57
+ SemVersion.valid?('1.2') # => false
58
+ SemVersion.valid?('1.2.3-pre.1') # => true
59
+ SemVersion.valid?('1.2.3-pre.!') # => false
60
+ ```
61
+
62
+ And so on...
63
+
64
+ Modifying
65
+ ---------
66
+
67
+ You can modify any part of a parsed version.
68
+ Invalid new values will raise an ArgumentError
69
+
70
+ ```ruby
71
+ v = SemVersion.new('1.2.3')
72
+ v.major = 3
73
+ v.minor = 5
74
+ v.pre = 'pre.2'
75
+ v.build = 'build.x.7'
76
+
77
+ v.to_s # => '3.5.1-pre.2+build.x.7'
78
+
79
+ v.major = -1 # => ArgumentError
80
+ v.major = 'a' # => ArgumentError
81
+ v.pre = 'a.!' # => ArgumentError
82
+ v.pre = '.a' # => ArgumentError
83
+ ```
84
+
85
+ Comparing
86
+ ---------
87
+
88
+ You can compare semantic versions using `<`, `>`, `<=`, `>=`, `==`, and `<=>`
89
+
90
+ ```ruby
91
+ SemVersion.new('1.2.3') < SemVersion.new('1.2.2') # => true
92
+ SemVersion.new('1.2.3-pre.1') <= SemVersion.new('1.2.3-pre') # => false
93
+ SemVersion.new('1.2.3+build.11') > SemVersion.new('1.2.3+build.2') # => true
94
+ ```
95
+
96
+ Satisfying constraints
97
+ ----------------------
98
+
99
+ You can see whether a semantic version satisfies a particular constraint.
100
+ Constraints are in the form `"<comparison> <version>"`, e.g. ">= 1.2.2", "= 1.3", or "~> 1.2".
101
+
102
+ When using the pessimistic operation, `~>`, versions may be specified in the form `"x.y"` or `"x.y.z"` (with `"~> x.y"` meaning `">= x.y.0" && "< x+1.0.0"`, and `"~> x.y.z"` meaning `">= x.y.z" && "< x.y+1.0"`).
103
+
104
+ When using the other operations, versions may be in the form `"x"`, `"x.y"`, or a full semantic version (including optional pre-release and build).
105
+ In the former two cases, the missing versions out of minor and patch will be filled in with 0's, and the pre-release and build ignored.
106
+
107
+ ```ruby
108
+ SemVersion.new('1.2.3').satisfies?('>= 1.2') # => true
109
+ SemVersion.new('1.2.3-pre.1').satisfies?('>= 1.2.3') # => false
110
+ SemVersion.new('0.1.0').satisfies?('> 0') # => true
111
+ SemVersion.new('2.3.0').satisfies?('~> 2.2') # => true
112
+ ```
113
+
114
+ You can also see whether a given constraint is 'open' (allows a range of versions), or 'closed' (allows only one version).
115
+
116
+ For example:
117
+
118
+ ```ruby
119
+ SemVersion.open_constraint?('1.2.3') # => false
120
+ SemVersion.open_constraint?('= 1.2.3') # => false
121
+ SemVersion.open_constraint?('== 1.2.3') # => false
122
+ SemVersion.open_constraint?('<= 1.2.3') # => true
123
+ SemVersion.open_constraint?('~> 1.2.3') # => true
124
+ ```
125
+
126
+ It's also possible to split a constraint into its comparison and version.
127
+ If the comparison is not given, or is '==', it is normalised to '='.
128
+
129
+ ```ruby
130
+ SemVersion.split_constraint('1.2.3') # => ['=', '1.2.3']
131
+ SemVersion.split_constraint('= 1.2.3') # => ['=', '1.2.3']
132
+ SemVersion.split_constraint('== 1.2.3') # => ['=', '1.2.3']
133
+ SemVersion.split_constraint('> 1.2.3') # => ['>', '1.2.3']
134
+ ```
135
+
136
+ Core Extensions
137
+ ===============
138
+
139
+ You can also load a set of core extensions using an optional require.
140
+
141
+ ```ruby
142
+ require 'sem_version'
143
+ require 'sem_version/core_ext'
144
+
145
+ "1.2.3+pre.4-build.5".to_version
146
+ ```
@@ -0,0 +1,8 @@
1
+ # Just make sure sem_version has been required
2
+ require 'sem_version'
3
+
4
+ class String
5
+ def to_version
6
+ SemVersion.new(self)
7
+ end
8
+ end
data/lib/sem_version.rb CHANGED
@@ -1,19 +1,32 @@
1
1
  class SemVersion
2
2
  include Comparable
3
3
 
4
- VERSION = '1.2.0'
4
+ VERSION = '1.3.0'
5
+
5
6
  # Pattern allows min and patch to be skipped. We have to do extra checking if we want them
6
7
  SEMVER_REGEX = /^(\d+)(?:\.(\d+)(?:\.(\d+)(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?(?:\+([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?)?)?$/
8
+ PRE_BUILD_REGEX = /^[\dA-Za-z\-]+(\.[\dA-Za-z\-]+)*$/
7
9
 
8
10
  attr_reader :major, :minor, :patch, :pre, :build
9
11
  alias_method :prerelease, :pre
10
12
 
11
13
  # 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)
14
+ def initialize(*args)
15
+ if args.first.is_a?(String)
16
+ @major, @minor, @patch, @pre, @build = self.class.parse(args.first)
17
+ # Validation should be handled at a string level by self.parse, but validate anyway
18
+ validate
19
+ elsif args.first.is_a?(Hash)
20
+ @major, @minor, @patch, @pre, @build = args.first.values_at(:major, :minor, :patch, :pre, :build)
21
+ # Allow :prerelease as well
22
+ @pre ||= args.first[:prerelease]
23
+ validate
24
+ elsif args.first.is_a?(Array)
25
+ @major, @minor, @patch, @pre, @build = *args.first
26
+ validate
15
27
  else
16
- @major, @minor, @patch, @pre, @build = [string, *args]
28
+ @major, @minor, @patch, @pre, @build = *args
29
+ validate
17
30
  end
18
31
  end
19
32
 
@@ -59,7 +72,7 @@ class SemVersion
59
72
  end
60
73
 
61
74
  def satisfies?(constraint)
62
- comparison, version = constraint.strip.split(' ', 2)
75
+ comparison, version = self.class.split_constraint(constraint)
63
76
  # Allow pessimistic operator
64
77
  if comparison == '~>'
65
78
  match = version.match(/^(\d+)\.(\d+)\.?(\d*)$/)
@@ -73,22 +86,17 @@ class SemVersion
73
86
  upper = "#{maj}.#{min.to_i+1}.0"
74
87
  end
75
88
 
76
- send('>=', SemVersion.new(lower)) && send('<', SemVersion.new(upper))
89
+ send('>=', SemVersion.new(lower)) && send('<', SemVersion.new(upper))
77
90
  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
91
  comparison = '==' if comparison == '='
82
-
83
92
  semversion = self.class.from_loose_version(version)
84
-
85
93
  send(comparison, semversion)
86
94
  end
87
95
  end
88
96
 
89
97
  def self.open_constraint?(constraint)
90
- comparison, version = constraint.strip.split(' ', 2)
91
- !['=', '=='].include?(comparison) && !version.nil?
98
+ comparison, _ = self.split_constraint(constraint)
99
+ comparison != '='
92
100
  end
93
101
 
94
102
  def self.split_constraint(constraint)
@@ -114,30 +122,42 @@ class SemVersion
114
122
  end
115
123
 
116
124
  def pre=(val)
117
- if !val.is_a?(String) || val !~ /^[\dA-Za-z\-]+(\.[\dA-Za-z\-]+)*$/
118
- raise ArgumentError, "#{val} is not a valid pre-release version (must be a string following http://semver.org constraints)"
125
+ unless val.nil? || (val.is_a?(String) && val =~ PRE_BUILD_REGEX)
126
+ raise ArgumentError, "#{val} is not a valid pre-release version (must be nil, or a string following http://semver.org constraints)"
119
127
  end
120
128
  @pre = val
121
129
  end
122
130
  alias_method :prerelease=, :pre=
123
131
 
124
132
  def build=(val)
125
- if !val.is_a?(String) || val !~ /^[\dA-Za-z\-]+(\.[\dA-Za-z\-]+)*$/
126
- raise ArgumentError, "#{val} is not a valid pbuild version (must be a string following http://semver.org constraints)"
133
+ unless val.nil? || (val.is_a?(String) && val =~ PRE_BUILD_REGEX)
134
+ raise ArgumentError, "#{val} is not a valid build version (must be nil, or a string following http://semver.org constraints)"
127
135
  end
128
136
  @build = val
129
137
  end
130
138
 
131
-
132
139
  def to_s
133
- r = "#{@major}.#{@minor}.#{patch}"
140
+ r = "#{@major}.#{@minor}.#{@patch}"
134
141
  r << "-#{@pre}" if @pre
135
142
  r << "+#{@build}" if @build
136
143
  r
137
144
  end
138
145
 
146
+ def to_a
147
+ [@major, @minor, @patch, @pre, @build]
148
+ end
149
+
150
+ def to_h
151
+ h = [:major, :minor, :patch, :pre, :build].zip(to_a)
152
+ Hash[h.reject{ |k,v| v.nil? }]
153
+ end
154
+
155
+ def inspect
156
+ "#<SemVersion: #{to_s}>"
157
+ end
158
+
139
159
  private
140
-
160
+
141
161
  def compare_sep(ours, theirs, nil_wins)
142
162
  # Both nil? They're equal
143
163
  return 0 if ours.nil? && theirs.nil?
@@ -162,6 +182,19 @@ class SemVersion
162
182
  # If we got this far, either they're equal (same length) or they won
163
183
  return (our_parts.length == their_parts.length) ? 0 : -1
164
184
  end
185
+
186
+ def validate
187
+ # Validates the instance variables. Different approach to validating a raw string
188
+ raise ArgumentError, "Invalid version (major is not an int >= 0)" unless @major.is_a?(Fixnum) && @major >= 0
189
+ raise ArgumentError, "Invalid version (minor is not an int >= 0)" unless @minor.is_a?(Fixnum) && @minor >= 0
190
+ raise ArgumentError, "Invalid version (patch is not an int >= 0)" unless @patch.is_a?(Fixnum) && @patch >= 0
191
+ unless @pre.nil? || (@pre.is_a?(String) && @pre =~ PRE_BUILD_REGEX)
192
+ raise ArgumentError, "Invalid version (pre must be nil, or a string following http://semver.org contraints)"
193
+ end
194
+ unless @build.nil? || (@build.is_a?(String) && @build =~ PRE_BUILD_REGEX)
195
+ raise ArgumentError, "Invalid version (build must be nil, or a string following http://semver.org contraints)"
196
+ end
197
+ end
165
198
  end
166
199
 
167
200
  def SemVersion(*args)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sem_version
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,18 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-12 00:00:00.000000000 Z
12
+ date: 2012-12-16 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: Allows you to parse and compare semantic versions, as specified by http://semver.org/.
15
- Allows constraint checking e.g. >=, <, ~>
14
+ description: Semantic Version parsing, comparison, and constraint checking utility
15
+ (e.g. ~> 1.2), as specified by http://semver.org/
16
16
  email: antony dot mail at gmail
17
17
  executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - lib/sem_version/core_ext.rb
21
22
  - lib/sem_version.rb
23
+ - README.md
24
+ - LICENSE
22
25
  homepage: https://github.com/canton7/sem_version
23
- licenses: []
26
+ licenses:
27
+ - MIT
24
28
  post_install_message:
25
29
  rdoc_options: []
26
30
  require_paths:
@@ -42,5 +46,6 @@ rubyforge_project:
42
46
  rubygems_version: 1.8.24
43
47
  signing_key:
44
48
  specification_version: 3
45
- summary: ! 'SemVersion: Semantic version parsing and comparison. See http://semver.org/'
49
+ summary: ! 'SemVersion: Semantic version parsing and comparison, and constraint checking.
50
+ See http://semver.org/'
46
51
  test_files: []