【问题标题】:lua environments and moduleslua 环境和模块
【发布时间】:2017-04-16 17:46:37
【问题描述】:

假设我有一个模块:

-- 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"))

我想要实现的是,来自 sandbox() 的 env.resolve() 将使用环境中的自定义 _resolve_path 函数。它看到该环境并未应用于从沙盒函数调用的代码。目标是根据调用它们的位置来增强某些模块的行为方式。例如。具有具有不同本地 _resolve_path() 函数的沙箱{1,2,3}()。

【问题讨论】:

    标签: lua sandbox


    【解决方案1】:

    当您使用require 加载模块时,它会绑定到全局环境。一旦在一个环境中创建了一个函数,它就会在其整个生命周期中都拥有该环境。

    在 Lua 5.2 之前,您可以使用 set/getfenv 来改变环境,但环境现在是词法的。环境只能通过调试库通过更改_ENV 上值来更改。

    那么,如何在不同的环境中运行相同的功能呢?可以将环境作为参数传入:

    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
    

    【讨论】:

    • 是否有解决方案可以让其他方法也能调用 env.resolve()。假设你有 env.load()、env.write() 那些现在看不到反弹 env.resolve() 函数:/
    猜你喜欢
    • 2015-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-03
    • 2012-11-08
    • 1970-01-01
    • 2014-01-11
    • 1970-01-01
    相关资源
    最近更新 更多