I'd like to create a simple mock table that would tell me what was tried to be called from it.
My first try was:
local function capture(table, key)
print("call to " .. tostring(table) .. " with key " .. tostring(key))
return key
end
function getMock()
mock = {}
mt = { __index = capture }
setmetatable(mock, mt)
return mock
end
Now calling this with
t = getMock()
t.foo
prints as I expected:
call to table: 002BB188 with key foo
but trying to call:
t.foo("bar")
gives:
call to table: 002BB188 with key foo
lua: test.lua:6: attempt to call field 'foo' (a string value)
Now I have two questions:
How to avoid the exception, ie. what am I doing wrong?
How to catch the method argument too ("bar" in this case)?
You need to return a function from the __index handler, not a string:
local function capture(table, key, rest)
return function(...)
local args = {...}
print(string.format("call to %s with key %s and arg[1] %s",
tostring(table), tostring(key),
tostring(args[1])))
end
end
-- call to table: 0x7fef5b40e310 with key foo and arg[1] nil
-- call to table: 0x7fef5b40e310 with key foo and arg[1] bar
You're getting an error because it's trying to call the result, but it's currently the key.
Related
i came across a post about metatable on roblox devforum,in proxy table part i dont understand the syntax of this code
local function TrackDownTable()
local t = {x = 5}
local proxy = setmetatable({}, {
__index = function(_, key)
print("User indexed table with "..key)
return t[key]
end,
__newindex = function(_, key, value)
print("User made or update the field "..key.." with the value "..value.." in table")
t[key] = value
end
})
return proxy
end
local t = TrackDownTable()
t.x = 5
print(t.x)
in this part
local t = TrackDownTable()
t.x = 5
what does local t = TrackdownTable() do? and how does this part t.x = 5 acces proxy table?
This is a very simple proxy demo table.
A proxy table is a table that controls table access. You can use it to track table access or to implement a read only table for example.
There is no way for you to access or modify that table's data without going through the proxy table.
It is actually quite simple. TrackDownTable creates t, which is just some demo table. We just need a simple table to demonstrate table access. So we create a minimum table with a single field {x=5}
local proxy = setmetatable({}, {
__index = function(_, key)
print("User indexed table with "..key)
return t[key]
end,
__newindex = function(_, key, value)
print("User made or update the field "..key.." with the value "..value.." in table")
t[key] = value
end
})
can be rewritten as:
local metatable = {}
metatable.__index = function(_, key)
print("User indexed table with "..key)
return t[key]
end
metatable.__newindex = function(_, key, value)
print("User made or update the field "..key.." with the value "..value.." in table")
t[key] = value
end
local proxy = {}
setmetatable(proxy, metatable)
This code simply creates a metatable with an __index and a __newindex metamethod and sets it as the metatable of our demo table.
__index is invoked when you index a field of proxy.
__newindex is invoked when you assign a value to an index in proxy.
Edit:
want to know is how is this assignmentt.x = 5 passed to the proxy
table as ``local t = TrackDownTable() ``` when t.x = 5 happens what
does it do, it passes 5 as the parameter to the function?
t.x = 5 is an indexing assignment. If you execute this Lua will check if there is a field with key "x" in t. As t["x"] is nil in this scope it will check if there is a metatable. There is, so it will call our __newindex metamethod which has 3 parameters (table, key, value)
So we actually call getmetatable(t).__index(t, "x", 5) which internally will assign the value to the local t.x defined inside TrackDownTable.
It is a bit misleading that both tables are named t in this example.
Please read https://www.lua.org/manual/5.4/manual.html#2.4
So I'm currently working on creating blocks of codes which can be called simultaneously by a name id. I've decided to do that with a main table, which contains table with id and with functions. To do that, I wrote 3 functions
function hook.add(name, hookname, func)
hooks[hookname[name]] = func
end
function hook.create(name)
hooks[name] = {}
end
function hook.run(name)
for _, func in pairs(hooks[name]) do
func()
end
end
hook.create("MainHook")
local function func()
print("working")
end
hook.add("todo", "MainHook", func)
However it doesnt work and crashes with
bin/hooks.lua:27: table index is nil
Error contains in
hooks[hookname[name]] = func
line but I have no idea why because even if i print hookname and name there is no nil at all.
I would really appreciate if you help me
Your function hook.create creates empty table for name, so function hook.add should look like this:
function hook.add(name, hookname, func)
-- create hooks[hookname] table if not exists
hooks[hookname] = hooks[hookname] or {}
-- add function to hooks[hookname] table
hooks[hookname][name] = func
end
I'm trying to get table key name from a value.
tostring only returns table: XXXXXXXXX
I tried some functions but nothing work.
config = {
opt1 = "etc..."
}
players = {}
function openMenu(playerName, configTable)
players[playerName] = Something to get Table Key...
-- read the table and create a gui not yet made
end
And next, if I do this :
print(players[playerName])
I want to get this output :
"config"
You will need to iterate over all pairs of the table and return the key if the value is equal. Note that this will only return one binding, even if multiple keys can lead to the same value:
function find(tbl, val)
for k, v in pairs(tbl) do
if v == val then return k end
end
return nil
end
table.find(t, value [,start_index]) -> [key or nil]
I have an empty table which I want to act as a "gateway" to another set of functions at another location.
tbl = {}
I want to pass called functions from this table to somewhere else as a string:
tbl.someMethod("hello")
I've tried this with limited success.
hand = {
__index = function(tbl, name)
hand[name] = function(...)
passToSomewhere(name, ...)
end
end,
__call = function(tbl, name, ...)
hand[name](...)
end
}
setmetatable(tbl, hand)
tbl.someFunction("hello!", someTbl, someNumber)
How do I forward the undefined function through the table without it throwing errors?
Edit: More detail
I'm trying to define and call a function in a table in one call:
tbl = {}
hand = {
__index = function(tbl, name)
print(name)
tbl[name] = function(...)
print(...)
end
end
}
setmetatable(tbl, hand)
s,e = pcall(tbl.help,"banana","goat")
print(s)
s,e = pcall(tbl.help,"banana","goat")
print(s)
This code does work but the first pcall will throw an error because the function hasn't been defined yet.
Say I wanted to use an library which I know updates quite a lot and keep my script compatible and this library may not be present on my computer. I would like to forward calls to this library across some interface but I still want to be able to call the functions in the same way.
--For example I would like to call this function like this:
someLib.doSomething(name, age, telephone)
--Instead of passing it through another function:
someOtherLib.invoke("someLib.doSomething", name, age, telephone)
Is this possible?
Edit 2:
Thanks #greatwolf !
This is my working test code.
tbl = {}
hand = {
__index = function(tbl, name)
tbl[name] = function(...)
return print(name, ...)
end
return rawget(tbl, name)
end
}
setmetatable(tbl, hand)
tbl.help("banana","goat")
Okay, based on your updated details you want lua to translate this call
someLib.doSomething(name, age, telephone)
into
someOtherLib.invoke("someLib.doSomething", name, age, telephone)
behind the scenes. What you have is almost there, you just need to return the newly created function back:
__index = function(tbl, name)
tbl[name] = function(...)
return someOtherLib.invoke("someLib."..name, ...)
end
-- return tbl[name] works too, I used rawget to indicate
-- no further __index lookup should be done
return rawget(tbl, name)
end
Now, if your someOtherLib is just a table of functions, lhf's suggestion will work too
setmetatable(tbl, {__index = someOtherLib})
Now if your someOtherLib provides someway to get the function you want to call without actually invoking it just yet, __index can relay this without creating extra closure wrappers
__index = function(tbl, name)
tbl[name] = someOtherLib.getFuncByName(name)
return tbl[name]
end
The __call metamethod is not needed here.
In Lua how would one pop/remove the next item (any order) in a key-value-pair table?
Is this possible without having to iterate using pairs?
There is a primitive function next, you can call next(t,k), where k is a key of the table t, returns a next key in the table, in an arbitrary order, and the value associated with this key.
If k is nil, next(t,k) returns the first element if there is one. So you can iterate the table from calling next(t,nil) and end when the next key is nil.
This is an simple example to demonstrate the use of next:
local t = {a = "va", b = "vb", c = "vc"}
local k,v = next(t,nil)
print(k,v)
k,v = next(t,k)
print(k,v)
k,v = next(t,k)
print(k,v)
k,v = next(t,k)
print(k,v)
Output:
a va
c vc
b vb
nil nil
The global function next is useful here. The docs explain it pretty well in general. To use it iteratively, this is 'key':
You may ... modify existing fields. In particular, you may clear
existing fields.
A simple pop function:
-- removes and returns an arbitrary key-value pair from a table, otherwise nil
local pop = function (t)
local key, value = next(t)
if key ~= nil then
t[key] = nil
end
return key, value
end
Demo:
local test = { "one", c = "see", "two", a = "ayy", b = "bee", "three" }
assert(next(test), "Table was expected to be non-empty")
local key, value = pop(test)
while key do
print(key, value)
key, value = pop(test)
end
assert(not next(test), "Table was expected to be empty")
If you run the demo multiple times, you might see the arbitrariness of the table sequence.