local Maid = {} Maid.ClassName = "Maid" function Maid.new() return setmetatable({ _tasks = {} }, Maid) end function Maid.isMaid(value) return type(value) == "table" and value.ClassName == "Maid" end function Maid:__index(index) if Maid[index] then return Maid[index] else return self._tasks[index] end end function Maid:__newindex(index, newTask) if Maid[index] ~= nil then error(("'%s' is reserved"):format(tostring(index)), 2) end local tasks = self._tasks local oldTask = tasks[index] if oldTask == newTask then return end tasks[index] = newTask if oldTask then if type(oldTask) == "function" then oldTask() elseif typeof(oldTask) == "RBXScriptConnection" then oldTask:Disconnect() elseif oldTask.Destroy then oldTask:Destroy() end end end function Maid:GiveTask(task) if not task then error("Task cannot be false or nil", 2) end local taskId = #self._tasks+1 self[taskId] = task if type(task) == "table" and (not task.Destroy) then warn("[Maid.GiveTask] - Gave table task without .Destroy\n\n" .. debug.traceback()) end return taskId end function Maid:GivePromise(promise) if not promise:IsPending() then return promise end local newPromise = promise.resolved(promise) local id = self:GiveTask(newPromise) newPromise:Finally(function() self[id] = nil end) return newPromise end function Maid:DoCleaning() local tasks = self._tasks for index, task in pairs(tasks) do if typeof(task) == "RBXScriptConnection" then tasks[index] = nil task:Disconnect() end end local index, task = next(tasks) while task ~= nil do tasks[index] = nil if type(task) == "function" then task() elseif typeof(task) == "RBXScriptConnection" then task:Disconnect() elseif task.Destroy then task:Destroy() end index, task = next(tasks) end end Maid.Destroy = Maid.DoCleaning return Maid