Features
Terminology
There are a few terms used by LibTSMCore to refer to lua files / groups of files.
Component
A component is a top-level grouping of related files which provide a common set of functionality. Components are typically used for high-level separation of things like application logic from business logic from ulility code. Components should have a very clear dependency hierarchy and are generally contained within a single top-level directory in an addon.
Module
A module is a single file within a component. Each module should contain a related set of APIs and functionality, and may depend on any other module within the same component or any component which the current component depends on. Modules which perform similar functions are generally grouped together into folders within the component.
Class Types
LibTSMCore makes it easy to create modules which define a class via LibTSMClass.
-- Utils/Range.lua
local Utils = select(2, ...).Utils
local Range = Utils:DefineClassType("Range")
function Range:__init(startValue, endValue)
self._start = startValue
self._end = endValue
end
function Range:IncludesValue(value)
return value >= self._start and value <= self._end
end
-- Utils/DebugPrint.lua
local Utils = select(2, ...).Utils
local DebugPrint = Utils:Init("DebugPrint")
local Range = Utils:IncludeClassType("Range")
local VALID_LEVEL_RANGE = Range(1, 80)
function DebugPrint.PrintIsValidLevel(level)
if VALID_LEVEL_RANGE:IncludesValues(level) then
print(format("%d is a valid level!", level))
else
print(format("%d is not a valid level!", level))
end
end
Loading / Unloading
Each module provides a set of default methods which can be used to run code when the module is loaded or unloaded. Note that these are not available for class types.
-- Utils/Table.lua
local Utils = select(2, ...).Utils
local Table = Utils:Init("Table")
Table:OnModuleLoad(function()
-- This code runs once when the module is loaded.
end)
Table:OnModuleUnload(function()
-- This code runs once when the module is unloaded.
end)
Dependencies
Components can depend on other components, which then allows them to include modules from the components they depend on.
-- Services/Core.lua
local ADDON_TABLE = select(2, ...)
ADDON_TABLE.Services = ADDON_TABLE.LibTSMCore.NewComponent("Services")
:AddDependency("Utils")
-- Services/SlashCommands.lua
local Services = select(2, ...).Services
local SlashCommands = Services:Init("SlashCommands")
local DebugPrint = Services:From("Utils"):Include("DebugPrint")
local private = {
greeting = "Hello World!",
}
SlashCommands:OnModuleLoad(function()
SLASH_HELLOWORLD1 = "/helloworld"
SLASH_HELLOWORLD2 = "/hw"
SlashCmdList.HELLOWORLD = private.SlashCommandHandler
end)
---Sets the greeting.
---@param greeting string
function SlashCommands.SetGreeting(greeting)
private.greeting = greeting
end
function private.SlashCommandHandler()
print(private.greeting)
local level = UnitLevel("player")
print(format("You are level %d.", level))
DebugPrint.PrintIsValidLevel(level)
end
Component APIs
Components provide a set of APIs which may be called within the modules to provide some baseline functionality.
Game Version
A set of APIs is provided by every component for accessing the active game version.
-- Utils/DebugPrint.lua
local Utils = select(2, ...).Utils
local DebugPrint = Utils:Init("DebugPrint")
function DebugPrint.PrintGameVersion()
if Utils.IsRetail() then
print("Game version is retail!")
elseif Utils.IsMistsClassic() then
print("Game version is mists class!")
elseif Utils.IsVanillaClassic() then
print("Game version is vanilla classic!")
else
error("Game version is unknown")
end
end
Addon Version
A set of APIs is provided by every component for accessing the current addon version. LibTSMCore
assumes that, for development, the version string is defined in the .toc file as ending in
"project-version@"
, which matches the conventions used by both the Curseforge and
BigWigs packagers. For test environments, LibTSMCore
assumes that C_AddOns.GetAddOnMetadata(ADODN_NAME, “Version”) is mocked to return "v0.0.0"
.
-- Utils/DebugPrint.lua
local Utils = select(2, ...).Utils
local DebugPrint = Utils:Init("DebugPrint")
function DebugPrint.PrintAddonVersion()
if Utils.IsTestVersion() then
print("Running in a test environment")
elseif Utils.IsDevVersion() then
print("Running in a development environment")
else
print("Addon version is: "..Utils.GetVersionStr())
end
end
Time
Since having a source of time is a fairly common requirement, LibTSMCore provides a mechanism for
getting the current time based on a registered time function. This allows for the encompassing
addon to provides its own source-of-truth time based on its own requirements of precision and
accuracy. This is also a purely-optional dependency, with GetTime()
simply returning 0
if no
time function is registered.
-- TimeInit.lua
local LibTSMCore = select(2, ...).LibTSMCore
LibTSMCore.SetTimeFunction(function()
return time()
end)
-- Utils/DebugPrint.lua
local Utils = select(2, ...).Utils
local DebugPrint = Utils:Init("DebugPrint")
function DebugPrint.PrintTime()
print("Current time is: "..Utils.GetTime())
end
Misc. APIs
LibTSMCore.ModuleInfoIterator()
This API is provided to get metadata about all registered modules for debugging purposes.
for _, componentName, modulePath, loadTime, unloadTime in LibTSMCore.ModuleInfoIterator() do
if loadTime then
print(format("%s->%s loaded in %d", componentName, modulePath, loadTime))
end
if unloadTime then
print(format("%s->%s unloaded in %d", componentName, modulePath, unloadTime))
end
end
:OnModuleUnloadLate()
This method is provided on modules in addition to :OnModuleUnload()
in order to defer unloading
of a module until later in the unloading process. This allows for a 2-stage unloading process if
other modules need to be unloaded first. Note that a single module cannot use both
:OnModuleUnload()
and :OnModuleUnloadLate()
.