lua-users home
lua-l archive

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


It was thus said that the Great Lorenzo Donati once stated:
> 
> I realized the discussion on the originating thread was hitting the 
> limits of my Lua knowledge, so I'm starting a new thread to avoid adding 
> noise to it with "newbie stuff".
> 
> All the discussions about environments, globals and modules have 
> confused me a bit (especially after rereading what's in the WIKI about it).
> Therefore I'd like to receive comments on my current practice when it 
> comes to write a new module (nothing original below, just a concoction 
> of what I read and learned about modules from the list and WIKI in the 
> last months).

  The problem (as I see it) comes down to poluting the global namespace. 
module() basically loads some code and returns it in a new global table
(plus maybe some magic).  I know that when I first started playing around
with Lua modules it wasn't all that intuitive to me.

  Just in the past few days I came up with the following bit of code:

-- **********************************************************************

nmodules       = {}
nmodules.lpath = { "./?.lua" }
nmodules.cache = {}

-- **********************************************************************

function loadtoenv(fname)
  local env   = setmetatable({} , { __index = _G } )
  local f,err = loadfile(fname)

  if f == nil then
    return nil,nil,err
  end

  setfenv(f,env)
  return f,env
end

-- ***********************************************************************

function nmodule(modname)
  if nmodules.cache[modname] then 
    return nmodules.cache[modname]
  end
  
  for i = 1 , #nmodules.lpath do
    local fname     = string.gsub(nmodules.lpath[i],"%?",modname)
    local f,env,err = loadtoenv(fname)
    if f ~= nil then
      nmodules.cache[modname] = env
      env._NAME = modname
      f()
      return env
    end
  end
  return nil,"module doesn't exist"
end

-- ***********************************************************************

A module then becomes just a Lua file with no other decorations.  Say, a
small utility class:

-- ****[util.lua]*************

function split(s,delim)
  local results = {}
  local delim   = delim or "%:"
  local pattern = "([^" .. delim .. "]+)" .. delim .. "?"
  
  for segment in string.gmatch(s,pattern) do
    table.insert(results,segment)
  end
  
  return results
end

function access(name,mode)
  local file = io.open(filename,mode)

  if file then
    file:close()
    return true
  else
    return false
  end
end

-- ****[end of line]**************

You can then include it with:

silly = nmodule('util')

path = silly.split(os.getenv("PATH"))
if not silly.access('/etc/passwd',"r") then
  print("not on a unix system")
end

  It wasn't hard to convert the one "module"ized project I have to use this
and it removed a bunch of lines of code (module(), local defs, etc).  Any
"globals" in the individual Lua files included via nmodule() become table
members, and it's up to the caller to determine the name under which the
file is located.  

  I don't see why a new method like this can't be accepted, along with the
older method.  

  -spc