2012-02-13 19 views
7

Sto provando a passare il contesto in un'espressione dinamica che valuto ogni iterazione di un ciclo for. Capisco che la stringa di caricamento valuti solo all'interno di un contesto globale che significa che le variabili locali sono inaccessibili. Nel mio caso aggiro questa limitazione convertendo un locale in un globale ai fini della valutazione della stringa. Ecco quello che ho:Lua: passare il contesto in loadstring?

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) 

Il mio obiettivo finale (diverso da padroneggiare Lua) è quello di costruire fuori un XSLT come motore di allettante dove ho potuto fare qualcosa di simile:

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

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

... e generare differenti uscite. Attualmente sono bloccato sui miei metodi sopra il falco di condividere un contesto locale attraverso un globale. Qualcuno qui ha una visione migliore su come farei ciò che sto tentando di fare?

risposta

7

È possibile modificare il contesto di una funzione con setfenv(). Ciò ti consente fondamentalmente di eseguire il sandbox della funzione caricata nel suo ambiente privato. Qualcosa come il seguente dovrebbe funzionare:

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

Questo eviterà anche il valore della condizione di essere in grado di accedere a tutti i dati che non si desidera che, o più importante, modificando i dati non si vuole che . Si noti, tuttavia, che è necessario esporre tutti i collegamenti di livello superiore nella tabella a cui si desidera consentire l'accesso a condition (ad esempio, se si desidera che abbia accesso al pacchetto math, è necessario attenersi in context). In alternativa, se non si ha alcun problema con condition avere accesso globale e si vuole semplicemente a che fare con il non rendere il vostro locale di una società globale, è possibile utilizzare un metatabella su context avere passare indici sconosciuti fino alla _G:

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

Io uso qualcosa di simile nella ricerca di elementi XML del mio povero uomo nel mio [minatore di dati web] (https://github.com/mkottman/wdm/blob/master/wdm.lua#L156). –

+0

Che funziona brillantemente! Grazie! :) – Cliff

9

Vale la pena notare che setfenv was removed from Lua 5.2 and loadstring is deprecated. 5.2 è abbastanza nuovo in modo da non devono preoccuparsi per un po ', ma è possibile scrivere una routine di carico che funziona per entrambe le versioni:

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) 

versione 5.2 di load gestisce sia il vecchio loadstring comportamento e imposta l'ambiente (contesto, nel tuo esempio). La versione 5.2 cambia anche il concetto di environments, quindi loadstring potrebbe essere l'ultima delle tue preoccupazioni. Eppure, è qualcosa da considerare per risparmiare un po 'di lavoro lungo la strada.

+0

Grazie Corbin! :) Mentre attualmente sto lavorando su 5.1 inizialmente assumevo un ambiente 5.2. Questo dovrebbe sicuramente salvarmi qualche mal di testa! – Cliff

Problemi correlati