I’m trying to pass context into a dynamic expression that I evaluate every iteration of a for loop. I understand that the load string only evaluates within a global context meaning local variables are inaccessible. In my case I work around this limitation by converting a local into a global for the purpose of the string evaluation. Here’s what I have:
require 'cosmo'
model = { { player = "Cliff", age = 35, gender = "male" }, { player = "Ally", age = 36, gender = "female" }, { player = "Jasmine", age = 13, gender = "female" }, { player = "Lauren", age = 6.5, gender = "female" } }
values = { eval = function(args)
output = ''
condition = assert(loadstring('return ' .. args.condition))
for _, it in ipairs(model) do
each = it
if condition() then
output = output .. each.player .. ' age: ' .. each.age .. ' ' .. '\n'
end
end
return output
end }
template = "$eval{ condition = 'each.age < 30' }"
result = cosmo.fill(template, values)
print (result)
My ultimate goal (other than mastering Lua) is to build out an XSLT like tempting engine where I could do something like:
apply_templates{ match = each.age > 30}[[<parent-player>$each.player</parent-player>]]
apply_templates{ match = each.age > 30}[[<child-player>$each.player</child-player>]]
…And generate different outputs. Currently I’m stuck on my above hawkish means of sharing a local context thru a global. Does anyone here have better insight on how I’d go about doing what I’m attempting to do?
You can change the context of a function with
setfenv(). This allows you to basically sandbox the loaded function into its own private environment. Something like the following should work:This will also prevent the condition value from being able to access any data you don’t want it to, or more crucially, modifying any data you don’t want it to. Note, however, that you’ll need to expose any top-level bindings into the
contexttable that you wantconditionto be able to access (e.g. if you want it to have access to themathpackage then you’ll need to stick that intocontext). Alternatively, if you don’t have any problem withconditionhaving global access and you simply want to deal with not making your local a global, you can use a metatable oncontextto have it pass unknown indexes through to_G: