Last active
December 18, 2015 06:09
-
-
Save markandgo/5738172 to your computer and use it in GitHub Desktop.
A class system with a novel constructor
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
-- simple class | |
------------------------------------------------- | |
local mixin_reserved = { | |
['new'] = true, | |
['onMixin'] = true, | |
['__type'] = true, | |
['__index'] = true, | |
} | |
local base = {__type = 'Object'} | |
base.__index = base | |
base._G = _G | |
setmetatable(base,{__index = _G}) | |
function base.__call(class,...) | |
local obj = {} | |
setmetatable(obj,class) | |
if class.new then | |
local old_env = getfenv(class.new) | |
setfenv(class.new,obj) | |
class.new(obj,...) | |
setfenv(class.new,old_env) | |
end | |
return obj | |
end | |
function base.new() | |
end | |
function base.type(obj) | |
return obj.__type | |
end | |
function base.typeOf(obj,name) | |
while obj do | |
if obj.__type == name then return true end | |
local meta = getmetatable(obj) | |
obj = meta and meta.__index | |
end | |
return false | |
end | |
function base:extend(parent) | |
parent.__call = base.__call | |
return setmetatable(self,parent) | |
end | |
function base:mixin(source,...) | |
local recur | |
recur = function(self,source) | |
local meta = getmetatable(source) | |
local index = meta and meta.__index | |
if index then recur(self,index) end | |
for i,v in pairs(source) do | |
if not mixin_reserved[i] then self[i] = v end | |
end | |
end | |
recur(self,source) | |
if source.onMixin then | |
source:onMixin(self,...) | |
end | |
return self | |
end | |
function base.init(class,onInit) | |
setfenv(onInit,class) | |
onInit(class) | |
return class | |
end | |
local function new(name) | |
local class = {__type = name} | |
class.__index = class | |
return setmetatable(class,base) | |
end | |
class = setmetatable({},{__call = function(_,name) return new(name) end}) | |
function class.extend(child,parent) | |
if type(child) == 'string' then return class(child):extend(parent) end | |
base.extend(child,parent) | |
end | |
function class.mixin(destination,source) | |
base.mixin(destination,source) | |
end |
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
require 'class' | |
-- class definition | |
person = class 'person' :init(function(self) | |
-- class method | |
function getHeight(self) | |
print(self:type()..' is '..self.height) | |
end | |
-- another method | |
function getWeight(self) | |
print(self:type()..' is '..self.weight) | |
end | |
-- self is by default refers to class "person" | |
self.weight = 'fat' | |
-- self is also implied | |
self.weight = nil | |
weight = 'fat' | |
-- optional constructor used when creating a new object | |
-- self is also implied here and refers to the new object | |
function new(self,height) | |
-- self refers to class object | |
self.height = height | |
end | |
end) | |
shortperson = class 'shortperson' | |
:extend(person) | |
:init(function(self) | |
-- default class height | |
height = 'short' | |
function new(self) | |
-- recursion and environment test | |
if not _G.shortperson2 then | |
weight = 'thin' | |
_G.shortperson2 = true | |
_G.shortperson2 = shortperson() | |
end | |
end | |
end) | |
tall = class 'tall' :init(function(self) | |
function onMixin(self,dest) | |
dest.height = self:type() | |
end | |
end) | |
person1 = person 'average' | |
person1:getHeight() | |
person1:getWeight() | |
shortperson1 = shortperson() | |
shortperson1:getHeight() | |
shortperson1:getWeight() | |
shortperson2:getHeight() | |
shortperson2:getWeight() | |
person2 = person() | |
person2:mixin(tall) | |
person2:getHeight() | |
person2:getWeight() | |
assert(person:typeOf 'person') | |
assert(person1:typeOf 'person') | |
assert(shortperson:typeOf 'shortperson') | |
assert(shortperson:typeOf 'person') | |
assert(shortperson1:typeOf 'shortperson') | |
assert(shortperson1:typeOf 'person') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment