2016-08-30 60 views
3

讓我們假設我有一個模塊:LUA環境和模塊

-- env.lua 

local env = {} 

function env.resolve(str) 
    print("mod", _ENV) 

    if _resolve_path ~= nil then 
    return _resolve_path(str) 
    else 
    error("bad env") 
    end 
end 

return env 

,並使用它的一些代碼:

-- sandbox demo 
-- run as: lua env-test.lua 

env = require('env') 

function _resolve_path(path) 
    return "/" .. path 
end 

print("before main()") 
print("", _ENV) 
print("", env.resolve("test")) 

local sandbox 
do 
    local _ENV = { 
    print = print, 
    env = env, 
    _resolve_path = function (path) 
     return "/chroot/" .. path 
    end 
    } 
    function sandbox() 
    print("from sandbox()") 
    print("", _ENV) 
    print("", env.resolve("test")) 
    end 
end 

sandbox() 

print("after main()") 
print("", _ENV) 
print("", env.resolve("test")) 

我想實現的是從env.resolve()沙箱()將使用環境中的自定義_resolve_path函數。它看到該環境不適用於從沙盒函數調用的代碼。我們的目標是根據它們被調用的位置來表達一些模塊的行爲方式。例如。使用具有不同本地_resolve_path()函數的沙箱{1,2,3}()。

回答

2

當您使用require加載模塊時,它將綁定到全局環境。一旦在一個環境中創建了一個函數,它在整個生命週期中都具有該環境。

在Lua 5.2之前,您可以使用set/getfenv來改變環境,但環境現在是詞彙。只能通過更改_ENV upvalue來更改環境。

那麼,如何在不同的環境中運行相同的功能呢?您可以在環境作爲參數傳遞:

function env.resolve(str, _ENV) 
    print("mod", _ENV) 
    if _resolve_path ~= nil then 
    return _resolve_path(str) 
    else 
    error("bad env") 
    end 
end 

你在哪裏,然後調用resolve這樣的:

env.resolve('test', _ENV) 

或者,如果您希望對環境沒有爲每個resolve呼叫被指定您可以在resolve功能結合到每一個新的環境:

-- env.lua 
local print = print 
local error = error 
local env = {} 

-- this is the actual resolve function that takes the environment as a parameter 
local function resolve_env(str, _ENV) 
    print("mod", _ENV) 
    if _resolve_path ~= nil then 
    return _resolve_path(str) 
    else 
    error("bad env") 
    end 
end 

-- this is the module (ie. global) resolve 
function env.resolve(str) 
    return resolve_env(str, _ENV) 
end 

-- this function binds a resolve function to a sandbox environment 
function env.bind(_ENV) 
    _ENV.env = { 
    resolve = function(str) 
     return resolve_env(str, _ENV) 
    end 
    } 
    return _ENV 
end 

return env 

沙箱現在可以設置一個必然的決心:

-- sandbox.lua 
env = require 'env' 

function _resolve_path(path) 
    return "/" .. path 
end 

print("before main()") 
print("", _ENV) 
print("", env.resolve("test")) 

local sandbox; do 
    local _ENV = env.bind{ 
    print = print, 
    _resolve_path = function (path) 
     return "/chroot/" .. path 
    end 
    } 

    function sandbox() 
    print("from sandbox()") 
    print("", _ENV) 
    print("", env.resolve("test")) 
    end 
end 

sandbox() 

print("after main()") 
print("", _ENV) 
print("", env.resolve("test")) 

這將產生的結果:

$ lua sandbox.lua 
before main() 
     table: 00612f40 
mod  table: 00612f40 
     /test 
from sandbox() 
     table: 0061c7a8 
mod  table: 0061c7a8 
     /chroot/test 
after main() 
     table: 00612f40 
mod  table: 00612f40 
     /test 
+0

是否有解決方案,使這項工作對其他的方法也叫env.resolve()。假設你有env.load(),env.write()那些現在看不到反彈env.resolve()函數:/ – ensonic