Reputation: 499
I'm using Lua tables to store data to create web pages. The body content is stored in a single table, there is some static text and some generated by Lua functions.
Web.HTML={
"<h1>Hello World</h1><br>",
"<br><h2>Current Directory</h2><br>",
io.popen("cd"):read('*l'),
"<br><h2>Current Lua Interpreter</h2><br>",
arg[-1] or arg[0],
"<br><h2>Current Package Path</h2><br>",
package.path:gsub(";",";<br>\n"),
"<br><h2>Current Package CPath</h2><br>",
package.cpath:gsub(";",";<br>\n"),
"<br><h2>Current Environment Table:</h2><br>",
io.popen("set"):read('*a'):gsub("\n","<br>\n").." ",
"<br><h2>Current Date:</h2><br>",
os.date(),
"<br><h2>Math calculation</h2><br>",
math.pi/180
}
This table is then "printed" using table.concat function, adding some newlines to aid readability:
print(table.concat(Web.HTML,"<br>\n"))
The example above works as expected in Lua 5.1 or equivalent and the server successfully passes this as part of my web page.
I would like to to place arbitrary Lua code in my HTML table which returns a string to be concatenated, but I can't find the correct syntax. The concat function complains invalid value (function) at index in table for 'concat'.
I have tried:
Web.HTML = {
"Classic text example:",
function() print "Hello World"; end,
}
and
Web.HTML = {
"Classic text example:",
function() return "Hello World"; end,
}
A more useful example would be to list all the tables in the Lua global environment:
Web.HTML = {
"<br><h2>Current Lua Libraries</h2><br>",
function()
local text = ''
for i,v in pairs(_G) do
if type(v)=="table" then
text = text..i.."<br>\n"
end
end
return text
end
,
"Success!"
}
I have also tried using loadstring(code ;return text )() as an entry in my table without success. Any pointers welcome.
Thanks in advance.
Gavin
Upvotes: 3
Views: 2897
Reputation: 23737
Unfortunately, standard function table.concat()
works only with strings and numbers.
You may write your own more versatile table.concat
:
do
local orig_table_concat = table.concat
-- Define new function "table.concat" which overrides standard one
function table.concat(list, sep, i, j, ...)
-- Usual parameters are followed by a list of value converters
local first_conv_idx, converters, t = 4, {sep, i, j, ...}, {}
local conv_types = {
['function'] = function(cnv, val) return cnv(val) end,
table = function(cnv, val) return cnv[val] or val end
}
if conv_types[type(sep)] then first_conv_idx, sep, i, j = 1
elseif conv_types[type(i)] then first_conv_idx, i, j = 2
elseif conv_types[type(j)] then first_conv_idx, j = 3
end
sep, i, j = sep or '', i or 1, j or #list
for k = i, j do
local v, idx = list[k], first_conv_idx
while conv_types[type(converters[idx])] do
v = conv_types[type(converters[idx])](converters[idx], v)
idx = idx + 1
end
t[k] = tostring(v) -- 'tostring' is always the final converter
end
return orig_table_concat(t, sep, i, j)
end
end
Examples of usage:
Web = {}
Web.HTML = {
"Classic text example:",
function() return "Hello World"; end,
}
-- without converters
print(table.concat(Web.HTML, "<br>\n"))
--> Classic text example:<br>
--> function: 0x9ad1398
-- with a converter
print(table.concat(
-- usual parameters for table.concat:
Web.HTML, "<br>\n",
-- additional parameters (converters):
function(x)
if type(x) == 'function' then
return x()
else
return x
end
end
))
--> Classic text example:<br>
--> Hello World
Upvotes: 0
Reputation: 28950
table.concat
concatenates the elements of a table to a string. Therefor it is
mandatory that every element in the table can be converted to a string.
In all your attempts:
Web.HTML = {
"Classic text example:",
function() print "Hello World"; end,
}
Web.HTML[2]
is a function which cannot be converted to a string.
You could replace your functions by strings or their return values in this case by simply defining them outside your list and then calling them in your table constructor or calling them right away with the function definitin in parentheses, or you could overload table.concat to your needs. Although I would rather implement a new concat function instead of overwriting the standard one to avoid confusion.
Upvotes: 0
Reputation: 22421
function
returns, obviously, a function. Just call it immediately with ()
. Also don't forget to change print
to return
- your function needs to return value for table, not to print it out!
Web.HTML = {
"Classic text example:",
(function() return "Hello World"; end)(),
}
print(table.concat(Web.HTML,"<br>\n"))
-- Classic text example:<br>
-- Hello World
Upvotes: 3
Reputation: 473447
table.concat
will not automagically execute code that it encounters. It concatenates a list of strings (or numbers); that's its job. If you pass it something that isn't a list of strings, then you have done something wrong.
If you have a list of strings+functions-that-return-strings, then you need to transform this into a list of strings yourself. This is easily done:
local list = --However you generate it.
for i, val in ipairs(list) do
if(type(val) == "function") then
list[i] = val() --call function
end
end
Then you can concatenate list
with table.concat
. If you want to create a copy of the table, instead of overwriting the existing one, then that's easily done as well.
local list = --However you generate it.
local copy = {}
for i, val in ipairs(list) do
if(type(val) == "function") then
copy[i] = val() --call function
else
copy[i] = val
end
end
Upvotes: 2