-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ccd885d
Showing
4 changed files
with
357 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Copyright (c) 2015 Pavel Batečko (ShiraNai7) | ||
|
||
Permission is hereby granted, free of charge, to any person | ||
obtaining a copy of this software and associated documentation | ||
files (the "Software"), to deal in the Software without | ||
restriction, including without limitation the rights to use, | ||
copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the | ||
Software is furnished to do so, subject to the following | ||
conditions: | ||
|
||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
Lua object model | ||
================ | ||
|
||
Simple object model implementation in Lua (~100 lines of code, including comments). | ||
|
||
Inspired by [http://lua-users.org/wiki/SimpleLuaClasses](http://lua-users.org/wiki/SimpleLuaClasses) | ||
|
||
|
||
## Features | ||
|
||
- classes | ||
- constructors | ||
- destructors | ||
- inheritance | ||
- instanceof | ||
- parent method calls | ||
|
||
|
||
## Requirements | ||
|
||
- Lua 5.2 or newer | ||
|
||
|
||
## Installation | ||
|
||
Using LuaRocks: | ||
|
||
luarocks install object-model | ||
|
||
|
||
## Module method overview | ||
|
||
- `class([parentClass]): table` | ||
- create a new class, optionally inheriting methods and properties of another one | ||
- `instanceof(object, class): boolean` | ||
- check if the given object is an instance of the given class or has that class as | ||
one of its parents | ||
- `new(class, ...): object` | ||
- create an instance of the given class and invoke its constructor | ||
- any additional arguments will be passed to the constructor | ||
- should not be used directly, invoke the class table instead (refer to the *Instantiating a class* section) | ||
- `super(object, methodName, ...): mixed` | ||
- invokes a parent method | ||
- this is the default implementation of `object:super(method, ...)` | ||
|
||
|
||
## Feature documentation | ||
|
||
Let's assume you have imported the `ObjectModel` module like this: | ||
|
||
local o = require 'ObjectModel' | ||
|
||
|
||
### Creating a new class | ||
|
||
The class function returns a new table that you can populate with your methods | ||
and properties. | ||
|
||
MyClass = o.class() | ||
|
||
|
||
### Inheritance | ||
|
||
If another class is passed to the `class()` function, all of its methods | ||
and properties are inherited. | ||
|
||
MyClass = o.class(OtherClass) | ||
|
||
Internally, a shallow copy of the parent class is created for performance reasons. | ||
Therefore modifications of the parent class at a later point will NOT be propagated | ||
to the child classes. | ||
|
||
|
||
### Prototype properties | ||
|
||
Prototype properties are available in all instances of the class. | ||
|
||
MyClass.foo = 'bar' | ||
|
||
**Warning!** Do not put tables into prototype properties, unless you want the table | ||
to be shared across all the instances. If you need to initialize a table property | ||
per-instance, do so in the constructor. | ||
|
||
|
||
### Static properties | ||
|
||
There is no separate namespace for static properties. All prototype properties are | ||
defined in the class table, therefore can be accessed without instantiating the class. | ||
|
||
MyClass.staticFoo = 'bar' | ||
|
||
print(MyClass.staticFoo) -- prints: bar | ||
|
||
|
||
### Methods | ||
|
||
Methods are defined the same way as prototype properties. | ||
|
||
MyClass.doSomething = function(self) | ||
-- do something, self points to the instance | ||
end | ||
|
||
However, one can take advantage of Lua's syntactic sugar to make method definitions prettier: | ||
|
||
function MyClass:doSomething() | ||
-- do something, self points to the instance | ||
end | ||
|
||
|
||
### Static methods | ||
|
||
All methods are defined in the class table (same as prototype properties), therefore can be | ||
accessed and called without instantiating the class. | ||
|
||
function MyClass:doSomethingStatic() | ||
-- self points to MyClass | ||
end | ||
|
||
MyClass:doSomethingStatic() -- calling a static method | ||
|
||
|
||
### Constructors | ||
|
||
Constructor is a special method that is invoked when a class is being instantiated. | ||
|
||
function MyClass:constructor(arg) | ||
-- self points to the instance | ||
-- arg is the first argument passed to the constructor, and so on | ||
end | ||
|
||
|
||
### Destructors | ||
|
||
Destructor is a special method that is invoked when an instance is being garbage-collected | ||
by Lua. | ||
|
||
function MyClass:destructor() | ||
-- self points to the instance | ||
-- no arguments are passed | ||
end | ||
|
||
Destructors are implemented using the `__gc` metamethod. | ||
|
||
|
||
### Instantiating a class | ||
|
||
To create an instance of a class, simply call the class table as a function. | ||
|
||
local obj = MyClass('something') | ||
|
||
All arguments passed to this function are forwarded to the constructor. | ||
|
||
|
||
### Instanceof | ||
|
||
To check whether an object is instance of a specific class or has that class as one of its parents, use the `instanceof()` function. | ||
|
||
local obj = MyClass() | ||
|
||
if o.instanceof(obj, MyClass) then | ||
print('obj is instance of MyClass') | ||
end | ||
|
||
|
||
### Calling parent methods | ||
|
||
If a class has inherited from another and overridden some of its methods, these methods can be | ||
invoked using the `:super(methodName, ...)` method. | ||
|
||
BaseClass = o.class() | ||
|
||
function BaseClass:constructor(foo) | ||
self.foo = foo | ||
end | ||
|
||
DerivedClass = o.class(BaseClass) | ||
|
||
function DerivedClass:constructor(foo, bar) | ||
self:super('constructor', foo) -- invoke the parent constructor | ||
self.bar = bar | ||
end | ||
|
||
local obj = DerivedClass('hello', 'world') | ||
|
||
print(obj.foo, obj.bar) -- prints: hello world | ||
|
||
|
||
### Metamethods | ||
|
||
A class is actually a metatable of its instances. This allows metamethods to be defined the same | ||
way as any other methods. | ||
|
||
function MyClass:__tostring() | ||
return 'stringified!' | ||
end | ||
|
||
local obj = MyClass() | ||
|
||
print(obj) -- prints: stringified! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package = 'object-model' | ||
version = '0.1.0-1' | ||
source = { | ||
url = 'git://github.com/ShiraNai7/lua-object-model.git', | ||
tag = 'v0.1.0', | ||
} | ||
description = { | ||
summary = "Simple object model implementation in Lua", | ||
detailed = [[ | ||
Simple object model implementation in Lua (~100 lines of code, including comments). | ||
Inspired by http://lua-users.org/wiki/SimpleLuaClasses | ||
]], | ||
homepage = 'https://github.com/ShiraNai7/lua-object-model', | ||
maintainer = 'ShiraNai7', | ||
license = 'MIT', | ||
} | ||
dependencies = { | ||
'lua >= 5.2', | ||
} | ||
build = { | ||
type = 'builtin', | ||
modules = { | ||
['ObjectModel'] = 'src/ObjectModel.lua', | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
-- | ||
-- Lua object model implementation | ||
-- | ||
|
||
--- Create an instance of the given class | ||
-- | ||
-- @param class the class being constructed | ||
-- @param ... constructor arguments | ||
-- @return table the object | ||
local function new(class, ...) | ||
local object = {} | ||
|
||
setmetatable(object, class) | ||
|
||
-- invoke constructor of the class | ||
if class.constructor then | ||
class.constructor(object, ...) | ||
elseif class._parent and class._parent.constructor then | ||
class._parent.constructor(object, ...) | ||
end | ||
|
||
return object | ||
end | ||
|
||
--- Invoke a parent method | ||
-- | ||
-- @param object the current object | ||
-- @param methodName the parent method name | ||
-- @param ... arguments for the parent method | ||
-- @return the return value(s) of the parent method | ||
local function super(object, methodName, ...) | ||
return object._parent[methodName](object, ...) | ||
end | ||
|
||
--- See if an object is an instance of the given class | ||
-- | ||
-- @param object the object to verify | ||
-- @param classToCompare the class to compare against | ||
-- @return boolean | ||
local function instanceof(object, classToCompare) | ||
local class = getmetatable(object) | ||
|
||
while class do | ||
if class == classToCompare then | ||
return true | ||
end | ||
|
||
class = class._parent | ||
end | ||
|
||
return false | ||
end | ||
|
||
--- Object destructor handler | ||
-- | ||
-- This is the __gc implementation and should not be called manually. | ||
-- | ||
-- @param object instance that is being destructed | ||
local function objectGarbageCollect(object) | ||
if object.destructor then | ||
object:destructor() | ||
end | ||
end | ||
|
||
--- Class table factory | ||
-- | ||
-- @param parent class definition to inherit from | ||
-- @return class table | ||
local function class(parent) | ||
local class = {} | ||
|
||
-- process the parent | ||
if parent then | ||
-- create a shallow copy of the parent class | ||
for i, v in pairs(parent) do | ||
class[i] = v | ||
end | ||
|
||
class._parent = parent | ||
end | ||
|
||
-- the class will be the metatable for all its instances | ||
-- and they will look up their methods in it | ||
class.__index = class | ||
|
||
if not parent then | ||
class.__gc = objectGarbageCollect | ||
end | ||
|
||
if parent then | ||
class.super = super | ||
end | ||
|
||
-- create a meta table for the class | ||
-- too hook the <class>(<args>) mechanism | ||
local meta = { | ||
__call = new | ||
} | ||
setmetatable(class, meta) | ||
|
||
return class | ||
end | ||
|
||
-- return the module table | ||
return { | ||
class = class, | ||
instanceof = instanceof, | ||
new = new, | ||
super = super, | ||
} |