[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Basic, no fuss, no magic, foolproof module pattern. [Was: require, module, globals and "magic"]
- From: Lorenzo Donati <lorenzodonatibz@...>
- Date: Tue, 17 Aug 2010 17:45:39 +0200
Hi all!
[Warning: long post ahead]
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).
What I'm trying to assess here is whether the following approach (very
basic, avoiding as much "magic" and "debug" library support as possible)
is reasonably foolproof and safe.
Note that it is a rather "verbose" solution, and that's an intended
trade-off for (hopefully) better encapsulation, less "baggage", and good
performance (thanks to heavy use of locals), all under an "avoid globals
like The Plague" approach.
Are there pitfalls/caveats in this approach (under the assumption that
the debug library is not used to tamper with the "module system")?
If every module in the system had this structure, would I be safe from
side effects from other modules/components/scripts (directly or
indirectly loaded, either with "require" or with "loadXXX" functions)?
Am I missing something or assuming too much?
Any comments appreciated!
TIA
--- Lorenzo
Currently my modules have the following structure (Lua 5.1.4 assumed):
-- mymodule.lua (placed in directory a\b\c on Lua's search path)
-- if needed to locate other components:
local module_dir = debug.getinfo(1, "S").source:match[[^@[^\/]-$]] and
"." or debug.getinfo(1, "S").source:match[[^@?(.*)[\/][^\/]-$]]
local print = print
local setfenv = setfenv
local setmetatable = setmetatable
local table_concat = table.concat
-- ... other "localization" of needed standard globals
local M_ENV = {} -- just a sink for unintended global accesses, not used
internally
setfenv(1, M_ENV)
local M = {} -- module table (will be "exported" to outer world)
-- "requiring" of external modules goes here:
local extmod = require "org.lua.morecoolstuff"
-- example of private data and function:
local x = 12
local function helper() --[[ do stuff ]] end
-- example of function to be exported:
local function M_MyCoolFunc(a,b,c)
--[[ do stuff ]]
end
-- "declare" M_MyCoolFunc to be exported
M.MyCoolFunc = M_MyCoolFunc
-- instead of simply "return M", so what gets
-- into "package.loaded" is read-only:
return setmetatable({}, { __index = M, __metatable = "locked",
__newindex = function()
error "attempt to write to read-only table"
end })
-- end mymodule.lua
-- module usage:
local mymod = require "a.b.c.mymodule" --> module's "namespace" table
mymod.MyCoolFunc("Hep!", 1, 2)
- Follow-Ups:
- Re: Basic, no fuss, no magic, foolproof module pattern. [Was: require, module, globals and "magic"], Matthias Kluwe
- Re: Basic, no fuss, no magic, foolproof module pattern. [Was: require, module, globals and "magic"], Sean Conner