Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Class management :
- local bases = {}
- bases.Functions = require(6976698809)
- bases.Signal = require(6976644438)
- bases.classes = {}
- local functions = bases.Functions
- local instances_proxy = functions.userdata.read_only(bases)
- local table = functions.table
- -- Settings :
- local debug_enabled = true -- Print the recognized classes after loading them.
- local silence_module = "__" -- Keyword to silence modules.
- local TYPE_ERR = "Expected type \"%s\" when assigning property \"%s\", got \"%s\""
- local NIL = "#@#@#@" -- Keyword to represent nil (You can't set a value to nil in a table and keep the reference).
- local attribute_fields = {"read", "public", "private"}
- local type_properties = {
- instance_name = "string",
- base_object = "Instance",
- constructor = "function"
- }
- local function base_constructor(object, ...)
- print(string.format("%s of class %s has been created!", tostring(object), object.ClassName))
- print(string.format("Additional arguments: %s", ... and table.concat({...}, ", ") or "null"))
- end
- -- Creation of attributes for objects.
- local create_attributes = function(class_attributes, instance, class_name)
- local object_attributes = {}
- object_attributes.key = instance
- object_attributes.signals = {}
- for section, attributes in pairs(class_attributes) do
- local object_section = {}
- for attribute_name, info in pairs(attributes) do
- object_section[attribute_name] = info[1]
- if section == "private" then continue end
- object_attributes.signals[attribute_name] = bases.Signal(attribute_name)
- end
- if section == "read" then object_section.ClassName = class_name end
- if section == "private" then continue end
- local section_proxy = newproxy(true)
- local section_meta = getmetatable(section_proxy)
- section_meta.__index = function(_, key)
- if key == "pairs" then
- return object_section
- else
- return object_section[key]
- end
- end
- section_meta.__newindex = function(_, key, value)
- if typeof(value) == attributes[key][2] or type(value) == "nil" then
- object_section[key] = value
- object_attributes.signals[key]:Fire()
- else
- error(string.format(TYPE_ERR, attributes[key][2], key, typeof(value)), 3)
- end
- end
- object_attributes[section] = section_proxy
- end
- return object_attributes
- end
- -- Create proxy for classes :
- local function class_proxy(class)
- local public = class.public
- local read = class.read
- local private = class.private
- local class_proxy = newproxy(true)
- local class_meta = getmetatable(class_proxy)
- -- Conventional metamethods.
- class_meta.__newindex = function(class_proxy, key, value)
- if public[key] then
- local property_type = type_properties[key]
- local value_type = typeof(value)
- assert(value_type == property_type, string.format(TYPE_ERR, property_type, key, value_type))
- public[key] = value
- elseif read[key] then
- error("Can't modify this property.", 2)
- else
- error("Unable to modify class.", 2)
- end
- end
- class_meta.__tostring = function(class_proxy)
- return class.name
- end
- class_meta.__index = function(class_proxy, index)
- return public[index] or read[index] or class_meta[index]
- end
- return class_proxy
- end
- -- Setup function for classes :
- local function setup_class(module)
- local class = {
- public = {},
- read = {},
- private = {}
- }
- local read = class.read
- local public = class.public
- local private = class.private
- private.objects = {}
- private.attributes = {
- public = {},
- read = {},
- private = {}
- }
- read.methods = {}
- read.name = module.Name
- public.instance_name = module.Name
- public.base_object = Instance.new("Part")
- public.constructor = base_constructor
- -- GetPropertyChangedSignal compatibility.
- function read.methods:GetPropertyChangedSignal(attribute_name)
- local attributes = private.objects[self]
- local signals = attributes.signals
- local key = attributes.key
- local signal = signals[attribute_name]
- if signal then
- return signal
- else
- local success, signal = pcall(key.GetPropertyChangedSignal, key, attribute_name)
- if not success then
- error(string.format("%s is not a valid property name.", attribute_name), 2)
- else
- return signal
- end
- end
- end
- -- Removing the object from references.
- function read.methods:Destroy()
- local attributes = private.objects[self]
- local key = attributes.key
- local signals = attributes.signals
- for signal_name, signal in pairs(signals) do
- signal:Destroy()
- end
- private.objects[self] = nil
- local meta = getmetatable(self)
- for i, v in pairs(meta) do
- meta[i] = nil
- end
- key:Destroy()
- end
- -- Creating the class' proxy.
- local class_proxy = class_proxy(class)
- local class_meta = getmetatable(class_proxy)
- -- Class functions :
- do
- -- Adding new object to the class.
- function class_meta.create(object)
- local class = class_proxy
- local instance = class.base_object:Clone()
- instance.Name = class.instance_name
- instance:SetAttribute("ClassName", class.name)
- local attributes = create_attributes(private.attributes, instance, class.name)
- private.objects[object] = attributes
- return attributes
- end
- -- Function for getting attributes in any attribute section (read, private, public)
- function class_meta.get(object_get, attribute_get)
- local class = class_proxy
- for section, attributes in pairs(private.objects[object_get]) do
- if section == "key" or section == "signals" then continue end
- local value = attributes[attribute_get]
- if value then
- return value ~= NIL and value or nil
- end
- end
- error(string.format("'%s' its not a valid attribute of class %s", attribute_get, class.name))
- return
- end
- -- Function for modifying attributes in any attribute section (read, private, public)
- function class_meta.set(object_modify, attribute_modify, value_modify)
- local class = class_proxy
- local sections = private.objects[object_modify]
- for section, attributes in pairs(sections) do
- if section == "key" or section == "signals" then continue end
- section = sections[section]
- local value = section[attribute_modify]
- if value == value_modify then return end
- if value then
- section[attribute_modify] = value_modify == nil and NIL or value_modify
- return
- end
- end
- error(string.format("'%s' its not a valid attribute of class %s", attribute_modify, class.name))
- end
- -- Adding attributes to your class.
- function class_meta.add_attribute(section, name, default, attribute_type)
- if not table.find(attribute_fields, section) then error("Expected a valid attribute section. (public / read / private)", 2) end
- if default then attribute_type = typeof(default) end
- private.attributes[section][name] = {default or NIL, attribute_type}
- end
- -- Check if its a valid attribute.
- function class_meta.is_attribute(object, attribute_name, user)
- for section, attributes in pairs(private.objects[object]) do
- if section == "key" or section == "signals" then continue end
- if user and section == "private" then continue end
- if attributes[attribute_name] then return true end
- end
- return false
- end
- -- Get object from the object's key (the key its the instance that identifies the object)
- function class_meta.getObjectFromKey(key)
- for object, attributes in pairs(private.objects) do
- if attributes.key == key then
- return object
- end
- end
- return
- end
- -- Get the key instance from the object.
- function class_meta.getKeyFromObject(object_goal)
- for object, sections in pairs(private.objects) do
- if object == object_goal then
- return sections.key
- end
- end
- return
- end
- end
- return class_proxy
- end
- --Object management functions.
- local getKeyInstance; getKeyInstance = function(object)
- if type(object) == "table" then
- local unwrapped = {}
- for key, value in next, object do
- unwrapped[key] = getKeyInstance(value)
- end
- return unwrapped
- elseif type(object) == "userdata" and bases.classes[object.ClassName] then
- local class = bases.classes[object.ClassName][2]
- local keyInstance = class.getKeyFromObject(object)
- if keyInstance then
- return keyInstance
- end
- return object
- else
- return object
- end
- end
- local wrapFunction; wrapFunction = function(normalFunction)
- if type(normalFunction) == "function" then
- local wrappedFunction = function(...)
- local arguments = getKeyInstance{...}
- return normalFunction(unpack(arguments))
- end
- return wrappedFunction
- else
- return normalFunction
- end
- end
- local createObject = function(class, ...)
- local object = newproxy(true)
- local meta = getmetatable(object)
- local attributes = class.create(object)
- local private = attributes.private
- local public = attributes.public
- local read = attributes.read
- meta.__index = function(object, index)
- if class.is_attribute(object, index, true) then return class.get(object, index) end
- return class.methods[index] or wrapFunction(attributes.key[index])
- end
- meta.__newindex = function(object, key, value)
- if public[key] then
- public[key] = value
- elseif read[key] then
- error("can't set value", 2)
- else
- attributes.key[key] = value
- end
- end
- meta.__tostring = function(object)
- return tostring(attributes.key)
- end
- class.constructor(object, ...)
- return object
- end
- local function load_classes()
- if #bases.classes > 1 then return end
- local class_debug = "Classes Recognized:"
- for _, classModule in pairs(script:GetChildren()) do
- local is_silenced = string.sub(classModule.Name, 1, 2) == silence_module
- if (not classModule:IsA("ModuleScript")) or is_silenced then continue end
- local success, class = pcall(require, classModule)
- if not success then continue end
- class_debug ..= class_debug and "\n\t\t\t\t\t\t\t\t"..class.name or ""
- bases.classes[class.name] = {function(...) return createObject(class, ...) end, class}
- end
- if debug_enabled then print(class_debug) else class_debug = nil end
- end
- -- Setting up the class management proxy.
- local bases_proxy = newproxy(true)
- local bases_meta = getmetatable(bases_proxy)
- bases_meta.__metatable = "Class manager."
- bases_meta.__call = function(_, ...)
- local args = {...}
- local intention = args[1]
- if intention == "setup" then
- return setup_class(unpack(args, 2))
- elseif intention == "modules" then
- return bases.Functions, bases.Signal
- else
- -- Class modules wrapper :
- load_classes()
- return {
- GetConstructor = function(className)
- local class = bases.classes[className]
- if class then
- return class[1]
- end
- error(string.format('Unable to find a constructor for class "%s"', className), 2)
- end,
- GetObject = function(instance)
- local className = instance:GetAttribute("ClassName")
- local class = bases.classes[className]
- if class then
- return class[2].getObjectFromKey(instance)
- else
- return instance
- end
- end,
- }
- end
- end
- bases_meta.__newindex = function()
- error("Can't modify read only userdata.", 2)
- end
- bases_meta.__index = function(_, key)
- if key == "classes" then return end
- return bases[key]
- end
- return bases_proxy
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement