Lua:将上下文传递到加载字符串中?

发布于 2025-01-04 20:11:43 字数 1164 浏览 0 评论 0原文

我试图将上下文传递到一个动态表达式中,我会评估 for 循环的每次迭代。我知道加载字符串仅在全局上下文中计算,这意味着局部变量不可访问。就我而言,为了字符串评估的目的,我通过将本地转换为全局来解决此限制。这就是我所拥有的:

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)

我的最终目标(除了掌握 Lua 之外)是构建一个类似 XSLT 的诱人引擎,我可以在其中执行以下操作:

apply_templates{ match = each.age > 30}[[<parent-player>$each.player</parent-player>]]

apply_templates{ match = each.age > 30}[[<child-player>$each.player</child-player>]]

...并生成不同的输出。目前,我仍坚持上述通过全球分享本地背景的鹰派方式。这里有人对我如何去做我想做的事情有更好的见解吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

提赋 2025-01-11 20:11:43

值得注意的是 setfenv 已从 Lua 5.2 中删除,并且 < code>loadstring 已弃用。 5.2 是相当新的,所以你暂时不必担心它,但可以编写一个适用于两个版本的加载例程:

local function load_code(code, environment)
    if setfenv and loadstring then
        local f = assert(loadstring(code))
        setfenv(f,environment)
        return f
    else
        return assert(load(code, nil,"t",environment))
    end
end

local context = {}
context.string = string
context.table = table
-- etc. add libraries/functions that are safe for your application.
-- see: http://lua-users.org/wiki/SandBoxes
local condition = load_code("return " .. args.condition, context)

版本 5.2 的 load 处理旧的 loadstring 行为并设置环境(上下文,在你的例子中)。 5.2 版本还改变了环境的概念,因此loadstring< /code> 可能是您最不用担心的。尽管如此,还是值得考虑一下,这样可能会为自己节省一些工作。

It's worth noting that setfenv was removed from Lua 5.2 and loadstring is deprecated. 5.2 is pretty new so you won't have to worry about it for a while, but it is possible to write a load routine that works for both versions:

local function load_code(code, environment)
    if setfenv and loadstring then
        local f = assert(loadstring(code))
        setfenv(f,environment)
        return f
    else
        return assert(load(code, nil,"t",environment))
    end
end

local context = {}
context.string = string
context.table = table
-- etc. add libraries/functions that are safe for your application.
-- see: http://lua-users.org/wiki/SandBoxes
local condition = load_code("return " .. args.condition, context)

Version 5.2's load handles both the old loadstring behavior and sets the environment (context, in your example). Version 5.2 also changes the concept of environments, so loadstring may be the least of your worries. Still, it's something to consider to possibly save yourself some work down the road.

往事随风而去 2025-01-11 20:11:43

您可以使用 setfenv()。这基本上允许您将加载的函数沙箱到它自己的私有环境中。像下面这样的东西应该可以工作:

local context = {}
local condition = assert(loadstring('return ' .. args.condition))
setfenv(condition, context)
for _, it in ipairs(model) do
    context['each'] = it
    if condition() then
        -- ...

这也将防止条件值能够访问您不希望它访问的任何数据,或者更重要的是,修改您不希望它访问的任何数据。但请注意,您需要将任何顶级绑定公开到您希望 condition 能够访问的 context 表中(例如,如果您希望它有权访问 math 包,那么您需要将其粘贴到 context 中)。或者,如果您对具有全局访问权限的 condition 没有任何问题,并且您只是想处理不使本地成为全局的问题,则可以在 context 上使用元表让它将未知索引传递给 _G

setmetatable(context, { __index = _G })

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:

local context = {}
local condition = assert(loadstring('return ' .. args.condition))
setfenv(condition, context)
for _, it in ipairs(model) do
    context['each'] = it
    if condition() then
        -- ...

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 context table that you want condition to be able to access (e.g. if you want it to have access to the math package then you'll need to stick that into context). Alternatively, if you don't have any problem with condition having global access and you simply want to deal with not making your local a global, you can use a metatable on context to have it pass unknown indexes through to _G:

setmetatable(context, { __index = _G })
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文