Last active
August 29, 2015 14:08
-
-
Save sclark39/8ddcd4a0ba3de3b922ea to your computer and use it in GitHub Desktop.
Lua class lib with 'base' helper method
This file contains hidden or 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
-- test.lua | |
-- using the class lib and the introspective base helper method | |
class 'A' | |
function A:test() | |
print "Hi" | |
end | |
class 'B' (A) | |
function B:test() | |
base() -- self.base.test( self ) would actually cause a stack overflow when calling C:test() | |
print "Hello" | |
end | |
class 'C' (B) | |
C:test() | |
-- prints | |
-- Hi | |
-- Hello | |
-- test2.lua | |
-- much more performant alternative to get similar 'base' sugar | |
class 'B2' (A) | |
local base = B2.test -- 'B2' here so if subclass gets modified in line above, this doesn't need to be updated | |
function B2:test() | |
base( self ) | |
print "Hello" | |
end | |
class 'C2' (B2) | |
C2:test() | |
-- prints | |
-- Hi | |
-- Hello | |
-- class.lua | |
local function isa( self, name ) | |
repeat | |
if self.__name == name then | |
return true | |
end | |
self = self.__base | |
until not self | |
return false | |
end | |
function class ( name ) | |
local class = { | |
__name = name; | |
isa = isa; | |
} | |
local instance_mt = { __index = class; } | |
class.new = function(...) | |
local instance = setmetatable( {}, instance_mt ) | |
instance:init( ... ) | |
return instance | |
end | |
getfenv( 2 )[ name ] = class | |
return | |
setmetatable( {}, { | |
__call = function(t,superclass) | |
class.__base = superclass | |
setmetatable( class, {__index = superclass } ) | |
end | |
} ) | |
end | |
local getinfo,getlocal,rawget = debug.getinfo, debug.getlocal, rawget -- make local for speed | |
function base( ... ) | |
local methodname,caller,self | |
do -- inspect stack to find caller and self | |
local callerinfo = getinfo(2, "nf") | |
local localname, localval = getlocal(2, 1) | |
assert( callerinfo.namewhat == "method" and localname == "self" and localval ) | |
methodname = callerinfo.name | |
caller = callerinfo.func | |
self = localval | |
end | |
local nextbase,basecall -- loop vals | |
nextbase = self | |
repeat -- find the function that called base | |
basecall = rawget( nextbase, methodname ) | |
if basecall == caller then | |
break | |
end | |
nextbase = nextbase.__base | |
until not nextbase | |
nextbase = nextbase.__base | |
while nextbase do -- call the next one up the inheritence tree | |
basecall = rawget( nextbase, methodname ) | |
if basecall ~= caller then | |
return basecall( self, ... ) | |
end | |
nextbase = nextbase.__base | |
end | |
error( "base() called by non-overrided method" ) | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment