【问题标题】:Lua: pass context into loadstring?Lua:将上下文传递给加载字符串?
【发布时间】:2012-02-13 22:25:21
【问题描述】:

我试图将上下文传递到一个动态表达式中,我会评估 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>]]

...并生成不同的输出。目前,我坚持通过全球共享本地环境的上述鹰派手段。这里有没有人对我将如何去做我想做的事情有更好的了解?

【问题讨论】:

    标签: templates lua template-engine


    【解决方案1】:

    您可以使用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 上使用元表,让它将未知索引传递给@987654331 @:

    setmetatable(context, { __index = _G })
    

    【讨论】:

    • 我在 web data miner 的穷人 XML 元素搜索中使用了类似的东西。
    【解决方案2】:

    值得注意的是setfenv was removed from Lua 5.2 and loadstring is deprecated。 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 版也改变了environments 的概念,所以loadstring 可能是您最不必担心的。尽管如此,还是要考虑为自己节省一些工作。

    【讨论】:

    • 谢谢科尔宾! :) 虽然我目前正在开发 5.1,但我最初假设的是 5.2 环境。这绝对可以让我头疼!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-19
    • 2014-07-27
    • 1970-01-01
    • 2022-11-26
    • 2012-04-02
    • 2012-06-13
    • 2020-04-08
    相关资源
    最近更新 更多