lua-users home
lua-l archive

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


On Apr 14, 2014, at 11:03 AM, Enrique Garcia Cota <kikito@gmail.com> wrote:

> I've written a series of articles about building Lua modules - it's here:
> 
> http://kiki.to/blog/2014/03/30/a-guide-to-building-lua-modules/
> 
> I would appreciate any feedback or comments on it.

All-in-all, very nice. Thanks for sharing.

FWIW, here is the anatomy of a prototypical module ‘ façon grand-mère’, circa Lua 5.2.

01 do --8<--
02 
03 --------------------------------------------------------------------------------
04 -- Import
05 --------------------------------------------------------------------------------
06 
07 local getmetatable = getmetatable
08 local setmetatable = setmetatable
09 local module = require( 'module' )
10 
11 --------------------------------------------------------------------------------
12 -- Module
13 --------------------------------------------------------------------------------
14 
15 local _ENV = module( 'IMAP' )
16 local self = setmetatable( _M, {} )
17 local meta = getmetatable( self )
18 
19 _VERSION = ‘1.0.0’
20 
21 --------------------------------------------------------------------------------
22 -- Main
23 --------------------------------------------------------------------------------
24 
25 end -->8—

Line 01-25 do/end block to denote the beginning and end of the module scope. Serves both as a visual marker and as a scope marker when concatenating multiple modules into one file.

Line 03-09 Import section. Explicitly localize all external dependencies. Both for clarity and local access.

Line 15 Naming and sealing of module. No external references after this point. Everything defined in terms of the module _ENV, which happen to be the module itself. 

Line 16-17 Convenience aliases to the module and its metatable.

Line 19 Various optional module level information, e.g. _VERSION.

Line 26 None. No return statement.  Allows for packaging of multiple modules per file.


The ‘module’ function itself mimics the behavior of the 5.1 module, by registering the module with package.loaded and providing various default aliases (_M, _NAME, _PACKAGE, etc ):

local function module( aName, ... )
  local aModule = package.loaded[ assert( aName ) ]

  if type( aModule ) ~= 'table' then
    aModule = {}
    aModule._M = aModule
    aModule._NAME = aName
    aModule._PACKAGE = aName:sub( 1, aName:len() - ( aName:reverse():find( '.', 1, true ) or 0 ) )

    package.loaded[ aName ] = aModule

    for anIndex = 1, select( '#', ... ) do
      select( anIndex, ... )( aModule )
    end
  end

  return aModule
end


In the memorable words of Porky Pig, "Th-th-th-that's all folks!"