semantic_version 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +41 -0
  4. data/lib/semantic_version.rb +177 -0
  5. metadata +46 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7f66dedf8397b08654d2916450edd305292885da
4
+ data.tar.gz: 533285d4dc57aac800fcbd44192c449e3ba300bb
5
+ SHA512:
6
+ metadata.gz: bc6fb8ebca00aaf4e9668d9d2f31278a946e41ebe86d82261a1578977514931b2f6994e9084b94a36a36f19de0d05c14eef7fe09126b017f450dd31c5b885736
7
+ data.tar.gz: 9b6c19356538f190ff03ede3466aa311c039af9d52a03c07d0ee641cd98db03cd4f46ffe19a2deff091f06a9ab16627a6b8718db6ebe4c381779bd4710051223
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2015 Jared Wyatt
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ semantic_version
2
+ ================
3
+
4
+ A utility for comparing semantic version numbers (see: http://semver.org).
5
+
6
+ ### Usage
7
+
8
+ Initialize a new SemanticVersion object with `SemanticVersion.new()` or `SemanticVersion[]`.
9
+
10
+ SemanticVersion objects have an `is` method for comparing against strings or other SemanticVersion objects.
11
+
12
+ __Available operators for use with the `is` method:__
13
+
14
+ * `eq` or `equal_to` returns true if versions are equivalent; false otherwise
15
+ * `lt` or `less_than` returns true if SemanticVersion is less than comparison version; false otherwise
16
+ * `lte` or `less_than_or_equal_to` returns true if SemanticVersion is less than or equal to comparison version; false otherwise
17
+ * `gt` or `greater_than` returns true if SemanticVersion is greater than comparison version; false otherwise
18
+ * `gte` or `greater_than_or_equal_to` returns true if SemanticVersion is greater than or equal to comparison version; false otherwise
19
+ * `between` returns true if SemanticVersion falls between two comparison versions; false otherwise
20
+ * `within` returns true if SemanticVersion falls within the range of two comparison versions (inclusive); false otherwise
21
+ * `any_of` returns true if SemanticVersion is equivalent to any of the versions in a list; false otherwise
22
+
23
+ __Examples:__
24
+
25
+ ```ruby
26
+ version_a = SemanticVersion.new("1.0")
27
+ version_b = SemanticVersion.new("2.0")
28
+ version_a.is less_than: version_b #=> true
29
+
30
+ SemanticVersion["2.5.0"].is eq: "2.5" #=> true
31
+
32
+ SemanticVersion["2.5.0"].is gt: "2.5.0-beta" #=> true
33
+
34
+ SemanticVersion["3.2.0-beta"].is gt: "3.2.0-alpha", lt: "3.2.0-rc" #=> true
35
+
36
+ SemanticVersion["5.6.2"].is between: ["5.6.0", "5.6.4"] #=> true
37
+
38
+ SemanticVersion["2.2.48"].is any_of: ["2.2.2", "2.2.48", "3.8.0"] #=> true
39
+
40
+ SemanticVersion["1.0.0-rc+1234"].is eq: "1.0.0-rc+6789" #=> true
41
+ ```
@@ -0,0 +1,177 @@
1
+ class SemanticVersion
2
+
3
+ SINGLE_OPERATORS = {
4
+ eq: [0],
5
+ lt: [-1],
6
+ lte: [-1, 0],
7
+ gt: [1],
8
+ gte: [1, 0],
9
+ equal_to: [0],
10
+ less_than: [-1],
11
+ less_than_or_equal_to: [-1, 0],
12
+ greater_than: [1],
13
+ greater_than_or_equal_to: [1, 0]
14
+ }.freeze
15
+
16
+ RANGE_OPERATORS = {
17
+ between: [],
18
+ within: [],
19
+ any_of: []
20
+ }.freeze
21
+
22
+ OPERATORS = SINGLE_OPERATORS.merge(RANGE_OPERATORS).freeze
23
+
24
+
25
+ attr_reader :number_components, :prerelease_components, :build_metadata
26
+
27
+
28
+ # Instantiates a new SemanticVersion.
29
+ #
30
+ # @param [String] version: A semantic version (see http://semver.org).
31
+ #
32
+ def self.[](version)
33
+ self.new(version)
34
+ end
35
+
36
+
37
+ # Parses the given value into version components.
38
+ #
39
+ # @param [String or SemanticVersion] version: A semantic version (see http://semver.org).
40
+ #
41
+ # @return An array [version_number, prerelease, build_metadata], where `version_number` is an array of the
42
+ # number components [MAJOR, MINOR, PATCH], `prerelease` is an array of the prerelease components,
43
+ # and `build_metadata` is, like, you know, the build metadata.
44
+ #
45
+ def self.parse_components(version)
46
+ return version.components if version.is_a? SemanticVersion
47
+
48
+ version_number, extensions = version.to_s.split('-', 2)
49
+ prerelease, build_metadata = extensions.to_s.split('+', 2)
50
+
51
+ version_number = version_number.to_s.split('.').map(&:to_i)
52
+ prerelease = prerelease.to_s.split('.').map {|c| c == c.to_i.to_s ? c.to_i : c }
53
+
54
+ return [version_number, prerelease, build_metadata]
55
+ end
56
+
57
+
58
+ # Instantiates a new SemanticVersion.
59
+ #
60
+ # @param [String] version: A semantic version (see http://semver.org).
61
+ #
62
+ def initialize(version)
63
+ @number_components, @prerelease_components, @build_metadata = self.class.parse_components(version)
64
+ end
65
+
66
+
67
+ # Compares this SemanticVersion with one or more other version numbers.
68
+ #
69
+ # @param [Hash] assertions: A hash where keys are OPERATORS and values are operands in the form of semantic versions.
70
+ #
71
+ # @return True if all assertions are true, false otherwise.
72
+ #
73
+ def is(comparison)
74
+ comparison.each_pair do |operator, version|
75
+ unless OPERATORS.keys.include? operator
76
+ raise ArgumentError.new("unrecognized operator `#{operator}'")
77
+ end
78
+
79
+ if RANGE_OPERATORS.keys.include? operator
80
+ unless version.is_a?(Array) && version.length >= 2
81
+ raise ArgumentError.new("range operand must be an array containing at least two elements")
82
+ end
83
+
84
+ result = if operator == :between
85
+ is gt: version[0], lt: version[1]
86
+ elsif operator == :within
87
+ is gte: version[0], lte: version[1]
88
+ elsif operator == :any_of
89
+ version.map {|v| is eq: v }.any?
90
+ else
91
+ false
92
+ end
93
+
94
+ return false unless result == true
95
+
96
+ else
97
+ number_components, prerelease_components, _ = self.class.parse_components(version)
98
+
99
+ result = 0
100
+
101
+ # Compare version number components.
102
+
103
+ (0..[@number_components.count, number_components.count].max-1).each do |i|
104
+ a = @number_components[i]
105
+ b = number_components[i]
106
+
107
+ result = if !a.nil? && b.nil?
108
+ a == 0 ? 0 : 1
109
+ elsif a.nil? && !b.nil?
110
+ b == 0 ? 0 : -1
111
+ else
112
+ a <=> b
113
+ end
114
+
115
+ break unless result == 0
116
+ end
117
+
118
+ if result == 0
119
+ if @prerelease_components.empty? && !prerelease_components.empty?
120
+ result = 1
121
+ elsif !@prerelease_components.empty? && prerelease_components.empty?
122
+ result = -1
123
+ end
124
+ end
125
+
126
+ # Compare pre-release components.
127
+
128
+ if result == 0
129
+ (0..[@prerelease_components.count, prerelease_components.count].max-1).each do |i|
130
+ break unless result == 0
131
+
132
+ a = @prerelease_components[i]
133
+ b = prerelease_components[i]
134
+
135
+ result = if !a.nil? && b.nil?
136
+ 1
137
+ elsif a.nil? && !b.nil?
138
+ -1
139
+ elsif a.class == b.class
140
+ a <=> b
141
+ else
142
+ a.to_s <=> b.to_s
143
+ end
144
+ end
145
+ end
146
+
147
+ return false unless OPERATORS[operator].include? result
148
+ end
149
+ end
150
+
151
+ return true
152
+ end
153
+
154
+
155
+ # Returns the string representation of the "MAJOR.MINOR.PATCH" version part.
156
+ #
157
+ def number
158
+ @number_components.join('.')
159
+ end
160
+
161
+
162
+ # Returns the string representation of the pre-release version part.
163
+ #
164
+ def prerelease
165
+ @prerelease_components.join('.')
166
+ end
167
+
168
+
169
+ # Returns the string representation of the version.
170
+ #
171
+ def to_s
172
+ number +
173
+ (@prerelease_components.empty? ? "" : "-#{prerelease}") +
174
+ (@build_metadata.nil? ? "" : "+#{@build_metadata}")
175
+ end
176
+
177
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: semantic_version
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Jared Wyatt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: j@wyatt.co
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - LICENSE
20
+ - README.md
21
+ - lib/semantic_version.rb
22
+ homepage: http://github.com/wyattisimo/semantic_version
23
+ licenses:
24
+ - MIT
25
+ metadata: {}
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements: []
41
+ rubyforge_project:
42
+ rubygems_version: 2.4.6
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: 'A utility for comparing semantic version numbers (see: http://semver.org).'
46
+ test_files: []