2012-02-13 25 views
7

Estoy tratando de pasar el contexto a una expresión dinámica que evalúo cada iteración de un ciclo for. Entiendo que la cadena de carga solo evalúa dentro de un contexto global, lo que significa que las variables locales son inaccesibles. En mi caso, evito esta limitación convirtiendo un local en global para el propósito de la evaluación de cadenas. Aquí es lo que tengo:Lua: ¿pasa el contexto a la cadena de carga?

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) 

Mi objetivo final (que no sea el dominio de Lua) es construir un motor XSLT como tentador en el que podía hacer algo como:

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

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

... Y generar diferentes salidas. Actualmente estoy atascado en mi medio halcón por encima de compartir un contexto local a través de un global. ¿Alguien aquí tiene una mejor idea de cómo haré lo que estoy intentando hacer?

Respuesta

7

Puede cambiar el contexto de una función con setfenv(). Esto le permite básicamente guardar la función cargada en su propio entorno privado. Algo parecido a lo siguiente debería funcionar:

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

Esto también evitará que el valor de condición de la posibilidad de acceder a los datos que no desea a, o más importante, la modificación de los datos que no desea que se . Sin embargo, tenga en cuenta que deberá exponer cualquier enlace de nivel superior en la tabla context que desee condition para poder acceder (por ejemplo, si desea que tenga acceso al paquete math, deberá pegar ese en context). Alternativamente, si usted no tiene ningún problema con condition tener acceso global y simplemente quiere tratar con no hacer su un local global, se puede utilizar un metatabla en context tener que pasar a través de los índices desconocidos a _G:

setmetatable(context, { __index = _G }) 
+0

Uso algo similar en la búsqueda de elementos XML de mi pobre hombre en mi [web data miner] (https://github.com/mkottman/wdm/blob/master/wdm.lua#L156). –

+0

¡Eso funciona brillantemente! Gracias! :) – Cliff

9

Vale la pena señalar que setfenv was removed from Lua 5.2 and loadstring is deprecated. 5.2 es bastante nuevo, así que no tendrá que preocuparse de él por un tiempo, pero es posible escribir una rutina de carga que funciona para ambas versiones:

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) 

Versión load manijas de 5.2 tanto el antiguo loadstring comportamiento y establece el entorno (contexto, en su ejemplo). La versión 5.2 también cambia el concepto de environments, por lo que loadstring puede ser la menor de sus preocupaciones. Aún así, es algo a considerar para posiblemente ahorrarse un poco de trabajo en el futuro.

+0

Gracias Corbin! :) Mientras estoy trabajando en 5.1 originalmente estaba asumiendo un entorno 5.2. Esto definitivamente debería salvarme algunos dolores de cabeza! – Cliff

Cuestiones relacionadas