Minimalistic approach to OOP by instantiating objects directly from user-defined classes. Works with Lua 5.1+ and LuaJIT.
The module returns a table, which can be called in order to create a new object:
local Object = require('Object')
local myobject = Object()
You can optionally pass in a user-defined class, as well as varargs that will be proxied to the constructor (if defined):
local Object = require('Object')
local MyClass = {
_init = function(self, a, b)
print(a, b)
end,
}
local myobject = Object(MyClass, "hello", "world") -- hello world
MyClass:_init(...)
MyClass:_get_XXX()
MyClass:_set_XXX(value)
MyClass:_on_XXX(...)
Object:rawget(key)
Object:get(key)
Object:rawset(key, value, publish)
Object:set(key, value)
Object:publish(event, ...)
Object:subscribe(event, callback)
Object:unsubscribe(event, callback)
Object:once(event, callback)
The class constructor. The arguments passed here are directly proxied from the
Object(class, ...)
call.
local Object = require('Object')
local MyClass = {}
function MyClass:_init(a, b)
self.sum = a + b
end
local myobject = Object(MyClass, 1, 2)
print(myobject.sum) -- 3
Class defined getter on property XXX
. When defined, accessing myobject.XXX
will return the result from the getter. You can use Object:rawget
to bypass getters.
local Object = require('Object')
local MyClass = {}
function MyClass:_get_myprop()
return 42
end
local myobject = Object(MyClass)
print(myobject.myprop) -- 42
Class defined setter on property XXX
. When defined, assigning
myobject.XXX = myvalue
will call the setter with myvalue
. You can use
Object:rawset
to bypass setters. change_XXX
events
are not automatically published after custom setters and must be published manually.
local Object = require('Object')
local MyClass = {}
function MyClass:_set_myprop(value)
self:rawset('myprop', value + 10)
end
local myobject = Object(MyClass)
myobject.myprop = 42
print(myobject.myprop) -- 52
Class defined event handler. When defined, gets called whenever the event XXX is published.
local Object = require('Object')
local MyClass = {}
function MyClass:_on_change_myprop(value)
print('myprop has changed to: ' .. tostring(value))
end
function MyClass:_on_myevent()
print('emitted myevent')
end
local myobject = Object(MyClass)
myobject.myprop = 42 -- myprop has changed to: 42
myobject:publish('myevent') -- emitted myevent
Gets the value indexed by key
from the object without invoking getters. First
checks for key
in the object, then searches for key
in the class, and
finally defaults to indexing Object
directy.
local Object = require('Object')
local MyClass = {}
function MyClass:_get_myprop(value)
return 42
end
local myobject = Object(MyClass)
myobject.myprop = 24
print(myobject.myprop) -- 42
print(myobject:rawget('myprop')) -- 24
The getter function for the object. Calling this is equivalent to simply accessing the key directly.
local Object = require('Object')
local myobject = Object()
-- equivalent
print(myobject.mykey)
print(myobject:get('mykey'))
Sets the index of key
to value
without invoking setters. If publish
is
set to true, publishes a change_XXX
event (where XXX is the value of key
)
that passes the new and old values.
local Object = require('Object')
local MyClass = {}
function MyClass:_set_myprop(value)
self:rawset('myprop', value + 10)
end
local myobject = Object(MyClass)
myobject.myprop = 42
print(myobject.myprop) -- 52
myobject:rawset('myprop', 42)
print(myobject.myprop) -- 42
local Object = require('Object')
local MyClass = {}
function MyClass:_on_change_myprop(new_value, old_value)
print(new_value, old_value)
end
local myobject = Object(MyClass)
myobject:rawset('myprop', 42, true) -- 42 nil
myobject:rawset('myprop', 24, true) -- 24 42
The setter function for the object. Calling this is equivalent to simply assigning the key directly.
local Object = require('Object')
local myobject = Object()
-- equivalent
myobject.mykey = 42
myobject:set('mykey', 42)
Invokes all subscribers of event
, passing in
the provided varargs to each subscription callback.
local Object = require('Object')
local myobject = Object()
myobject:subscribe('myevent', function(a, b)
print(a + b)
end)
myobject:publish('myevent', 1, 2) -- 3
Adds a callback to be called whenever event
is published.
Returns the callback itself (useful for unsubscribing).
The same function cannot be subscribed to the same event multiple times (no duplicate subscriptions).
local Object = require('Object')
local myobject = Object()
myobject:subscribe('myevent', function(a, b)
print(a + b)
end)
myobject:publish('myevent', 1, 2) -- 3
Removes a callback from being called when event
is published.
local Object = require('Object')
local myobject = Object()
local subscription = myobject:subscribe('myevent', function(a, b)
print(a + b)
end)
myobject:publish('myevent', 1, 2) -- 3
myobject:unsubscribe('myevent', subscription)
myobject:publish('myevent', 1, 2) -- nothing prints!
Adds a callback to be called the next time event
is published.
This callback only fires once and then immediately unsubscribes itself. Similarly to
Object:subscribe, this returns the subscribed function
and can be removed via Object:unsubscribe (note that
the subscribed function is not the same as callback
). Unlike
Object:subscribe, the same callback may be registered
multiple times.
local Object = require('Object')
local myobject = Object()
local subscription = myobject:once('myevent', function()
print('hello world')
end)
myobject:publish('myevent') -- hello world
myobject:publish('myevent') -- nil
This repo also contains a Class.lua
helper, which is simply a light wrapper
that allows calling user-defined classes directly to instantiate a corresponding
Object. Note that this requires overriding the metatable for the class:
local Class = require('Class')
local MyClass = Class()
function MyClass:_init(a, b)
self.sum = a + b
end
-- equivalent to Object(MyClass, 1, 2)
local myobject = MyClass(1, 2)
You can also pass the class definition directly to Class
:
local Class = require('Class')
local MyClass = Class({
_init = function(self, a, b)
self.sum = a + b
end
})