Package System


VersionNotice: This page is a bit outdated. It's a initial proposal for a module system implemented on top of Lua 5.0, which lacked a standard module system. A standard module system was formally incorporated in Lua 5.1, and that module system was also backported to Lua 5.0 via [LuaCompat]. I'm not sure if this page has any remaining educational value. If it does have remaining value, it probably could be described or reworked in light of the 5.1 module work.

This is an embryonic package system for Lua 5. Its main function is

use "packagename" {options}
(where {options} is optional ;-) That call is similar to a require, except that

Currently, the current option function handles only the import option. import="*" means to declare all global names of the package into the global space of the importing package; import={"name1", "name2", ...} imports only the selected names.

It also defines a declare ("name1", "name2", ...) function, that turns on enforcing declaration of names, and also declares the given names. Any access to an undefined/undeclared global raises an error.

--
-- auxiliar error function
--
local function error (level, fmt, ...)
 _G.error(string.format(fmt, unpack(arg)), level+1)
end
--
-- this package cannot use the package system (itself!), so use old
-- package tricks (but most of its functions are global anyway...)
--
_G.Package = {}
local function loadfrompath (packname)
 LUA_PATH = LUA_PATH or os.getenv"LUA_PATH" or "?.lua;?"
 for k in string.gfind(LUA_PATH, "[^;]+") do
 local fname = string.gsub(k, "?", packname)
 local f, err = loadfile(fname)
 if f then return f end
 if not string.find(err, "^cannot read") then
 error(err)
 end
 end
 error(3, "cannot find package `%s' in path `%s'", packname, LUA_PATH)
end
--
-- Metatable for Global tables
-- Inherit absent fields from main global
--
local global_mt = {
 __index = function (t,n)
 local val = _G[n] -- get value from main global
 rawset(t, n, val) -- save it for next time
 return val
 end,
}
--
-- Alternative metatable, that enforces declarations
--
local Predefined = {} -- table for predefined variables
setmode(Predefined, "k")
local req_global_mt = {
 __index = function (t,n)
 local val = global_mt.__index(t, n)
 if val then return val end
 if not Predefined[t][n] then
 error(2, "attempt to read undeclared variable `%s'", n)
 end
 return nil
 end,
 __newindex = function (t,n, val)
 if not Predefined[t][n] then
 error(2, "attempt to write to undeclared variable `%s'", n)
 end
 rawset(t, n, val)
 end,
}
--
-- Declare variables (and turn on declaration enforcing)
--
function _G.declare (...)
 local predec = Predefined[getglobals(2)]
 if predec == nil then -- package didn't enforce declarations
 local g = getglobals(2) -- get package global table
 setmetatable(g, req_global_mt)
 predec = {}
 Predefined[g] = predec
 end
 for _, name in ipairs(arg) do
 predec[name] = true
 end
end
--
-- Default function to handle `use' options
-- (where `oldpack' is using `newpack')
--
function Package.defaultoptions (oldpack, newpack, options)
 for k, v in pairs(options) do
 if k == "version" then
 -- ???
 elseif k == "import" then
 if v == "*" then -- import all?
 for k,v in pairs(newpack) do
 -- do not import names starting with `_'
 if not string.find(k, "^_") then oldpack[k] = v end
 end
 elseif type(v) == "table" then -- import list?
 for _,n in ipairs(v) do oldpack[n] = newpack[n] end
 else error(3, "invalid value for `import' option")
 end
 else error(3, "invalid option `"..k.."'")
 end
 end
end
--
-- Import a package, initialize it, and install it in current package
--
function _G.use (packname)
 local g = _G[packname]
 if not g then
 local f = loadfrompath(packname)
 g = {_name = packname} -- new global table
 g._self = g
 _G[packname] = g
 setmetatable(g, global_mt)
 setglobals(f, g) -- change global table of calling function
 f() -- run main
 end
 local init = rawget(g, "_init")
 if init then init(getglobals(2)) end
 return function (options)
 (rawget(g, "_options") or Package.defaultoptions)(getglobals(2), g, options)
 end
end


RecentChanges · preferences
edit · history
Last edited January 1, 2007 11:36 pm GMT (diff)

AltStyle によって変換されたページ (->オリジナル) /