Lua - 走弯路的函数
Lua - Function That Creates Detours
我需要在各种功能上走几条弯路,一个一个地做是不行的。我正在寻找一个理想情况下采用 table 的函数,而这个 table 是 class。循环遍历它,对于作为函数的每个键、值对,在原始函数名称之前创建一个带有前缀的函数指针。我尝试了几种变体来实现这种效果,但它们都会产生不同的问题。有的不管你给他们什么都不会做迂回指针,有的做了迂回指针但是不起作用,还有一些会溢出堆栈或者根本不被识别。
我想知道是否有办法,即 rawsets、metatable 覆盖、不断循环直到它们匹配等,以便函数可以获得 table(或一个与 table 同名的字符串,因此 loadstring 方法也可以在这里工作)并循环遍历每个函数并创建一个工作绕行指针......无论如何。
我更喜欢使用 self:prefix_orig_name(...) 语法 [...可以用实际参数替换]。
这是我尝试使用示例的 2 个变体。
-- 1st Method
detours = detours or {}
function detour(object, class) -- Class is an extra arg that I would send if for some reason just sending an object didn't work...it was theory oh'ed
if detours[object] then -- Check if the detour already exists...might be worth remaking it especially if the function gets overridden several times in different places?
print("detour: Previous " .. object .. " detour found, using previous detour")
return
end
for name, func in pairs(class and class or loadstring("return " .. object)()) do
-- the loadstring method here is used because the argument received is a string of the same name as the table...thus loading it will yield a table
if type(func) == "function" then
local execute, error = loadstring(object .. ".custom_detour_" .. name .. " = " .. object .. "." .. name) -- This makes the actual pointer
if error then
print("detour Error: " .. " Failed to detour: " .. object .. " Error: " .. error)
end
local luanch, assert = pcall(execute)
if not luanch then
print("detour Error: " .. " Failed to detour: " .. object .. " Error: " .. assert)
end
end
end
print("Table: " .. object .. " successfully detourd")
detours[object] = true -- tells us we made a detour of this table/string
end
-- 2nd Method
function detour(object) -- Takes a table
for k, v in pairs(object) do
if type(v) == "function" and not detours[k] then
if not object.custom_detour_ then
object.custom_detour_ = clone(object) -- use a simple cloning function (shallow) to put a clone of the main table into a sub table of the main table
end
if object["custom_detour_" .. k] ~= object.custom_detour_[k] then
object["custom_detour_" .. k] = object.custom_detour_[k] -- this makes it so the self:custom_detour_orig_name(...) syntax can be used, if I am not mistaken
end
end
end
end
-- Example Usage:
MyClass = class() -- class function is relatively OOP standard
function MyClass:init()
self._something = true
end
function MyClass:change(value)
self._something = value
end
function MyClass:table_print(tbl) -- just making funcs up
for k, v in pairs(tbl) do
print(v)
end
end
my_class = MyClass:new()
-- 1st Method
detour("MyClass")
--2nd Method
detour(MyClass)
我个人更喜欢第一种方法或至少一个字符串,因为我可以记录每一次绕行,如果以后出现问题,它使调试更容易......但我支持任何可行的方法。
简单的绕路用闭包很容易做到;不需要 loadstring
:
function detour(cls)
local detours = {}
for key, value in pairs(cls) do
if type(value) == "function" then -- note: ignores objects with __call metamethod
detours["custom_detour_"..key] = function(...)
-- Do whatever you want here
return value(...)
end
end
end
for key, value in pairs(detours) do
cls[key] = value
end
end
我需要在各种功能上走几条弯路,一个一个地做是不行的。我正在寻找一个理想情况下采用 table 的函数,而这个 table 是 class。循环遍历它,对于作为函数的每个键、值对,在原始函数名称之前创建一个带有前缀的函数指针。我尝试了几种变体来实现这种效果,但它们都会产生不同的问题。有的不管你给他们什么都不会做迂回指针,有的做了迂回指针但是不起作用,还有一些会溢出堆栈或者根本不被识别。
我想知道是否有办法,即 rawsets、metatable 覆盖、不断循环直到它们匹配等,以便函数可以获得 table(或一个与 table 同名的字符串,因此 loadstring 方法也可以在这里工作)并循环遍历每个函数并创建一个工作绕行指针......无论如何。
我更喜欢使用 self:prefix_orig_name(...) 语法 [...可以用实际参数替换]。
这是我尝试使用示例的 2 个变体。
-- 1st Method
detours = detours or {}
function detour(object, class) -- Class is an extra arg that I would send if for some reason just sending an object didn't work...it was theory oh'ed
if detours[object] then -- Check if the detour already exists...might be worth remaking it especially if the function gets overridden several times in different places?
print("detour: Previous " .. object .. " detour found, using previous detour")
return
end
for name, func in pairs(class and class or loadstring("return " .. object)()) do
-- the loadstring method here is used because the argument received is a string of the same name as the table...thus loading it will yield a table
if type(func) == "function" then
local execute, error = loadstring(object .. ".custom_detour_" .. name .. " = " .. object .. "." .. name) -- This makes the actual pointer
if error then
print("detour Error: " .. " Failed to detour: " .. object .. " Error: " .. error)
end
local luanch, assert = pcall(execute)
if not luanch then
print("detour Error: " .. " Failed to detour: " .. object .. " Error: " .. assert)
end
end
end
print("Table: " .. object .. " successfully detourd")
detours[object] = true -- tells us we made a detour of this table/string
end
-- 2nd Method
function detour(object) -- Takes a table
for k, v in pairs(object) do
if type(v) == "function" and not detours[k] then
if not object.custom_detour_ then
object.custom_detour_ = clone(object) -- use a simple cloning function (shallow) to put a clone of the main table into a sub table of the main table
end
if object["custom_detour_" .. k] ~= object.custom_detour_[k] then
object["custom_detour_" .. k] = object.custom_detour_[k] -- this makes it so the self:custom_detour_orig_name(...) syntax can be used, if I am not mistaken
end
end
end
end
-- Example Usage:
MyClass = class() -- class function is relatively OOP standard
function MyClass:init()
self._something = true
end
function MyClass:change(value)
self._something = value
end
function MyClass:table_print(tbl) -- just making funcs up
for k, v in pairs(tbl) do
print(v)
end
end
my_class = MyClass:new()
-- 1st Method
detour("MyClass")
--2nd Method
detour(MyClass)
我个人更喜欢第一种方法或至少一个字符串,因为我可以记录每一次绕行,如果以后出现问题,它使调试更容易......但我支持任何可行的方法。
简单的绕路用闭包很容易做到;不需要 loadstring
:
function detour(cls)
local detours = {}
for key, value in pairs(cls) do
if type(value) == "function" then -- note: ignores objects with __call metamethod
detours["custom_detour_"..key] = function(...)
-- Do whatever you want here
return value(...)
end
end
end
for key, value in pairs(detours) do
cls[key] = value
end
end