From 37e25d297a1b33975f7107c56e7e60630ac00f93 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:04:13 +0900 Subject: [PATCH 01/16] add super implementation --- lua/wikis/commons/Class.lua | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lua/wikis/commons/Class.lua b/lua/wikis/commons/Class.lua index 6232174d916..c857708c17b 100644 --- a/lua/wikis/commons/Class.lua +++ b/lua/wikis/commons/Class.lua @@ -51,6 +51,36 @@ function Class.new(base, init) instance.__index = instance + instance.super = function(object) + local proxy = {} + local proxyMT = { + __index = function (obj, param) + local objVal = rawget(obj, param) + if objVal then + return objVal + end + return base and base[param] + end, + __newindex = object, + __add = base and base.__add, + __sub = base and base.__sub, + __mul = base and base.__mul, + __div = base and base.__div, + __mod = base and base.__mod, + __pow = base and base.__pow, + __unm = base and base.__unm, + __concat = base and base.__concat, + __eq = base and base.__eq, + __lt = base and base.__lt, + __le = base and base.__le, + __pairs = base and base.__pairs, + __ipairs = base and base.__ipairs, + __tostring = base and base.__tostring, + } + setmetatable(proxy, proxyMT) + return proxy + end + local metatable = {} metatable.__call = function(class_tbl, ...) From b60ad1eace219f3b16d534c66704f109c785fec9 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:16:20 +0900 Subject: [PATCH 02/16] make instanceOf to work with super --- lua/wikis/commons/Class.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/wikis/commons/Class.lua b/lua/wikis/commons/Class.lua index c857708c17b..8579fda2d26 100644 --- a/lua/wikis/commons/Class.lua +++ b/lua/wikis/commons/Class.lua @@ -61,6 +61,7 @@ function Class.new(base, init) end return base and base[param] end, + _base = base, __newindex = object, __add = base and base.__add, __sub = base and base.__sub, From 198f77ec8dd389fa6edae6c59e7320130dc404a6 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:17:42 +0900 Subject: [PATCH 03/16] tests --- lua/spec/class_spec.lua | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lua/spec/class_spec.lua b/lua/spec/class_spec.lua index c7ee412a86e..2c3fd6395c1 100644 --- a/lua/spec/class_spec.lua +++ b/lua/spec/class_spec.lua @@ -8,6 +8,8 @@ describe('class', function() return 'Animal' end + Animal.__tostring = Animal.type + function Animal:size() error('abstract') end @@ -48,6 +50,21 @@ describe('class', function() end) end) + describe('super', function() + it('access super methods', function () + local c1 = Cat(5) + + assert.equal('Animal', c1:super():type()) + assert.error(function() return c1:super():numLegs() end) + end) + + it('access instance value from super', function () + local c1 = Cat(5) + + assert.equal(4, c1:super()._size) + end) + end) + describe('instanceOf', function() it('with same class', function () local c1 = Cat(5) @@ -62,5 +79,11 @@ describe('class', function() local a1 = Animal() assert.is_false(Class.instanceOf(a1, Cat)) end) + + it('with super', function () + local c1 = Cat(5) + assert.is_true(Class.instanceOf(c1:super(), Animal)) + assert.is_false(Class.instanceOf(c1:super(), Cat)) + end) end) end) From aecb1818b5f1d2c2979fa84f416eac380a2c06e8 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:22:52 +0900 Subject: [PATCH 04/16] fix expected val in test --- lua/spec/class_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/spec/class_spec.lua b/lua/spec/class_spec.lua index 2c3fd6395c1..b81f389eddc 100644 --- a/lua/spec/class_spec.lua +++ b/lua/spec/class_spec.lua @@ -61,7 +61,7 @@ describe('class', function() it('access instance value from super', function () local c1 = Cat(5) - assert.equal(4, c1:super()._size) + assert.equal(5, c1:super()._size) end) end) From fbfe0e5da323498beaa8b2885faa155cd3698640 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:23:05 +0900 Subject: [PATCH 05/16] update test name --- lua/spec/class_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/spec/class_spec.lua b/lua/spec/class_spec.lua index b81f389eddc..e4c4559dc5b 100644 --- a/lua/spec/class_spec.lua +++ b/lua/spec/class_spec.lua @@ -58,7 +58,7 @@ describe('class', function() assert.error(function() return c1:super():numLegs() end) end) - it('access instance value from super', function () + it('access instance variable from super', function () local c1 = Cat(5) assert.equal(5, c1:super()._size) From 73d50e31b887dbf104e802a59fd3a090c189f8c3 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:25:43 +0900 Subject: [PATCH 06/16] code style --- lua/wikis/commons/Class.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/commons/Class.lua b/lua/wikis/commons/Class.lua index 8579fda2d26..9aeff9203c1 100644 --- a/lua/wikis/commons/Class.lua +++ b/lua/wikis/commons/Class.lua @@ -56,7 +56,7 @@ function Class.new(base, init) local proxyMT = { __index = function (obj, param) local objVal = rawget(obj, param) - if objVal then + if objVal then return objVal end return base and base[param] From dfc9d73dfdaf8c88c74ac65d54193a975e3f8d10 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:26:17 +0900 Subject: [PATCH 07/16] add metamethod test --- lua/spec/class_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lua/spec/class_spec.lua b/lua/spec/class_spec.lua index e4c4559dc5b..ff5722465da 100644 --- a/lua/spec/class_spec.lua +++ b/lua/spec/class_spec.lua @@ -58,6 +58,13 @@ describe('class', function() assert.error(function() return c1:super():numLegs() end) end) + it('call super metamethods', function () + local c1 = Cat(5) + + assert.equal('Cat', tostring(c1)) + assert.equal('Animal', tostring(c1:super())) + end) + it('access instance variable from super', function () local c1 = Cat(5) From a5364da0a1d32b37b6803057b3da2263019076ec Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:29:13 +0900 Subject: [PATCH 08/16] fix instance var access from super --- lua/wikis/commons/Class.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/wikis/commons/Class.lua b/lua/wikis/commons/Class.lua index 9aeff9203c1..4b1729056ac 100644 --- a/lua/wikis/commons/Class.lua +++ b/lua/wikis/commons/Class.lua @@ -55,7 +55,7 @@ function Class.new(base, init) local proxy = {} local proxyMT = { __index = function (obj, param) - local objVal = rawget(obj, param) + local objVal = rawget(object, param) if objVal then return objVal end From 245c091449156c2c13cabf97e6f85e482b446abf Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:30:22 +0900 Subject: [PATCH 09/16] fix testclass implementation --- lua/spec/class_spec.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/spec/class_spec.lua b/lua/spec/class_spec.lua index ff5722465da..28d974e3b07 100644 --- a/lua/spec/class_spec.lua +++ b/lua/spec/class_spec.lua @@ -8,7 +8,9 @@ describe('class', function() return 'Animal' end - Animal.__tostring = Animal.type + function Animal:__tostring() + return self:type() + end function Animal:size() error('abstract') From 5a565decae98a0c62c9b555f0d53006925136c0a Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:36:46 +0900 Subject: [PATCH 10/16] add another test case --- lua/spec/class_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lua/spec/class_spec.lua b/lua/spec/class_spec.lua index 28d974e3b07..15f81a2454f 100644 --- a/lua/spec/class_spec.lua +++ b/lua/spec/class_spec.lua @@ -72,6 +72,16 @@ describe('class', function() assert.equal(5, c1:super()._size) end) + + it('set instance variable from super', function () + local c1 = Cat(5) + + c1.super()._size = 20 + + assert.are_not_equal(5, c1._size) + assert.equal(20, c1._size) + assert.equal(20, c1.size()) + end) end) describe('instanceOf', function() From 1f841d5416328dc458fd168575e948326659b05d Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:39:21 +0900 Subject: [PATCH 11/16] syntax --- lua/spec/class_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/spec/class_spec.lua b/lua/spec/class_spec.lua index 15f81a2454f..8e4d22715a4 100644 --- a/lua/spec/class_spec.lua +++ b/lua/spec/class_spec.lua @@ -76,7 +76,7 @@ describe('class', function() it('set instance variable from super', function () local c1 = Cat(5) - c1.super()._size = 20 + c1:super()._size = 20 assert.are_not_equal(5, c1._size) assert.equal(20, c1._size) From f6ae92bab09c6afc080bb04c649836c8ddd9d241 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:42:20 +0900 Subject: [PATCH 12/16] syntax --- lua/spec/class_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/spec/class_spec.lua b/lua/spec/class_spec.lua index 8e4d22715a4..842054a1897 100644 --- a/lua/spec/class_spec.lua +++ b/lua/spec/class_spec.lua @@ -80,7 +80,7 @@ describe('class', function() assert.are_not_equal(5, c1._size) assert.equal(20, c1._size) - assert.equal(20, c1.size()) + assert.equal(20, c1:size()) end) end) From 365b98e38eaccfd303fe0651e875e45f1347f6b9 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:43:50 +0900 Subject: [PATCH 13/16] type annotate super() --- lua/wikis/commons/Class.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/wikis/commons/Class.lua b/lua/wikis/commons/Class.lua index 4b1729056ac..973cd342f03 100644 --- a/lua/wikis/commons/Class.lua +++ b/lua/wikis/commons/Class.lua @@ -30,6 +30,7 @@ Class.PRIVATE_FUNCTION_SPECIFIER = '_' ---@class BaseClass ---@operator call:self ---@field init fun(self, ...) +---@field super fun(self: self): table ---@param base? table ---@param init? fun(self, ...) From 5d0f0e500603b8d423216fb615d38860ff3651a0 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:57:02 +0900 Subject: [PATCH 14/16] block calling super().super() --- lua/wikis/commons/Class.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/wikis/commons/Class.lua b/lua/wikis/commons/Class.lua index 973cd342f03..feaa4cde231 100644 --- a/lua/wikis/commons/Class.lua +++ b/lua/wikis/commons/Class.lua @@ -56,6 +56,9 @@ function Class.new(base, init) local proxy = {} local proxyMT = { __index = function (obj, param) + if param == 'super' then + error('Cannot create proxy from a super proxy') + end local objVal = rawget(object, param) if objVal then return objVal @@ -63,6 +66,7 @@ function Class.new(base, init) return base and base[param] end, _base = base, + _isSuperProxy = true, __newindex = object, __add = base and base.__add, __sub = base and base.__sub, From 5a1c664443db97572ceef0edc3eaecc8d41a3f24 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:10:27 +0900 Subject: [PATCH 15/16] avoid creating multiple proxies --- lua/wikis/commons/Class.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/wikis/commons/Class.lua b/lua/wikis/commons/Class.lua index feaa4cde231..93971d0ec75 100644 --- a/lua/wikis/commons/Class.lua +++ b/lua/wikis/commons/Class.lua @@ -53,6 +53,9 @@ function Class.new(base, init) instance.__index = instance instance.super = function(object) + if object._superProxy then + return object._superProxy + end local proxy = {} local proxyMT = { __index = function (obj, param) @@ -84,6 +87,7 @@ function Class.new(base, init) __tostring = base and base.__tostring, } setmetatable(proxy, proxyMT) + object._superProxy = proxy return proxy end From 9a47b1e7e4dd9c38955a825173d7a1a9da72f5b9 Mon Sep 17 00:00:00 2001 From: ElectricalBoy <15651807+ElectricalBoy@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:12:15 +0900 Subject: [PATCH 16/16] more tests --- lua/spec/class_spec.lua | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lua/spec/class_spec.lua b/lua/spec/class_spec.lua index 842054a1897..61487869af3 100644 --- a/lua/spec/class_spec.lua +++ b/lua/spec/class_spec.lua @@ -36,6 +36,12 @@ describe('class', function() return 4 end + local SpecialCat = Class.new(Cat) + + function SpecialCat:makeSound() + return 'Meow' + end + describe('class operations', function() it('base class', function () local a1 = Animal() @@ -53,11 +59,23 @@ describe('class', function() end) describe('super', function() + it('assert single proxy', function () + local sc1 = SpecialCat(5) + + assert.is_true(sc1:super() == sc1:super()) + end) + it('access super methods', function () local c1 = Cat(5) assert.equal('Animal', c1:super():type()) assert.error(function() return c1:super():numLegs() end) + + local sc1 = SpecialCat(5) + + assert.equal('Cat', sc1:super():type()) + assert.equal(4, sc1:super():numLegs()) + assert.error(function() return sc1:super():makeSound() end) end) it('call super metamethods', function () @@ -82,6 +100,12 @@ describe('class', function() assert.equal(20, c1._size) assert.equal(20, c1:size()) end) + + it('error if getting grandparent class', function () + local sc1 = SpecialCat(5) + + assert.error(function() return sc1:super():super() end, 'Cannot create proxy from a super proxy') + end) end) describe('instanceOf', function() @@ -104,5 +128,14 @@ describe('class', function() assert.is_true(Class.instanceOf(c1:super(), Animal)) assert.is_false(Class.instanceOf(c1:super(), Cat)) end) + + it('with super of grandchild', function () + local sc1 = SpecialCat(5) + + local superSc1 = sc1:super() + + assert.is_true(Class.instanceOf(superSc1, Cat)) + assert.is_true(Class.instanceOf(superSc1, Animal)) + end) end) end)