2010-06-23 15 views
5

Estoy tratando de usar archivos Lua sin procesar para fines de configuración, pero no quiero que los archivos de configuración contaminen el espacio de nombres global.Alcance variable de Lua con setfenv

El problema al que me estoy enfrentando es que dofile siempre parece ejecutarse en el entorno global real, por lo que los archivos externos simplemente lanzan todas sus declaraciones a _G.

Aquí hay un archivo principal de ejemplo, con comentarios que indican mis deseos.

function myFunc() 
    print("In the sandbox:") 
    print("Should be 1:", a) -- falls back to _G for lookup 
    a = 2 -- instantiating new global for sandbox 
    print("Should be 2:", a) -- from sandbox 
    print("Should still be 1:", _G.a) -- from host environment 

    dofile("loading.lua") -- here's where things go wrong 

    print "\nBack in the sandbox:" 
    print("Should be 3:", a) -- changed by loadfile 
    print("Should STILL be 1:", _G.a) -- unchanged 
end 

a = 1 
local newgt = {} -- new environment 
setmetatable(newgt, {__index = _G}) 
setfenv(myFunc, newgt) 
myFunc() 

print("\nOutside of the sandbox:") 
print("Should be 1: ", a) -- in theory, has never changed 

y el archivo se carga (loading.lua:

print ("\nLoading file...") 

print("Should be 2: ", a) -- coming from the sandbox environment 
a = 3 
print("Should be 3: ", a) -- made a change to the environment 

Y, finalmente, la salida que estoy viendo:

In the sandbox: 
Should be 1: 1 
Should be 2: 2 
Should still be 1: 1 

Loading file... 
Should be 2: 1 
Should be 3: 3 

Back in the sandbox: 
Should be 3: 2 
Should STILL be 1: 3 

Outside of the sandbox: 
Should be 1: 3 
+2

Está imprimiendo el literal 1 en lugar del valor de a. Si se trata de un trabajo de cortar y pegar, entonces su código es incorrecto, por lo que está viendo esa angustiosa línea final. –

+0

¡Ja! Gracias, el dedo gordo es el culpable de al menos el final. Gracias por la captura. – SJML

Respuesta

10

El problema que usted describe también se discute en esta página Dofile Namespace Proposal. La solución parecía ser el siguiente reemplazo para dofile:

function myapp.import(name) 
    local f,e = loadfile(name) 
    if not f then error(e, 2) end 
    setfenv(f, getfenv(2)) 
    return f() 
end 

Consulte también: Sand Boxes

+2

Gracias por el enlace. Para encapsular los aprendizajes de esa página que son relevantes para esta pregunta: 'dofile' ** always ** opera en el espacio de nombres global, ignorando el entorno de su función de llamada. Los intentos de afectarlo directamente con 'setfenv' generan un error. Esa misma restricción no se aplica a una función compilada anónima que se devuelve de 'archivo de carga', por lo que al usar el código anterior, se supera esta limitación. – SJML

+1

@SJML, exactamente. Mi entendimiento es que 'dofile' es un poco como el stock' print'. Está ahí por su gran conveniencia para principiantes y estudiantes, especialmente en el prompt interactivo. Un código serio evitaría la función o la redefiniría para funcionar de forma segura en el mundo real. – RBerteig