Lulu Enums — Enumerator Metatables
The Base Metatable for Enumerators
The enumerators within an Enum
all share a common metatable.
That metatable inherits from a base Enumerator
metatable.
The base metatable provides the following methods for all enumerators:
Method | Brief Description |
---|---|
tostring() |
Returns the name of the enumerator. Enumerator names are unique within an Enum . |
tonumber() |
Returns the ordinal value of the enumerator. By default, ordinals are consecutive integers starting at 1. However, they can be set to other values and need not be unique. |
is_a(enum) |
Returns true if the Enumerator belongs to the argument enum . |
For example, if we have
local Suit = Enum{ 'Clubs', 'Diamonds', 'Hearts', 'Spades' }
1local s = Suit.Clubs
- 1
-
The
s
variable is anEnumerator
instance, so its metatable inherits from the baseEnumerator
metatable.
Then s:tostring()
is “Clubs”, s:tonumber()
is 1, and s:is_a(Suit)
is true
.
Base Metamethods
The base metatable also provides the following metamethods for all enumerators:
Method | Brief Description |
---|---|
.__index(key) |
This metamethod allows direct access to any associated data for the enumerator. |
.__newindex(key, val) |
This metamethod prevents attempts to set values in an enumerator. |
.__tostring() |
Connects Lua’s tostring() and print methods to the Enumerator:tostring() method. |
.__eq(lhs, rhs) |
Returns true if the two arguments agree on their ordinal values. |
.__le(lhs, rhs) |
Returns true if the first argument is numerically less than or equal to the second. |
.__lt(lhs, rhs) |
Returns true if the first argument is numerically less than the second. |
For example, if we have
local Suit = Enum({
Clubs = { abbrev = 'C', color = 'black', icon = '♣', ordinal = 0 },
Diamonds = { abbrev = 'D', color = 'red', icon = '♦', ordinal = 1 },
Hearts = { abbrev = 'H', color = 'red', icon = '♥', ordinal = 2 },
Spades = { abbrev = 'S', color = 'black', icon = '♠', ordinal = 3 }
})
local s = Suit.Hearts
Then print(Suit.Clubs)
is “Clubs”, while print(Suit.Diamonds < Suit.Clubs)
is false
.
You can use the __eq
metamethod to check if two enumerators are the same:
if s == Suit.Clubs then
...
elseif s == Suit.Diamonds then
...
elseif s == Suit.Hearts then
...
elseif s == Suit.Spades then
...
end
This is a slightly wordy version of the C switch statement.
The __index
metamethod allows you to access the associated data for an enumerator directly.
For example, if we have
local s = Suit.Hearts
Then s.abbrev
is “H” and s.color
is “red”.
The __newindex
metamethod prevents you from setting values in an enumerator.
For example, if we have
local s = Suit.Hearts
s.abbrev = "X"
We get an error:
[WARNING] from 'newindex' (Enum.lua:73): Enumerators are immutable -- ignoring attempt to set `Hearts.abbrev` to "X".
Custom Metatables: Enum:mt
While enumerators all share a common base metatable, each Enum
provides a specific metatable for its enumerators. That metatable is returned by the Enum:mt()
method.
All the enumerators in an Enum share the same metatable. That metatable is a clone of the base Enumerator metatable.
|
By accessing the Enum:mt()
metatable, you can add your methods to all the enumerators in the Enum
without affecting other enums you may have created.
For example, if we have
local Suit = Enum[[Clubs, Diamonds, Hearts, Spades]]
We can add a method to all the enumerators in the Suit
enum:
local mt = Suit:mt()
function mt.is_red(self)
return self == Suit.Diamonds or self == Suit.Hearts
end
Now all the enumerators in the Suit
enum have the is_red
method:
print(Suit.Diamonds:is_red()) -- true
print(Suit.Hearts:is_red()) -- true
print(Suit.Clubs:is_red()) -- false
print(Suit.Spades:is_red()) -- false
Only the enumerators in the Suit
enum have the is_red
method. The enumerators in other enums do not have it.