First time making a custom class. Is this well made?

Hi, I’m new to custom classes and I made one recently that allows you to make categories for gui or any other objects like this:

The script works, but I don’t know if I’m doing this right or if it’s optimized properly. Would love to hear your feedback on it. Thanks!

Module Script for Making the Class

--!strict
local categories = {}
categories.__index = categories

-- // Category variable \\ --
export type category = {
	Name: string,

	Opens: any,--Frame
	PropertyForOpen: string,--Transparency or Visible
	ResetProperties: {Property: string, Value: any}?,--Reset properties of "Opens" when category is closed

	Button: GuiButton,--Button that opens frame
	Signal: string, --RBXScriptSignal to listen for when to open "Opens"
	_connection: any, --Is set by module itself, not other scripts(The signal connection to disconnect if ever needed to)

	Categories: {}?,--Also set by module itself(The group of categories that the button is in)
	_index: any?--Also set by module itself(Index of category in categories table)
}

-- // Type checking stuff \\ --
type self = category

export type categories = typeof(setmetatable({}:: self, categories))

-----------------------------------------------------------------------------------------
------------------------------ // Settings and Activators \\ ----------------------------
-----------------------------------------------------------------------------------------

-- // Makes new category BUTTON. Not group \\ --
function categories.new(t: {category}, c: category, index: number):categories
	local self = {}

	self.Categories = t
	self.Name = c.Name
	self.Opens = c.Opens
	self.Button = c.Button
	self.Signal = c.Signal
	self.PropertyForOpen = c.PropertyForOpen
	self.ResetProperties = nil

	self._connection = nil

	self._index = table.find(t, c)

	return setmetatable(self, categories)
end

-- // Allows other scripts to add a new property to reset when the opened frame is closed \\ --
function categories:ResetPropertyWhenClosed(property: string, value: any)
	if self.ResetProperties == nil then
		self.ResetProperties = {}
	end

	table.insert(self.ResetProperties, {Property = property, Value = value})

	categories.UpdateToTable(self, self.Categories[self._index])
end

-- // Lets other scripts connect the button to an event \\ --
function categories:ConnectTo()
	self._connection = self.Button[self.Signal]:Connect(function()
		categories.OpenCategory(self)
	end)
end

-----------------------------------------------------------------------------------------
----------------------------------- // Functions \\ -------------------------------------
-----------------------------------------------------------------------------------------

-- // Opens the category and closes all others \\ --
function categories:OpenCategory()
	self.Opens[self.PropertyForOpen] = true

	for i, cat:category in self.Categories do
		if cat.Name == self.Name then continue end
		cat.Opens[cat.PropertyForOpen] = false

		categories.Reset(cat)
	end

end


-- // Resets properties for the next \\ --
function categories:Reset()
	if self.ResetProperties ~= nil then--If it has properties to reset...
		for i, v in self.ResetProperties do--For every property, do...
			self.Opens[self.ResetProperties[i]["Property"]] = self.ResetProperties[i]["Value"]
			wait()
		end

	end
end


-----------------------------------------------------------------------------------------
-------------------------------- // Miscellaneous \\ ------------------------------------
-----------------------------------------------------------------------------------------

-- // Updates all self stuff to go into the actual table \\ --
function categories:UpdateToTable(category)
	category.Categories = self.Categories
	category.Name = self.Name
	category.Opens = self.Opens
	category.Button = self.Button
	category.Signal = self.Signal
	category.PropertyForOpen = self.PropertyForOpen
	category.ResetProperties = self.ResetProperties

	category._connection = self._connection
end

-----------------------------------------------------------------------------------------
---------------------------- // Turn off category button \\ -----------------------------
-----------------------------------------------------------------------------------------

-- // Disconnects the connection \\ --
function categories:Disconnect()
	self._connection:Disconnect()
end

-- // Destroys all connections and self stuff \\ --
function categories:Destroy()
	self._connection:Disconnect()
	
	for i, v in self do
		pcall(function()
			v:Destroy()
		end)
		
		pcall(function()
			v = {}
		end)
	end
end

return categories

Local script that requires the module and stuff

local categoryButtons = frame.CategoryButtons
local primaryCategoryButton = categoryButtons.Primary
local secondaryCategoryButton = categoryButtons.Secondary

local catFrames = categoryButtons.Parent.Shop
local pCatFrame = catFrames.Primary.ScrollingFrame
local sCatFrame = catFrames.Secondary.ScrollingFrame

type category = CategoryModule.category


for i, category in categories do
	local cat = CategoryModule.new(categories, category, i)
	cat:ResetPropertyWhenClosed("CanvasPosition", Vector2.new(0, 0))
	cat:ConnectTo()
	
	wait()
	if category.Name == "Primary" then--Default opened one
		cat:OpenCategory()
	end
end
1 Like

There’s a better way to annotate OOP: Type checking - Luau

And use a cleanup module instead of wrapping destroy around pcall

Thirdly I recommend following Roblox Lua Style guide to style your code a bit more uniformly.

Also what is going on here? Why not just Opens: Frame, if it’s of type Frame?

Oh yeah, that was for if you wanted to use a frame, a part, or anything else. Just makes the module have a more variety of things to use for

Here’s the change that I added now:

type categories = {
	__index: categories,
	new: (t: {category}, c: category) -> category,
	ResetPropertyWhenClosed: (self: category) -> (),
	ConnectTo: (self: category) -> (),
	OpenCategory: (self: category) -> (),
	Reset: (self: category) -> (),
	UpdateToTable: (self: category) -> (),
	Disconnect: (self: category) -> (),
	Destroy: (self: category) -> ()
}

Still adding trove right now though

1 Like