semi_semantic 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,3 @@
1
+ module SemiSemantic
2
+ class ParseError < StandardError; end
3
+ end
@@ -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: []