• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

扩展luarequire的行为

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

 

来源 https://blog.codingnow.com/2015/10/lua_require_env.html

 

今天同事提了个需求,他希望可以给部分 lua 代码(由策划编写)做一个沙盒关起来。在 lua 里做沙盒很容易,只需要控制函数的环境就可以了。不过另一个附加需求是,这些代码还可以直接利用 require 加载。

而我们又不想去修改系统的 api 接口,那么怎么做到这点呢?

首先, 我希望使用的时候看起来像这样:

local xxx = require "xxx" (myEnv)

和传统的 require 用法不同,可以在后面追加一个参数 myEnv 。这样的话,每次 xxx 模块被 require 时,它其实被重复运行一次,但会绑定不同的 _ENV 。

其次,既然模块会被反复初始化,那么我们甚至还可以约定,每个这种沙盒封装的模块还可以接收 require 的传入的额外参数。

做到这点很容易,我们只需要在 package.searchers 里追加一个自定义的 loader 然后并不返回加载的模块 chunk ,而是做一个函数封装。将 chunk 的运行推迟到传入 myEnv 调用之后。

这样,load chunk 本身还是依靠 require 的 package 机制缓存代码的,只是每次调用后,重新绑定 _ENV 生成了一组新实例。

我在 gist 上贴了一组代码实现这个特性:延迟绑定环境的 require 。

 

mymod.user.lua

local M = {}

function M.test(...)
    print(...)
end

return M

 

 

requirenv.lua

local package = package
local debug = debug

local function load_env(filename)
    local f,err = loadfile(filename)
    if f == nil then
        return err
    end
    return function()
        return function(env)
            if env then
                debug.setupvalue(f, 1, env)
            end
            return f(filename)
        end
    end
end

local function searcher_env(name)
    local filename, err = package.searchpath(name, package.upath)
    if filename == nil then
        return err
    else
        return load_env(filename)
    end
end

table.insert(package.searchers, searcher_env)

 

test.lua

require "requirenv"

package.upath = "./?.user.lua"

local myprint = print

local env = {
    print = function (...)
        myprint("hook", ...)
    end
}

local s = require "mymod"(env)

s.test "hello world"  -- hook hello world

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap