semi_semantic 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/README.md +58 -0
- data/lib/semi_semantic/parse_error.rb +3 -0
- data/lib/semi_semantic/version.rb +73 -0
- data/lib/semi_semantic/version_segment.rb +88 -0
- metadata +83 -0
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
semi-semantic
|
2
|
+
=============
|
3
|
+
|
4
|
+
A Ruby library for parsing/formatting/comparing semi-semantic versions.
|
5
|
+
|
6
|
+
### Why not just use Semantic Versioning?
|
7
|
+
The purpose of this library is to _support, but not require_ semantic versioning.
|
8
|
+
|
9
|
+
### How is this different than Semantic Versioning?
|
10
|
+
Unlike SemVer, Semi-Semantic does not define exactly how it must be used.
|
11
|
+
|
12
|
+
Semi-Semantic...
|
13
|
+
- Allows unlimited version segment components separated by periods (accessed by array index).
|
14
|
+
- Does not have named concept of 'major', 'minor', or 'patch' versions.
|
15
|
+
- Supports underscores, to allow compatibility with ruby gem conventions and timestamps.
|
16
|
+
|
17
|
+
### Usage
|
18
|
+
|
19
|
+
```Ruby
|
20
|
+
require 'semi_semantic/version'
|
21
|
+
...
|
22
|
+
version_string = '1.0.2-alpha.1+build.10'
|
23
|
+
version = SemiSemantic::Version.parse(version_string)
|
24
|
+
|
25
|
+
p version.release.to_s
|
26
|
+
# '1.0.2'
|
27
|
+
|
28
|
+
p version.pre_release.to_s
|
29
|
+
# 'alpha.1'
|
30
|
+
|
31
|
+
p version.post_release.to_s
|
32
|
+
# 'build.10'
|
33
|
+
|
34
|
+
# increment post-release number
|
35
|
+
p SemiSemantic::Version.new(version.release, version.pre_release, version.post_release.increment)
|
36
|
+
# '1.0.2-alpha.1+build.11'
|
37
|
+
|
38
|
+
# increment pre-release number
|
39
|
+
p SemiSemantic::Version.new(version.release, version.pre_release.increment)
|
40
|
+
# '1.0.2-alpha.2'
|
41
|
+
|
42
|
+
# increment release number
|
43
|
+
p SemiSemantic::Version.new(version.release.increment)
|
44
|
+
# '1.0.3'
|
45
|
+
|
46
|
+
# increment 'major' release number
|
47
|
+
p SemiSemantic::Version.new(version.release.increment(0))
|
48
|
+
# '2.0.0'
|
49
|
+
|
50
|
+
# increment 'minor' release number
|
51
|
+
p SemiSemantic::Version.new(version.release.increment(1))
|
52
|
+
# '1.1.0'
|
53
|
+
|
54
|
+
# increment second most least significant release number
|
55
|
+
p SemiSemantic::Version.new(version.release.increment(-2))
|
56
|
+
# '1.1.0'
|
57
|
+
|
58
|
+
```
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'semi_semantic/parse_error'
|
2
|
+
require 'semi_semantic/version_segment'
|
3
|
+
|
4
|
+
module SemiSemantic
|
5
|
+
class Version
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
PRE_RELEASE_PREFIX = '-'
|
9
|
+
POST_RELEASE_PREFIX = '+'
|
10
|
+
|
11
|
+
attr_reader :release, :pre_release, :post_release, :segments
|
12
|
+
|
13
|
+
# Parses a semi-semantic version string into up to three segments
|
14
|
+
# Raises a ParseError if the string format is invalid
|
15
|
+
# Raises an ArgumentError if version_string is nil
|
16
|
+
def self.parse(version_string)
|
17
|
+
raise ArgumentError.new 'Invalid Version String: nil' if version_string.nil?
|
18
|
+
raise ArgumentError.new "Invalid Version String: '#{version_string}'" if version_string == ''
|
19
|
+
matches = /^(?<release>[0-9A-Za-z_\.]+)(\-(?<pre_release>[0-9A-Za-z_\-\.]+))?(\+(?<post_release>[0-9A-Za-z_\-\.]+))?$/.match(version_string)
|
20
|
+
raise ParseError.new "Invalid Version Format: '#{version_string}'" if matches.nil?
|
21
|
+
|
22
|
+
release = VersionSegment.parse matches[:release]
|
23
|
+
pre_release = nil
|
24
|
+
if matches[:pre_release]
|
25
|
+
pre_release = VersionSegment.parse matches[:pre_release]
|
26
|
+
end
|
27
|
+
post_release = nil
|
28
|
+
if matches[:post_release]
|
29
|
+
post_release = VersionSegment.parse matches[:post_release]
|
30
|
+
end
|
31
|
+
self.new(release, pre_release, post_release)
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(release, pre_release=nil, post_release=nil)
|
35
|
+
raise ArgumentError.new 'Invalid Release: nil' if release.nil?
|
36
|
+
@release = release
|
37
|
+
@pre_release = pre_release
|
38
|
+
@post_release = post_release
|
39
|
+
|
40
|
+
@segments = [release]
|
41
|
+
@segments << pre_release unless pre_release.nil?
|
42
|
+
@segments << post_release unless post_release.nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
def <=>(other)
|
46
|
+
result = (@release <=> other.release)
|
47
|
+
return result unless result == 0
|
48
|
+
|
49
|
+
unless @pre_release.nil? && other.pre_release.nil?
|
50
|
+
return 1 if @pre_release.nil?
|
51
|
+
return -1 if other.pre_release.nil?
|
52
|
+
result = (@pre_release <=> other.pre_release)
|
53
|
+
return result unless result == 0
|
54
|
+
end
|
55
|
+
|
56
|
+
unless @post_release.nil? && other.post_release.nil?
|
57
|
+
return -1 if @post_release.nil?
|
58
|
+
return 1 if other.post_release.nil?
|
59
|
+
result = (@post_release <=> other.post_release)
|
60
|
+
return result unless result == 0
|
61
|
+
end
|
62
|
+
|
63
|
+
0
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
str = @release.to_s
|
68
|
+
str += PRE_RELEASE_PREFIX + @pre_release.to_s unless @pre_release.nil?
|
69
|
+
str += POST_RELEASE_PREFIX + @post_release.to_s unless @post_release.nil?
|
70
|
+
str
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'semi_semantic/parse_error'
|
2
|
+
|
3
|
+
module SemiSemantic
|
4
|
+
class VersionSegment
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
#TODO: immutable?
|
8
|
+
attr_reader :components
|
9
|
+
|
10
|
+
# Converts a string into a VersionCluster
|
11
|
+
# Raises a ParseError if the string format is invalid
|
12
|
+
# Raises an ArgumentError if version_string is nil
|
13
|
+
def self.parse(component_string)
|
14
|
+
raise ArgumentError.new 'Invalid Version Component String: nil' if component_string.nil?
|
15
|
+
self.new(component_string.split('.').map do |v|
|
16
|
+
if v.match(/\A[0-9]+\z/)
|
17
|
+
v.to_i
|
18
|
+
elsif v.match(/\A[0-9A-Za-z_\-]+\z/)
|
19
|
+
v
|
20
|
+
else
|
21
|
+
raise ParseError.new 'Invalid Version Component Format: Requires alphanumerics and hyphens only'
|
22
|
+
end
|
23
|
+
end)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Construction can throw ArgumentError, but does no parsing or type-conversion
|
27
|
+
def initialize(components)
|
28
|
+
raise ArgumentError.new 'Invalid Version Components: nil' if components.nil?
|
29
|
+
raise ArgumentError.new "Invalid Version Components: #{components}" if components.empty? || components.include?('')
|
30
|
+
@components = components
|
31
|
+
end
|
32
|
+
|
33
|
+
def <=>(other)
|
34
|
+
a = @components
|
35
|
+
b = other.components
|
36
|
+
if a.size > b.size
|
37
|
+
comparison = a[0...b.size] <=> b
|
38
|
+
return comparison unless comparison == 0
|
39
|
+
a[b.size..-1].each {|v| return 1 unless v == 0 }
|
40
|
+
0
|
41
|
+
elsif a.size < b.size
|
42
|
+
comparison = a <=> b[0...a.size]
|
43
|
+
return comparison unless comparison == 0
|
44
|
+
b[a.size..-1].each {|v| return -1 unless v == 0 }
|
45
|
+
0
|
46
|
+
else
|
47
|
+
a <=> b
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns a copy of the VersionCluster with the integer at the provided index incremented by one.
|
52
|
+
# Raises a TypeError if the value at that index is not an integer.
|
53
|
+
def increment(index=-1)
|
54
|
+
value = @components[index]
|
55
|
+
raise TypeError.new "'#{value}' is not an integer" unless value.is_a? Integer
|
56
|
+
|
57
|
+
copy = Array.new @components
|
58
|
+
copy[index] = value + 1
|
59
|
+
|
60
|
+
while index < copy.size && index != -1
|
61
|
+
index += 1
|
62
|
+
value = copy[index]
|
63
|
+
if value.is_a? Integer
|
64
|
+
copy[index] = 0
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
self.class.new copy
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns a copy of the VersionCluster with the integer at the provided index decremented by one.
|
72
|
+
# Raises a TypeError if the value at that index is not an integer.
|
73
|
+
# Raises a RangeError if the value is zero or less
|
74
|
+
def decrement(index=-1)
|
75
|
+
value = @components[index]
|
76
|
+
raise TypeError.new "'#{value}' is not an integer" unless value.is_a? Integer
|
77
|
+
raise RangeError.new "'#{value}' is zero or less" unless value > 0
|
78
|
+
|
79
|
+
copy = Array.new @components
|
80
|
+
copy[index] = value - 1
|
81
|
+
self.class.new copy
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
@components.join('.')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: semi_semantic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Pivotal
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-05-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0.rc
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0.rc
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec-legacy_formatters
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.0.0.rc1
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.0.0.rc1
|
46
|
+
description: ! 'Semi Semantic
|
47
|
+
|
48
|
+
120471'
|
49
|
+
email: support@cloudfoundry.com
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- lib/semi_semantic/parse_error.rb
|
55
|
+
- lib/semi_semantic/version.rb
|
56
|
+
- lib/semi_semantic/version_segment.rb
|
57
|
+
- README.md
|
58
|
+
homepage: https://github.com/pivotal-cf-experimental/semi_semantic
|
59
|
+
licenses:
|
60
|
+
- Apache 2.0
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 1.9.3
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.23
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Semi Semantic
|
83
|
+
test_files: []
|