Make __call metamethod as iterator

609 Views Asked by At

I'm trying to emulate execution of certain functions from scripts of other app. That app have Lua library which contains function list(), it returns table where key is string UUID and value just string, like local tbl = { "0000..-0000-..." = "someString", etc... }. That table can be iterated in for loop, like

local lib = require("someLibrary.lua");

for key, value in lib.list() do
    -- do something with keys and values, like print
end

-- or it can be used like this

local tbl = lib.list();
for key, value in tbl do -- tbl works as pairs(tbl) and works exactly how code on top
    -- do something with keys and values, like print
end

So the question, how do I implement __call metamethod to work as pairs() or next() etc.?

Thanks

2

There are 2 best solutions below

0
On BEST ANSWER

Yes! I've managed to find answer to my question. I've found source code of library that I trying to replicate. It actually uses local variables to iterate through table

Here is a code how I made lib.list() and lst work

function lib.list(filter, exact)
    if filter == nil then filter = '' end;
    if exact == nil then exact = false end;

    local list = Component.list(filter, exact); -- just gets table from app that written in C#, treat like someClass.getSomeTable()

    local list_mt = {}; -- metatable that assigns to above "list" table
    local key = nil; -- key that will be used in iterator

    function list_mt.__call() -- __call metamethod for "list" table
        key = next(list, key);
        if key then
            return key, list[key]
        end
    end

    return setmetatable(list, list_mt); -- return table with assigned metatable that contains __call metamethod
end
5
On

pairs(tbl) returns next,tbl,nil.

So do

setmetatable(tbl,{__call=function (t) return next,t,nil end})

and then you can write

for key, value in tbl() do
        print(key, value)
end

I don't think you can avoid the () there.