# 30log **Repository Path**: mirrors_LuaDist/mirrors_LuaDist_30log ## Basic Information - **Project Name**: 30log - **Description**: 30 lines library for object orientation in Lua - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-12-09 - **Last Updated**: 2026-02-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 30log ===== [![Build Status](https://travis-ci.org/Yonaba/30log.png)](https://travis-ci.org/Yonaba/30log) __30log__, in extenso *30 Lines Of Goodness* is a minified framework for [object-orientation](http://lua-users.org/wiki/ObjectOrientedProgramming) in Lua. It features __named (and unnamed) classes__, __single inheritance__ and a basic support for __mixins__.
It makes __30 lines__. No less, no more.
__30log__ is [Lua 5.1](http://www.lua.org/versions.html#5.1), [Lua 5.2](http://www.lua.org/versions.html#5.2) compatible. ##Contents * [Download](https://github.com/Yonaba/30log/#download) * [Installation](https://github.com/Yonaba/30log/#installation) * [Quicktour](https://github.com/Yonaba/30log/#quicktour) * [Chained initialisation](https://github.com/Yonaba/30log/#chained-initialisation) * [Mixins](https://github.com/Yonaba/30log/#mixins) * [Printing classes and objects](https://github.com/Yonaba/30log/#printing-classes-and-objects) * [Class Commons support](https://github.com/Yonaba/30log/#class-commons) * [Specification](https://github.com/Yonaba/30log/#specification) * [Source](https://github.com/Yonaba/30log/#source) * [Benchmark](https://github.com/Yonaba/30log/#benchmark) * [Contributors](https://github.com/Yonaba/30log/#contributors) ##Download You can download __30log__ via: ###Bash ```bash git clone git://github.com/Yonaba/30log.git ```` ###Archive * __Zip__: [0.9.0](https://github.com/Yonaba/30log/archive/30log-0.9.0.zip) ( *latest stable, recommended* ) | [older versions](https://github.com/Yonaba/30log/tags) * __Tar.gz__: [0.9.0](https://github.com/Yonaba/30log/archive/30log-0.9.0.tar.gz) ( *latest stable, recommended* ) | [older versions](https://github.com/Yonaba/30log/tags) ###LuaRocks ``` luarocks install 30log ```` ###MoonRocks ```bash luarocks install --server=http://rocks.moonscript.org/manifests/Yonaba 30log ```` ##Installation Copy the file [30log.lua](https://github.com/Yonaba/30log/blob/master/30log.lua) inside your project folder, call it using [require](http://pgl.yoyo.org/luai/i/require) function. It will return a single local function, keeping safe the global environment.
##Quicktour ###Creating a class Creating a new class is fairly simple. Just call the returned function, then add some properties to this class : ```lua class = require '30log' Window = class () Window.x, Window.y = 10, 10 Window.width, Window.height = 100,100 ``` You can also make it shorter, packing the default properties and their values within a table and then pass it as a single argument to the `class` function : ```lua class = require '30log' Window = class { width = 100, height = 100, x = 10, y = 10} ``` ###Named classes Classes can be named.
To name a class, you will have to set the desired name as a string value to the reserved key `__name` : ```lua class = require '30log' Window = class () Window.__name = 'Window' ``` This feature can be quite useful when debugging your code. See the section [printing classes](https://github.com/Yonaba/30log/#printing-classes-and-objects) for more details. ###Instances ####Creating instances You can easily create new __instances__ (objects) from a class using the __default instantiation method__ named `new()`: ```lua appFrame = Window:new() print(appFrame.x,appFrame.y) --> 10, 10 print(appFrame.width,appFrame.height) --> 100, 100 ``` There is a shorter version though. You can call new class itself with parens, __just like a function__ : ```lua appFrame = Window() print(appFrame.x,appFrame.y) --> 10, 10 print(appFrame.width,appFrame.height) --> 100, 100 ``` From the two examples above, you might have noticed that once an object is created from a class, it already shares the properties of his mother class. That's the very basis of `inheritance`. So, by default, the attributes of the newly created object will copy their values from its mother class.

Yet, you can init new objects from a class with custom values for properties. To accomplish that, you will have to implement your own __class constructor__. Typically, it is a method (a function) that will be called whenever the new() method is used from the class to derive a new object, and then define custom attributes and values for this object.
By default, __30log__ uses the reserved key `__init` as a __class constructor__. ```lua Window = class { width = 100, height = 100, x = 10, y = 10} function Window:__init(x,y,width,height) self.x,self.y = x,y self.width,self.height = width,height end appFrame = Window:new(50,60,800,600) -- same as: appFrame = Window(50,60,800,600) print(appFrame.x,appFrame.y) --> 50, 60 print(appFrame.width,appFrame.height) --> 800, 600 ``` `__init` can also be a __table with named keys__.
In that case though, the values of each single object's properties will be taken from this table upon instantiation, no matter what the values passed-in at instantiation would be. ```lua Window = class() Window.__init = { width = 100, height = 100, x = 10, y = 10} appFrame = Window:new(50,60,800,600) -- or appFrame = Window(50,60,800,600) print(appFrame.x,appFrame.y) --> 10, 10 print(appFrame.width,appFrame.height) --> 100, 100 ```` ####Under the hood *30log* classes are metatables of their own instances. This implies that one can inspect the mother/son relationship between a class and its instance via Lua's standard function [getmetatable](http://www.lua.org/manual/5.2/manual.html#pdf-getmetatable). ```lua local aClass = class() local someInstance = aClass() print(getmetatable(someInstance) == aClass) --> true ```` Also, classes are metatables of their derived classes. ```lua local aClass = class() local someDerivedClass = aClass:extends() print(getmetatable(someDerivedClass) == aClass) --> true ```` ###Methods Objects can call their class __methods__. ```lua Window = class { width = 100, height = 100, w = 10, y = 10} function Window:__init(x,y,width,height) self.x,self.y = x,y self.width,self.height = width,height end function Window:set(x,y) self.x, self.y = x, y end function Window:resize(width, height) self.width, self.height = width, height end appFrame = Window() appFrame:set(50,60) print(appFrame.x,appFrame.y) --> 50, 60 appFrame:resize(800,600) print(appFrame.width,appFrame.height) --> 800, 600 ``` Though, objects cannot be used to instantiate new objects. ```lua appFrame = Window:new() aFrame = appFrame:new() -- Creates an error aFrame = appFrame() -- Also creates an error ```` ###Inheritance A class can __inherit__ from any other class using a reserved method named `extends`. Similarly to `class`, this method also takes an optional table with named keys as argument to include __new properties__ that the derived class will implement. The new class will inherit his mother class __properties__ as well as its __methods__. ```lua Window = class { width = 100, height = 100, x = 10, y = 10} Frame = Window:extends { color = 'black' } print(Frame.x, Frame.y) --> 10, 10 appFrame = Frame() print(appFrame.x,appFrame.y) --> 10, 10 ``` A derived class can __redefine any method__ implemented in its base class (or mother class). Therefore, the derived class *still* has access to his mother class methods and properties via a reserved key named `super`.
```lua -- Let's use this feature to build a class constructor for our `Frame` class. -- The base class "Window" Window = class { width = 100, height = 100, x = 10, y = 10} function Window:__init(x,y,width,height) self.x,self.y = x,y self.width,self.height = width,height end -- A method function Window:set(x,y) self.x, self.y = x, y end -- A derived class named "Frame" Frame = Window:extends { color = 'black' } function Frame:__init(x,y,width,height,color) -- Calling the superclass constructor Frame.super.__init(self,x,y,width,height) -- Setting the extra class member self.color = color end -- Redefining the set() method function Frame:set(x,y) self.x = x - self.width/2 self.y = y - self.height/2 end -- An appFrame from "Frame" class appFrame = Frame(100,100,800,600,'red') print(appFrame.x,appFrame.y) --> 100, 100 -- Calls the new set() method appFrame:set(400,400) print(appFrame.x,appFrame.y) --> 0, 100 -- Calls the old set() method in the mother class "Windows" appFrame.super.set(appFrame,400,300) print(appFrame.x,appFrame.y) --> 400, 300 ``` ###Inspecting inheritance `class.is` can check if a given class derives from another class. ```lua local aClass = class() local aDerivedClass = aClass:extends() print(aDerivedClass:is(aClass)) --> true ```` It also returns *true* when the given class is not necessarily the immediate ancestor of the calling class. ```lua local aClass = class() local aDerivedClass = aClass:extends():extends():extends() -- 3-level depth inheritance print(aDerivedClass:is(aClass)) --> true ```` Similarly `instance.is` can check if a given instance derives from a given class. ```lua local aClass = class() local anObject = aClass() print(anObject:is(aClass)) --> true ```` It also returns *true* when the given class is not the immediate ancestor. ```lua local aClass = class() local aDerivedClass = aClass:extends():extends():extends() -- 3-level depth inheritance local anObject = aDerivedClass() print(anObject:is(aDerivedClass)) --> true print(anObject:is(aClass)) --> true ```` ##Chained initialisation In a single inheritance tree, the `__init` constructor can be chained from one class to another.
This is called *initception*.
And, yes, *it is a joke.* ```lua -- A mother class 'A' local A = Class() function A.__init(instance,a) instance.a = a end -- Class 'B', deriving from class 'A' local B = A:extends() function B.__init(instance, a, b) B.super.__init(instance, a) instance.b = b end -- Class 'C', deriving from class 'B' local C = B:extends() function C.__init(instance, a, b, c) C.super.__init(instance,a, b) instance.c = c end -- Class 'D', deriving from class 'C' local D = C:extends() function D.__init(instance, a, b, c, d) D.super.__init(instance,a, b, c) instance.d = d end -- Creating an instance of class 'D' local objD = D(1,2,3,4) for k,v in pairs(objD) do print(k,v) end -- Output: --> a 1 --> d 4 --> c 3 --> b 2 ``` The previous syntax can also be simplified, as follows: ```lua local A = Class() function A:__init(a) self.a = a end local B = A:extends() function B:__init(a, b) B.super.__init(self, a) self.b = b end local C = B:extends() function C:__init(a, b, c) C.super.__init(self, a, b) self.c = c end local D = C:extends() function D:__init(a, b, c, d) D.super.__init(self, a, b, c) self.d = d end ```` ##Mixins __30log__ provides a basic support for [mixins](http://en.wikipedia.org/wiki/Mixin). This is a powerful concept that can be used to implement a functionality into different classes, even if they do not have any special relationship.
__30log__ assumes a `mixin` to be a table containing a **set of methods** (function).
To include a mixin in a class, use the reserved key named `include`. ```lua -- A mixin Geometry = { getArea = function(self) return self.width, self.height end, resize = function(self, width, height) self.width, self.height = width, height end } -- Let's define two unrelated classes Window = class {width = 480, height = 250} Button = class {width = 100, height = 50, onClick = false} -- Include the "Geometry" mixin inside the two classes Window:include(Geometry) Button:include(Geometry) -- Let's define objects from those classes local aWindow = Window() local aButton = Button() -- Objects can use functionalities brought by the mixin. print(aWindow:getArea()) --> 480, 250 print(aButton:getArea()) --> 100, 50 aWindow:resize(225,75) print(aWindow.width, aWindow.height) --> 255, 75 ```` Note that, when including a mixin into a class, **only methods** (functions, actually) will be imported into the class. Also, objects cannot include mixins. ```lua aWindow = Window() aWindow:include(Geometry) -- produces an error ```` ##Printing classes and objects Any attempt to [print](http://pgl.yoyo.org/luai/i/print) or [tostring](http://pgl.yoyo.org/luai/i/tostring) a __class__ or an __instance__ will return the name of the class as a string. This feature is mostly meant for debugging purposes. ```lua -- Let's illustrate this, with an unnamed __Cat__ class: -- A Cat Class local Cat = class() print(Cat) --> "class(?):" local kitten = Cat() print(kitten) --> "object(of ?):" ```` The question mark symbol `?` means here the printed class is unnamed (or the object derives from an unnamed class). ```lua -- Let's define a named __Cat__ class now: -- A Cat Class local Cat = class() Cat.__name = 'Cat' print(Cat) --> "class(Cat):" local kitten = Cat() print(kitten) --> "object(of Cat):" ```` ##Class Commons [Class-Commons](https://github.com/bartbes/Class-Commons) is an interface that provides a common API for a wide range of object orientation libraries in Lua. There is a small plugin, originally written by [TsT](https://github.com/tst2005) which provides compatibility between *30log* and *Class-commons*.
See here: [30logclasscommons](http://github.com/Yonaba/30logclasscommons). ##Specification You can run the included specs with [Telescope](https://github.com/norman/telescope) using the following command from the root foolder: ``` lua tsc -f specs/* ``` ###Source ###30logclean __30log__ was initially designed for minimalistic purposes. But then commit after commit, I came up with a source code that was obviously surpassing 30 lines. As I wanted to stick to the "30-lines" rule, I had to use an ugly syntax which not much elegant, yet 100 % functional.
For those who might be interested though, the file [30logclean.lua](https://github.com/Yonaba/30log/blob/master/30logclean.lua) contains the full source code, properly formatted and well indented for your perusal. ###30logglobal The file [30logglobal.lua](https://github.com/Yonaba/30log/blob/master/30logglobal.lua) features the exact same source as the original [30log.lua](https://github.com/Yonaba/30log/blob/master/30log.lua), excepts that it sets a global function named `class`. This is convenient for Lua-based frameworks such as [Codea](http://twolivesleft.com/Codea/). ##Benchmark Performance tests featuring classes creation, instantiation and such have been included. You can run these tests with the following command with Lua from the root folder, passing to the test script the actual implementation to be tested. ```lua lua performance/tests.lua 30log ```` Find [here an example of output](https://github.com/Yonaba/30log/tree/master/performance/results.md). ##Contributors * [TsT2005](https://github.com/tst2005), for the original Class-commons support. ##License This work is under [MIT-LICENSE](http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2012-2014 Roland Yonaba 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. [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/Yonaba/30log/trend.png)](https://bitdeli.com/free "Bitdeli Badge")