You can checkout the GitHub here and download the rbxm here
Hey! If you’re like me and love the architecture of object-oriented code, you may find lots of use in my package, Wrapper.
Do note, if you don’t understand OOP principles or haven’t messed around much with it, this may not be the module for you! Also, while Wrapper is in a stable state, I’m always looking for suggestions and improvements.
Wrapper Overview
Wrapper makes object-oriented programming patterns easy to connect into YOUR world. An easy to understand example would be with a KillPart class.
Here we have a simple KillPart class. There is a constructor with the part, a Trove object, and a GUID.
local KillPartClass = {}
KillPartClass.__index = KillPartClass
type KillPart = typeof(setmetatable({} :: {
Part: BasePart,
Trove: any,
GUID: string
}, KillPartClass))
function KillPartClass.new(Part: Instance, Trove: any, GUID: string?): KillPart
local self = setmetatable({}, KillPartClass)
self.Part = Part :: BasePart
self.Trove = Trove
self.GUID = GUID :: string
return self
end
function KillPartClass.Init(self: KillPart) -- automatically runs!
self:WatchTouchedEvent()
end
function KillPartClass.WatchTouchedEvent(self: KillPart)
self.Trove:Add(self.Part.Touched:Connect(function(Hit: BasePart)
local Humanoid = Hit.Parent and Hit.Parent:FindFirstChildWhichIsA("Humanoid")
if not Humanoid then return end
Humanoid.Health = 0
end))
end
function KillPartClass.Destroy(self: KillPart)
print("This object has been destroyed!") -- the trove and metatable are cleaned externally, no need to do it here.
end
Now, we can use Wrapper to manage this class! What Wrapper will do is watch for any instances that get added with the tag “KillPart”. Once that instance is added, it will create a new object and store it internally. Not only does it instantiate objects in the class, but it also provides the constructor with a Trove object that gets automatically cleaned up so you don’t have to do any cleaning yourself! (This also means Trove:Extend() becomes quite useful.) Here is an example of how we could make this work:
local KillPartClass = require(path.to.class.above)
local Wrapper = require(path.to.wrapper)
local KillPartWrapper = Wrapper.new(KillPartClass, "KillPart")
It’s as simple as that! Now we have objects managed by Wrapper! But… what if we want some customization? Fear no longer, Wrapper supports plenty of customization! Here are all of the properties you can change of a Wrapper object.
Methods
There are four types of a methods your class will have: Init, Destroy, Startup, and Constructor. The constructor is .new() by default, the init is :Init by default, the destroy is :Destroy by default, and startup is .OnStart by default. If you have different naming conventions than me, I would suggest you change the method names to your like!
KillPartWrapper = Wrapper.new(KillPartClass, "KillPart", {
Methods = {
Init = "Initialize"
}
})
So, if your class had the Init method named “Initialize”, you would do this!
AutoInit
This is on by default. Setting it to false makes the Init method inside of the class not run automatically. You will have to call Init yourself.
KillPartWrapper = Wrapper.new(KillPartClass, "KillPart", {
AutoInit = true
})
Debug
Setting debug to enabled will add extra logs, warnings, etc.
KillPartWrapper = Wrapper.new(KillPartClass, "KillPart", {
Debug = true
})
Context
When the Startup method is called in a class, it is given the context. You set that context here!
KillPartWrapper = Wrapper.new(KillPartClass, "KillPart", {
Context = { Foo = 1 },
})
Logging
Setting logging to enabled will log all instances that are processed
KillPartWrapper = Wrapper.new(KillPartClass, "KillPart", {
Logging = true
})
Filter
This is predicate method to filter instances you don’t want instantiated.
KillPartWrapper = Wrapper.new(KillPartClass, "KillPart", {
Filter = function(Inst: Instance)
if Inst.Name ~= "Jaeymo" then
return false
end
return true
end,
})
Resolver
This method is used for dynamic requires. If you’re into inheritance with child classes, you may find use in this. Lets say we have two modules under a folder, KillPartA and KillPartB.
local KillPartModules = game:GetService("ReplicatedStorage").KillPartModules
local KillPartA = require(KillPartModules.A)
local KillPartB = require(KillPartModules.B)
-- we do not pass a class here, it can just be an empty table.
KillPartWrapper = Wrapper.new({}, "KillPart", {
Resolver = function(Inst: Instance)
if Inst.Name == "A" then
return KillPartA
elseif Inst.Name == "B" then
return KillPartB
else
warn(`Something went wrong!`)
return nil
end
end
})
Thank you everyone for reading! Please leave any feedback if you have any, I’d greatly appreciate it! You can find all of the API on the GitHub. Enjoy Wrapper.