lua environments and modules
假设我有一个模块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | -- 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 |
和一些使用它的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | -- 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")) |
我想要实现的是sandbox()中的
当使用
在Lua 5.2之前,您可以使用set / getfenv来更改环境,但是现在环境是词汇化的。 只能使用调试库通过更改
那么,如何在不同的环境中运行相同的功能? 您可以将环境作为参数传递:
1 2 3 4 5 6 7 8 | function env.resolve(str, _ENV) print("mod", _ENV) if _resolve_path ~= nil then return _resolve_path(str) else error("bad env") end end |
然后在其中调用
1 | env.resolve('test', _ENV) |
或者,如果您希望不必为每个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | -- 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 |
沙盒现在可以设置绑定的解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | -- 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")) |
这将产生结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $ 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 |