Skip to content

PseudoInstance

Summary

Rigidly defined PseudoInstance class system based upon Roblox Instances. The goal is to create encapsulated instances whose state is simply a function of its externally accessible properties. In other words, a cloned instance should render exactly the same as the original instance.

Library API

PseudoInstance.new

PseudoInstance PseudoInstance.new(string ClassName, ...)

Instantiates a new PseudoInstance of type ClassName. Arguments (...) are passed to the Init constructor.

Example

local PseudoInstance = Resources:LoadLibrary("PseudoInstance")

local Shadow = PseudoInstance.new("Shadow")
Shadow.Elevation = 8 -- this will cast to Enumeration.ShadowElevation.Elevation8
Shadow.Parent = Background -- Whatever Gui you wish

Note

Only classes which have been Registered may be instantiated. If you attempt to instantiate a class which has not been Registered, it will call Resources:LoadLibrary(ClassName) and try again.

PseudoInstance.Make

PseudoInstance PseudoInstance.Make(string ClassName, dictionary Properties, ...)

PseudoInstance.new wrapper which automatically assigns properties in dictionary Properties. Arguments passed to (...) must be dictionaries of Properties too. The only downside is you cannot pass any parameters to the Init constructor, but you probably don't need to. See the Make library's documentation for more information, as it works identically.

Example

local PseudoInstance = Resources:LoadLibrary("PseudoInstance")

local Shadow = PseudoInstance.Make("Shadow", {
    Elevation = 8; -- this will cast to Enumeration.ShadowElevation.Elevation8
    Parent = Background; -- Parent is set last
})

PseudoInstance:Register

PseudoTemplate PseudoInstance:Register(string ClassName, table Template, table InheritsFrom = PseudoInstance)

Registers a new class of PseudoInstances which can be instantiated via PseudoInstance.new(ClassName). Please read all the documentation in the example below:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Resources = require(ReplicatedStorage:WaitForChild("Resources"))
local Typer = Resources:LoadLibrary("Typer")
local Enumeration = Resources:LoadLibrary("Enumeration")
local PseudoInstance = Resources:LoadLibrary("PseudoInstance")

Enumeration.PastaStyle = {"Spaghetti", "Fusilli", "Penne", "Rigatoni", "Rotelle"}

local ClassNameTemplate = PseudoInstance:Register("ClassName", {
    Events = {
        -- These are the events (see: Signal) of the PseudoInstance. These can be Connect()ed to,
        -- Fire()d, Wait()ed on, etc

        -- implicit numerical indeces define an Event member without Constuctors or Destructors
        "OnPressed";

        OnRightPressed = function(self)
            -- self is the PseudoInstance for which this Event is being constructed.
            -- Must return two functions, one constuctor and
            -- one destructor with which to call Signal.new (see docs)
            return function()
            end, function()
            end
        end;
    };

    Internals = {
        -- These values are internal-only and not externally accessible

        -- implicit numerical indeces are set by default to false, to be defined at run-time
        "NumChildren";

        Set = function(self, Bool) -- These can be set to anything
            return Bool == true and 1 or 0
        end;
    };

    Methods = {
        Kill = function(self)
            -- Methods and the Init functions are sent an internal-access table version of self

            self.OnPressed:Fire() -- Internal Signal-access has full control
            return self:Set(true)
        end;

        Destroy = function(self, ...)
            print("We are being destroyed!")

            -- self:super() calls the superclass's method by the name of the first parameter
            -- In this case, this calls Superclass.Destroy(self, ...)
            self:super("Destroy", ...)
        end;

        -- When set to 0, it makes the class Abstract
        FunctionWhichMustBeImplementedByAClassThatInheritsFromThisOne = 0;
    };

    Properties = {
        -- Can be set to a Typer value for typechecking
        Name = Typer.String;

        -- This is equivalent to the previous declaration
        Name = Typer.AssignSignature(2, Typer.String, function(self, Value)
            self:rawset("Name", Value)
        end)

        -- Can also be constrained to a certain EnumerationType
        Style = Typer.EnumerationOfTypePastaStyle;

        Parent = function(self, Parent)
            -- Always called with the Object and the Property value it is being set to

            -- Do stuff
            self:rawset("Parent", Parent) -- Make sure to rawset the Property to what it should be
        end;
    };

    Init = function(self)
        -- Called by PseudoInstance.new()

        -- Every PseudoInstance comes with a built-in Janitor which is called upon Destruction
        self.Janitor:Add(workspace.ChildAdded:Connect(function() end))


        -- Sets externally-accessible Value of PseudoInstance directly
        -- without calling a Property setting function
        -- This can also be used for read-only values
        self:rawset("IsPlayer", true)

        -- Must be in your init function, to run the constructor in the superclass
        -- Will not exist after the Init function runs if the constructors resolved properly
        self:superinit()
    end;
})

-- Will Error, because `ClassName` is Abstract
print(pcall(PseudoInstance.new, "ClassName"))

local MyClass = PseudoInstance:Register("MyClass", {
    Methods = {
        FunctionWhichMustBeImplementedByAClassThatInheritsFromThisOne = function(self)
        end;
    };

    Init = function(self)
        self:superinit()
    end;
}, ClassNameTemplate)

local MyInstance = PseudoInstance.new("MyClass")
MyInstance.Style = "Rigatoni" -- Gets cast to Enumeration
MyInstance.Style = 3 -- Gets cast to Rigatoni
MyInstance:Kill()

-- Externally, one only may Connect() and Wait() on events
MyInstance.OnPressed:Connect(print)

-- Error: Cannot `Fire` externally.
print(pcall(MyInstance.OnPressed.Fire, MyInstance.OnPressed))

print(pcall(function()
    MyInstance:Set(true)
end)) -- Set does not exist externally

PseudoInstance API

Properties type
Archivable Boolean
Parent OptionalInstance
Name String
ClassName read-only String
Methods
Clone
GetFullName
IsDescendantOf
GetPropertyChangedSignal
FindFirstChild
GetChildren
IsA
Destroy
Events
Changed