Lua の OOP , クラスベース
function Class(obj)
-- metatable も __index も同じにする (再帰参照)
-- 演算子オーバーロードも直感的に書けるように
obj.__index = obj
-- superclass の設定
setmetatable(obj, { __index = obj.super})
return setmetatable({
new = function(...)
local newObj = {}
setmetatable(newObj, obj)
newObj:initialize(unpack(arg))
return newObj
end
}, obj)
end
List = Class { super = nil,
__tostring = function ()
return "#<Class List>"
end,
initialize = function (self, ...)
self.firstIndex = 0
self.lastIndex = -1
for i,v in ipairs(arg) do self:push(v) end
end,
unshift = function (self, value)
self.firstIndex = self.firstIndex - 1
self[self.firstIndex] = value
return self
end,
push = function (self, value)
self.lastIndex = self.lastIndex + 1
self[self.lastIndex] = value
return self
end,
shift = function (self)
local first = self.firstIndex
if first > self.lastIndex then
return nil
end
local value = self[first]
self[first] = nil
self.firstIndex = first + 1
return value
end,
pop = function (self)
local last = self.lastIndex
if self.firstIndex > last then
return nil
end
local value = self[last]
self[last] = nil
self.lastIndex = last - 1
return value
end,
clear = function (self)
for i,v in ipairs(self) do
self[i] = nil
end
self.firstIndex = 0
self.lastIndex = -1
end,
size = function (self)
return self.lastIndex - self.firstIndex + 1
end,
first = function (self)
return self[self.firstIndex]
end,
last = function (self)
return self[self.lastIndex]
end,
}
l = List.new()
print(l)
-- basic tests
l:push(1)
l:push(2)
assert(l:pop() == 2)
assert(l:pop() == 1)
l:push(1)
l:unshift(2)
assert(l:size() == 2)
assert(l:first() == 2)
assert(l:last() == 1)
assert(l:shift() == 2)
assert(l:shift() == 1)
assert(l:size() == 0)
l:push(1)
assert(l:size() == 1)
l:clear()
assert(l:size() == 0)
-- multi-obj tests
l1 = List.new()
l1:push(1)
l:push(1)
l1:push(2)
l:push(2)
assert(l1:pop() == 2)
assert(l:pop() == 2)
assert(l1:pop() == 1)
assert(l:pop() == 1)
l2 = List.new(1, 2, 3, 4, 5)
assert(l2:pop() == 5)
assert(l2:pop() == 4)
assert(l2:shift() == 1)
assert(l2:shift() == 2)
assert(l2:pop() == 3)
-- prototype 書きかえてみる
getmetatable(l).hoge = function ()
return "hoge"
end
assert(l:hoge() == "hoge")
List2 = Class { super = List,
__tostring = function ()
return "#<Class List2>"
end,
initialize = function (self, values)
self.super.initialize(self, values)
end,
test = function (self, str)
print(str)
self:push(str)
end
}
l2 = List2.new()
print(l2)
l2:test("hoe")
l2:push(1)
l2:push(2)
assert(l2:pop() == 2)
assert(l2:pop() == 1)
print "Tests are completed"どうだろ