Created
February 24, 2017 10:55
-
-
Save s-shin/58f930eb0f006eb4e0a25ec00e7fbead to your computer and use it in GitHub Desktop.
Simple class to handle SemVer (http://semver.org/).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SemVer | |
include Comparable | |
attr_accessor :major, :minor, :patch, :prerelease, :build_metadata | |
@@re = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))*))?(?:\+((?:0|[1-9A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))*))?$/ | |
def initialize(major, minor, patch, prerelease = "", build_metadata = "") | |
@major = major.to_i | |
@minor = minor.to_i | |
@patch = patch.to_i | |
@prerelease = prerelease.to_s | |
@build_metadata = build_metadata.to_s | |
end | |
def valid? | |
!(@@re !~ to_s) | |
end | |
def prerelease? | |
@prerelease && !@prerelease.empty? | |
end | |
def self.parse(str) | |
m = str.match(@@re) | |
return nil unless m | |
SemVer.new(*m[1..-1]) | |
end | |
def to_s | |
s = "#{@major}.#{@minor}.#{@patch}" | |
s += "-#{@prerelease}" if prerelease? | |
s += "+#{@build_metadata}" if @build_metadata && !@build_metadata.empty? | |
s | |
end | |
def compare_major(other) | |
return 1 if @major > other.major | |
return -1 if @major < other.major | |
return 0 | |
end | |
def compare_minor(other) | |
return 1 if @minor > other.minor | |
return -1 if @minor < other.minor | |
return 0 | |
end | |
def compare_patch(other) | |
return 1 if @patch > other.patch | |
return -1 if @patch < other.patch | |
return 0 | |
end | |
def compare_major_minor_patch(other) | |
c = compare_major(other) | |
return c if c != 0 | |
c = compare_minor(other) | |
return c if c != 0 | |
c = compare_patch(other) | |
return c if c != 0 | |
return 0 | |
end | |
def compare_prerelease(other) | |
return 1 if !prerelease? && other.prerelease? | |
return -1 if prerelease? && !other.prerelease? | |
ids = @prerelease.split('.') | |
other_ids = other.prerelease.split('.') | |
ids_size = ids.size | |
other_ids_size = other_ids.size | |
min_size = ids_size < other_ids_size ? ids_size : other_ids_size | |
for i in 0..min_size do | |
next if ids[i] == other_ids[i] | |
as_i = nil | |
begin | |
as_i = Integer(ids_[i]) | |
rescue | |
end | |
other_as_i = nil | |
begin | |
other_as_i = Integer(other_ids[i]) | |
rescue | |
end | |
return 1 if !as_i.nil? && other_as_i.nil? | |
return -1 if as_i.nil? && !other_as_i.nil? | |
return as_i <=> other_as_i if !as_i.nil? && !other_as_i.nil? | |
return ids[i] <=> other_ids[i] | |
end | |
return 1 if ids_size > other_ids_size | |
return -1 if ids_size < other_ids_size | |
return 0 | |
end | |
def <=>(other) | |
c = compare_major_minor_patch(other) | |
return c if c != 0 | |
c = compare_prerelease(other) | |
return c if c != 0 | |
return 0 | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'test/unit' | |
$:.unshift File.dirname(__FILE__) + '/.' | |
require 'semver' | |
class TestSemVer < Test::Unit::TestCase | |
def test_parse | |
s = '0.1.2' | |
v = SemVer.parse(s) | |
assert_true(v.valid?) | |
assert_equal(0, v.major) | |
assert_equal(1, v.minor) | |
assert_equal(2, v.patch) | |
assert_equal(s, v.to_s) | |
s = '10.0.0-alpha.1.2+123' | |
v = SemVer.parse(s) | |
assert_true(v.valid?) | |
assert_equal(10, v.major) | |
assert_equal(0, v.minor) | |
assert_equal(0, v.patch) | |
assert_equal('alpha.1.2', v.prerelease) | |
assert_equal('123', v.build_metadata) | |
assert_equal(s, v.to_s) | |
[ | |
'00.1.2', | |
'0.1.2-$12', | |
'0.1.2-alpha.12~3', | |
].each do |s| | |
assert_nil(SemVer.parse(s)) | |
end | |
end | |
def test_compare | |
[ | |
['0.1.2', :==, '0.1.2'], | |
['0.1.2', :>=, '0.1.2'], | |
['0.1.2', :<, '0.1.3'], | |
['0.1.2', :<, '1.0.0'], | |
['1.0.0', :>, '0.100.100'], | |
['1.0.0-alpha', :<, '1.0.0-alpha.1'], | |
['1.0.0-alpha.1', :<, '1.0.0-alpha.beta'], | |
['1.0.0-alpha.1', :<, '1.0.0-beta'], | |
['1.0.0-beta', :<, '1.0.0-beta.2'], | |
['1.0.0-beta.2', :<, '1.0.0-beta.11'], | |
['1.0.0-beta.11', :<, '1.0.0-rc.1'], | |
['1.0.0-rc.1', :<, '1.0.0'], | |
].each do |c| | |
assert_operator(SemVer.parse(c[0]), c[1], SemVer.parse(c[2])) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment