add gs
This commit is contained in:
+100
@@ -0,0 +1,100 @@
|
||||
local function strict(t, name)
|
||||
name = name or tostring(t)
|
||||
|
||||
return setmetatable(t, {
|
||||
__index = function(self, key)
|
||||
local message = ("%q (%s) is not a valid member of %s"):format(
|
||||
tostring(key),
|
||||
typeof(key),
|
||||
name
|
||||
)
|
||||
|
||||
error(message, 2)
|
||||
end,
|
||||
|
||||
__newindex = function(self, key, value)
|
||||
local message = ("%q (%s) is not a valid member of %s"):format(
|
||||
tostring(key),
|
||||
typeof(key),
|
||||
name
|
||||
)
|
||||
|
||||
error(message, 2)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
local function addEnumValue(enumInternal, enumInternalRawValues, enumName, valueName, rawValue)
|
||||
local isValueNameString = typeof(valueName) == "string"
|
||||
assert(isValueNameString, "Only string names are supported for enums!")
|
||||
if isValueNameString then
|
||||
assert(valueName ~= "fromRawValue", "fromRawValue is reserved")
|
||||
assert(valueName ~= "isEnumValue", "isEnumValue is reserved")
|
||||
end
|
||||
assert(enumInternal[valueName] == nil, "Enum value names can only be used once!")
|
||||
assert(enumInternalRawValues[valueName] == nil, "Enum values can only be used once!")
|
||||
|
||||
local value = newproxy(true)
|
||||
local valueMetatable = getmetatable(value)
|
||||
|
||||
valueMetatable.__tostring = function()
|
||||
return ("%s.%s"):format(enumName, valueName)
|
||||
end
|
||||
|
||||
valueMetatable.__index = strict({
|
||||
rawValue = function()
|
||||
return rawValue
|
||||
end
|
||||
})
|
||||
|
||||
enumInternal[valueName] = value
|
||||
enumInternalRawValues[rawValue] = value
|
||||
end
|
||||
|
||||
local function enumerate(enumName, values)
|
||||
assert(typeof(enumName) == "string", "Bad argument #1 - enums must be created using a string name!")
|
||||
assert(typeof(values) == "table", "Bad argument #2 - enums must be created using a table!")
|
||||
|
||||
local enumInternal = {}
|
||||
local enumInternalRawValues = {}
|
||||
|
||||
-- Allow a list-like syntax for string enums for convenience
|
||||
if values[1] ~= nil then
|
||||
for _, valueName in ipairs(values) do
|
||||
addEnumValue(enumInternal, enumInternalRawValues, enumName, valueName, valueName)
|
||||
end
|
||||
else
|
||||
for valueName, rawValue in pairs(values) do
|
||||
addEnumValue(enumInternal, enumInternalRawValues, enumName, valueName, rawValue)
|
||||
end
|
||||
end
|
||||
|
||||
function enumInternal.fromRawValue(rawValue)
|
||||
return enumInternalRawValues[rawValue]
|
||||
end
|
||||
|
||||
function enumInternal.isEnumValue(value)
|
||||
if typeof(value) ~= "userdata" then
|
||||
return false
|
||||
end
|
||||
|
||||
for _, enumValue in pairs(enumInternal) do
|
||||
if enumValue == value then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local enum = newproxy(true)
|
||||
local meta = getmetatable(enum)
|
||||
meta.__index = strict(enumInternal, enumName)
|
||||
meta.__tostring = function()
|
||||
return enumName
|
||||
end
|
||||
|
||||
return enum
|
||||
end
|
||||
|
||||
return enumerate
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
return function()
|
||||
local enumerate = require(script.Parent.enumerate)
|
||||
|
||||
describe("Any Enum", function()
|
||||
local AnyEnum = enumerate("AnyEnum", { "A", "B", "C" })
|
||||
|
||||
it("should be valid", function()
|
||||
expect(AnyEnum).to.be.ok()
|
||||
end)
|
||||
|
||||
it("should have the correct name", function()
|
||||
expect(tostring(AnyEnum)).to.be.equal("AnyEnum")
|
||||
end)
|
||||
|
||||
it("cannot be altered", function()
|
||||
expect(function()
|
||||
AnyEnum.A = "B"
|
||||
end).to.throw()
|
||||
end)
|
||||
|
||||
it("should error when accessing an invalid value", function()
|
||||
expect(function()
|
||||
local _ = AnyEnum.D
|
||||
end).to.throw()
|
||||
end)
|
||||
|
||||
it("should have values that can be compared for equality", function()
|
||||
expect(AnyEnum.A).to.equal(AnyEnum.A)
|
||||
expect(AnyEnum.A == AnyEnum.B).to.equal(false)
|
||||
end)
|
||||
|
||||
it("should have userdata values", function()
|
||||
expect(typeof(AnyEnum.A)).to.equal("userdata")
|
||||
end)
|
||||
|
||||
it("should have values with correct rawValue types", function()
|
||||
expect(typeof(AnyEnum.A.rawValue())).to.equal("string")
|
||||
end)
|
||||
|
||||
it("should have values with a useful name", function()
|
||||
expect(tostring(AnyEnum.A)).to.equal("AnyEnum.A")
|
||||
end)
|
||||
|
||||
it("should have values with correct rawValues", function()
|
||||
expect(AnyEnum.A.rawValue()).to.equal("A")
|
||||
end)
|
||||
|
||||
it("should return the correct value from a rawValue", function()
|
||||
expect(AnyEnum.fromRawValue("A")).to.equal(AnyEnum.A)
|
||||
end)
|
||||
|
||||
it("should detect whether a value is an enum value", function()
|
||||
expect(AnyEnum.isEnumValue(AnyEnum.A)).to.equal(true)
|
||||
expect(AnyEnum.isEnumValue("A")).to.equal(false)
|
||||
end)
|
||||
end)
|
||||
|
||||
it("should error when creating an enum with a non-string name", function()
|
||||
expect(function()
|
||||
enumerate(1, { "A", "B", "C" })
|
||||
end).to.throw()
|
||||
end)
|
||||
|
||||
it("should error when creating an enum with duplicate values", function()
|
||||
expect(function()
|
||||
enumerate(1, { "A", "B", "C", "C" })
|
||||
end).to.throw()
|
||||
end)
|
||||
end
|
||||
+1
@@ -0,0 +1 @@
|
||||
return require(script.enumerate)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
return function()
|
||||
local enumerate = require(script.Parent)
|
||||
|
||||
it("should load a function", function()
|
||||
expect(typeof(enumerate)).to.equal("function")
|
||||
end)
|
||||
end
|
||||
Reference in New Issue
Block a user