lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi,

Tiago Dionizio wrote:
> Looking at the new package system for Lua 5.1 (work 4) i was thinking
> about a simple feature that could be added to the core system.
> 
> The ability to register module loaders, enabling a user to load lua
> scripts from specific locations or even compressed files (along with
> many other uses).

Well, the
  setmetatable(package.preload, { __index = your_loader })
trick from Diego sure is nice.

But you made me think about a different idea: require() uses hardcoded
control flow to go through package.loaded, package.preload, package.cpath
and package.path. Why not use a single 'path table' that holds closures for
individual loaders (bound to individual path elements):

package.path = {
  loader_table(package.preload),           -- could do without a closure here

  loader_c   "./?.so",
  loader_c   "/usr/local/lib/lua/5.1/?.so",

  loader_lua "./?.lua",
  loader_lua "/usr/local/share/lua/5.1/?.lua",
  loader_lua "/usr/local/share/lua/5.1/?/init.lua",
}

Sample implementation (untested):

function package.loader_table(t)
  return function(name) return t[name] end
end

local function exists(path, name)
  local file = string.gsub(path, "%?", name)
  local f = io.open(file)
  return f and f:close() and file
end

function package.loader_c(path)
  return function(name)
    local file = exists(path, name)
    local init = "luaopen_" .. string.gsub(name, "%.", "_")
    return file and assert(loadlib(file, init))
  end
end

function package.loader_lua(path)
  return function(name)
    local file = exists(path, name)
    return file and assert(loadfile(file))
  end
end

function require(name)
  local res = package.loaded[name]
  if res then return res end
  for _,loader in ipairs(package.path) do
    local f = loader(name)
    if f then
      package.loaded[name] = true
      res = f(name)
      package.loaded[name] = res
      return res
    end
  end
  error("cannot find "..name.." in package path", 2)
end


Adding a zip loader, a DLL-path-relative-to-EXE loader and so on is very
simple (for anyone who wants it -- not part of the core). Manipulation of
the path and the loader priorities can be done with standard Lua functions
(table.insert, table.remove) and does not require string processing and/or
patching the core.

IMHO this is much cleaner and simpler than the current hardcoded approach.
It may even use less code than the current approach if properly coded in C
(because we can get rid of path splitting and other cruft).

Opinions?

Bye,
     Mike