Skip to content

Commit 930b761

Browse files
committed
initial release
1 parent 3376a8a commit 930b761

2 files changed

Lines changed: 154 additions & 0 deletions

File tree

fallback.lua

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
2+
-- ----------------------------------------------------------
3+
4+
--local assert = assert
5+
local error, ipairs, type = error, ipairs, type
6+
local format = string.format
7+
--local loadfile = loadfile
8+
9+
local function lassert(cond, msg, lvl)
10+
if not cond then
11+
error(msg, lvl+1)
12+
end
13+
return cond
14+
end
15+
local function checkmodname(s)
16+
local t = type(s)
17+
if t == "string" then
18+
return s
19+
elseif t == "number" then
20+
return tostring(s)
21+
else
22+
error("bad argument #1 to `require' (string expected, got "..t..")", 3)
23+
end
24+
end
25+
--
26+
-- iterate over available searchers
27+
--
28+
local function iload(modname, searchers)
29+
lassert(type(searchers) == "table", "`package.searchers' must be a table", 2)
30+
local msg = ""
31+
for _, searcher in ipairs(searchers) do
32+
local loader, param = searcher(modname)
33+
if type(loader) == "function" then
34+
return loader, param -- success
35+
end
36+
if type(loader) == "string" then
37+
-- `loader` is actually an error message
38+
msg = msg .. loader
39+
end
40+
end
41+
error("module `" .. modname .. "' not found: "..msg, 2)
42+
end
43+
44+
local function bigfunction_new(with_loaded)
45+
46+
local _PACKAGE = {}
47+
local _LOADED = with_loaded or {}
48+
local _SEARCHERS = {}
49+
50+
--
51+
-- new require
52+
--
53+
local function _require(modname)
54+
55+
modname = checkmodname(modname)
56+
local p = _LOADED[modname]
57+
if p then -- is it there?
58+
return p -- package is already loaded
59+
end
60+
61+
local loader, param = iload(modname, _SEARCHERS)
62+
63+
local res = loader(modname, param)
64+
if res ~= nil then
65+
p = res
66+
elseif not _LOADED[modname] then
67+
p = true
68+
end
69+
70+
_LOADED[modname] = p
71+
return p
72+
end
73+
74+
_LOADED.package = _PACKAGE
75+
do
76+
local package = _PACKAGE
77+
package.loaded = _LOADED
78+
package.searchers = _SEARCHERS
79+
end
80+
return _require, _PACKAGE
81+
end -- big function
82+
83+
local new = bigfunction_new
84+
85+
local with_loaded = {}
86+
local _require, _PACKAGE = new(with_loaded)
87+
local searchers = _PACKAGE.searchers
88+
89+
-- [keep] 0) already loaded package (in _PACKAGE.loaded)
90+
-- [keep] 1) local submodule will be stored in _PACKAGE.preload[?]
91+
-- [new ] 2) uplevel require() (follow uplevel's loaded/preload/...)
92+
-- [new ] 3) fallback -> search in preload table but with a suffix name "fallback."
93+
94+
--
95+
-- check whether library is already loaded
96+
--
97+
local _PRELOAD = {}
98+
_PACKAGE.preload = _PRELOAD
99+
local function searcher_preload(name)
100+
lassert(type(name) == "string", format("bad argument #1 to `require' (string expected, got %s)", type(name)), 2)
101+
lassert(type(_PRELOAD) == "table", "`package.preload' must be a table", 2)
102+
return _PRELOAD[name]
103+
end
104+
table.insert(searchers, searcher_preload)
105+
106+
--
107+
local function search_uplevel(modname)
108+
local ok, ret = pcall(require, modname)
109+
if not ok then return false end
110+
return function() return ret end
111+
end
112+
table.insert(searchers, search_uplevel)
113+
114+
--
115+
local function search_fallback(modname)
116+
return _PRELOAD["fallback." .. modname]
117+
end
118+
table.insert(searchers, search_fallback)
119+
120+
return setmetatable({require = _require, package = _PACKAGE}, {__call = function(_self, ...) return _require(...) end})

test.fallback.lua

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
local fallback = require "fallback"
2+
local _require = fallback.require -- or directly fallback
3+
local _PACKAGE = fallback.package
4+
local preload = _PACKAGE.preload
5+
6+
preload["fallback.compat_env"] = function()
7+
return {_NAME="compat_env"}
8+
end
9+
10+
preload["foo.bar"] = function()
11+
return {_NAME="foo.bar"}
12+
end
13+
14+
15+
16+
assert( require "string" == _require("string") )
17+
assert(_require("foo.bar")._NAME == "foo.bar")
18+
assert(_require("compat_env")._NAME == "compat_env")
19+
20+
do
21+
local loaded = assert( package.loaded )
22+
local _loaded = assert( _PACKAGE.loaded )
23+
24+
assert( not loaded["foo.bar"] )
25+
assert( _loaded["foo.bar"] )
26+
27+
assert( not loaded["compat_env"] )
28+
assert( _loaded["compat_env"] )
29+
30+
assert( loaded["string"] )
31+
assert( _loaded["string"] )
32+
33+
end
34+
print("ok")

0 commit comments

Comments
 (0)