luna offers elegant syntax which allows you to build beautiful object oriented programs with ease.
- Supports multiple object inheritance, avoiding ambiguity between parent-classes
- Supports all versions of Lua
- Supports accessors and mutators
- Offers a natural transition between private and public variables
- Supports static methods
- Definitions follow a C# like structure
Download the source file and place it in your projects directory. require
the module and store it in the variable class
local class = require'luna'
Classes are defined as follows
local class = require'luna'
local planet = class {
}
This module offers classes a private and public scope. Private variables can only be indexed from within the definition while public variables can be indexed outside of the definition. Unlike the public scope, the private scope will not error when you attempt to set or get an index.
local ceres = planet()
print(ceres.PrivateVariable)
>> error PrivateVariable is not a valid member of planet
...but from the definition itself
print(this.PrivateVariable)
>> nil
When indexing a variable from the private scope any metamethods (index or newindex) that you have defined will not be invoked.
Properties are required to remain whatever type they are defined as, tables, userdatas and variable types should be defined using accessors.
local planet = class {
Name = "";
Magnitude = 0;
}
local ceres = planet()
ceres.Name = "Ceres"
ceres.Magnitude = 3.36
print(ceres.Name, ceres.Magnitude)
>> Ceres, 3.36
Accessors are useful when you wish to store a table, userdata or value of unknown type. The get
function is called when the user wants to retrieve the value
of the variable. The set
function is called when the user attempts to set the value
of the variable. Both are given the object as the first parameters, while set is also given the value the user wishes to set your variable to.
local planet = class {
Radius = 0;
SurfaceArea = {
get = function (this)
return 4 * math.pi * this.Radius * this.Radius
end,
set = function (this, value)
this.Radius = math.sqrt(value / (4 * math.pi))
end
}
}
local ceres = planet()
ceres.Radius = 473000
print(ceres.SurfaceArea)
>> 2811461531180
Methods are functions which can be called on your class, the parameters given are the object followed by the parameters the method was called with.
local planet = class {
Mass = 0;
GetGravitationalForce = function (this, distance)
return (this.Mass * 6.67e-11) / (distance * distance)
end;
}
local ceres = planet()
ceres.Mass = 9.393e20
print(ceres:GetGravitationalForce(473000))
>> 0.28003213709443
...or from the definition
this.Mass = 9.393e20
print(this.GetGravitationalForce(473000))
>> 0.28003213709443
The __construct
method is called when a new object is created. It allows you to set any private variables and prepare the class for use. It's parameters will be the object itself followed by any variables passed into the instance function.
local planet = class {
Name = "";
Radius = 0;
__construct = function (this, name, radius)
this.Name = name
this.Radius = radius
end
}
local ceres = planet("Ceres", 473000)
print(ceres.Name, ceres.Radius)
>> Ceres, 473000
This module supports metamethods which can be added to your definition.
local planet = class {
Name = "";
__tostring = function (this)
return this.Name
end;
}
The __index
metamethod will override any errors that may have occured if it did not exist, it is up to the user defining the class to impliment their own.
The __newindex
metamethod is called as soon as the user attempts to set a value. If an error occurs then the internal code will not continue executing and the value or accessor will not be set.
Both these methods are ignored when indexing private variables.
This module supports multiple inheritance which means a class can inherit many other classes.
local planet = class {
Age = 0;
Name = "";
}
local solarSystem = class {
DistanceFromSun = 0;
}
local localPlanet = class (solarSystem, planet) {
ShortestDistanceFromEarth = 0;
LongestDistanceFromEarth = 0;
}
...or to just inherit multiple classes (the braces are required)
local localPlanet = class (solarSystem, planet) {}
In the case of two inherited classes having a different value for a property, the class that is first in the list of inherited classes will be considered more important and therefore have its value used. This is also the case for metamethods.
Static functions and variables exist within the definition itself rather than per object. They can be added to the definition in the same way that any other method or property is. It is up to you to ensure you know what is static and what is not.
local someClass = class {
StaticMethod = function (msg)
print(msg)
end
}
someClass.StaticMethod("Hello world!")
>> Hello world!
Reflection allows you to view information about a class.
local planet = class {
Age = 0;
Name = "";
}
local properties = planet:GetProperties()
for i, v in pairs(properties) do
print(properties)
end
>> Age 0
>> Name [empty_string]
If you feel offended by the fact I suggested that Ceres is a planet, pretend it's the 1800's.
MIT License Copyright (c) 2016 Brad Sharp