Skip to content

Latest commit

 

History

History
303 lines (221 loc) · 7.38 KB

README.md

File metadata and controls

303 lines (221 loc) · 7.38 KB

lua-object

Minimalistic approach to OOP by instantiating objects directly from user-defined classes. Works with Lua 5.1+ and LuaJIT.

Usage

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

API

MyClass:_init(...)

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

MyClass:_get_XXX()

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

MyClass:_set_XXX(value)

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

MyClass:_on_XXX(...)

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

Object:rawget(key)

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

Object:get(key)

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'))

Object:rawset(key, value, publish)

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

Object:set(key, value)

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)

Object:publish(event, ...)

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

Object:subscribe(event, callback)

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

Object:unsubscribe(event, callback)

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!

Object:once(event, callback)

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

Class.lua

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
})