在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
来源 https://blog.codingnow.com/2015/10/lua_require_env.html
今天同事提了个需求,他希望可以给部分 lua 代码(由策划编写)做一个沙盒关起来。在 lua 里做沙盒很容易,只需要控制函数的环境就可以了。不过另一个附加需求是,这些代码还可以直接利用 require 加载。 而我们又不想去修改系统的 api 接口,那么怎么做到这点呢? 首先, 我希望使用的时候看起来像这样: local xxx = require "xxx" (myEnv) 和传统的 require 用法不同,可以在后面追加一个参数 myEnv 。这样的话,每次 xxx 模块被 require 时,它其实被重复运行一次,但会绑定不同的 其次,既然模块会被反复初始化,那么我们甚至还可以约定,每个这种沙盒封装的模块还可以接收 require 的传入的额外参数。 做到这点很容易,我们只需要在 package.searchers 里追加一个自定义的 loader 然后并不返回加载的模块 chunk ,而是做一个函数封装。将 chunk 的运行推迟到传入 myEnv 调用之后。 这样,load chunk 本身还是依靠 require 的 package 机制缓存代码的,只是每次调用后,重新绑定 我在 gist 上贴了一组代码实现这个特性:延迟绑定环境的 require 。
local M = {} function M.test(...) print(...) end return M
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)
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
|
请发表评论