diff --git a/semver.lua b/semver.lua index 5641102..69ee0b6 100644 --- a/semver.lua +++ b/semver.lua @@ -12,6 +12,16 @@ local function checkPositiveInteger(number, name) assert(math.floor(number) == number, name .. ' must be an integer') end +local function present(value) + return value and value ~= '' +end + +local function filterPrerelease(prerelease) + local identifiers = prerelease:match("-([%w-][%.%w-]+)") + assert(identifiers, ("The prerelease %q must start with a dash and be followed by dashes, alphanumerics or dots."):format(prerelease)) + return identifiers +end + local methods = {} function methods:nextMajor() @@ -28,7 +38,8 @@ local mt = { __index = methods } function mt:__eq(other) return self.major == other.major and self.minor == other.minor and - self.patch == other.patch + self.patch == other.patch and + self.prerelease == other.prerelease end function mt:__lt(other) return self.major < other.major or @@ -40,18 +51,23 @@ function mt:__pow(other) self.minor <= other.minor end function mt:__tostring() - return ("%d.%d.%d"):format(self.major, self.minor, self.patch) + local buffer = { ("%d.%d.%d"):format(self.major, self.minor, self.patch) } + if self.prerelease then table.insert(buffer, "-" .. self.prerelease) end + return table.concat(buffer) end -- defined as local at the begining of the file -version = function(major, minor, patch) +version = function(major, minor, patch, prerelease) assert(major, "At least one parameter is needed") if type(major) == 'string' then - local sMajor, sMinor, sPatch = major:match("^(%d+)%.?(%d*)%.?(%d*)$") - assert(type(sMajor) == 'string', ("Could not version number(s) from %q"):format(major)) + local sMajor, sMinor, sPatch, sPrerelease = major:match("^(%d+)%.?(%d*)%.?(%d*)(.-)$") + assert(type(sMajor) == 'string', ("Could not extract version number(s) from %q"):format(major)) major, minor, patch = tonumber(sMajor), tonumber(sMinor), tonumber(sPatch) + if present(sPrerelease) then + prerelease = filterPrerelease(sPrerelease) + end end patch = patch or 0 @@ -61,7 +77,8 @@ version = function(major, minor, patch) checkPositiveInteger(minor, "minor") checkPositiveInteger(patch, "patch") - return setmetatable({major=major, minor=minor, patch=patch}, mt) + local result = {major=major, minor=minor, patch=patch, prerelease=prerelease} + return setmetatable(result, mt) end return version diff --git a/spec/semver_spec.lua b/spec/semver_spec.lua index c70d628..096d386 100644 --- a/spec/semver_spec.lua +++ b/spec/semver_spec.lua @@ -1,9 +1,10 @@ local v = require 'semver' -local function checkVersion(ver, major, minor, patch) +local function checkVersion(ver, major, minor, patch, prerelease) assert_equal(major, ver.major) assert_equal(minor, ver.minor) assert_equal(patch, ver.patch) + assert_equal(prerelease, ver.prerelease) end context('semver', function() @@ -22,6 +23,10 @@ context('semver', function() it('parses 1 number correctly', function() checkVersion(v(1), 1,0,0) end) + + it('parses prereleases, if they exist', function() + checkVersion(v(1,2,3,"alpha"), 1,2,3,"alpha") + end) end) describe("from strings", function() @@ -37,6 +42,9 @@ context('semver', function() test("5", function() checkVersion( v'5', 5,0,0) end) + test("1.2.3-alpha", function() + checkVersion( v'1.2.3-alpha', 1,2,3,'alpha' ) + end) end) describe('errors', function() @@ -72,6 +80,10 @@ context('semver', function() it("works with major, minor and patch", function() assert_equal("1.2.3", tostring(v(1,2,3))) end) + + it("works with a prerelease", function() + assert_equal("1.2.3-beta", tostring(v(1,2,3,'beta'))) + end) end) describe("==", function() @@ -81,6 +93,9 @@ context('semver', function() it("is false when major, minor and patch are not the same", function() assert_not_equal(v(1,2,3), v(4,5,6)) end) + it("false if all is the same except the prerelease", function() + assert_not_equal(v(1,2,3), v'1.2.3-alpha') + end) end) describe("<", function()