lua-users home
lua-l archive

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


In 5.1, one could do the following out-of-the-box, courtesy of module:

(1) define a self-contained, self-registered  module with a one-liner

(2) define multiple modules per source file

(3) package multiple lua source files into one file, courtesy of cat, without further ado

(4) package multiple lua source files into one compiled file, courtesy of luac -o, without further ado


Not so much with 5.2 as:

(a) module is deprecated
(b) even though module is still defined and enabled by default, its implementation is not backward compatible in terms of (2), (3) and (4) which renders it rather pointless and dangerous


So what to do to get the same level of functionality in 5.2?


To allow for feature parity with 5.1, it looks like in 5.2 a module might need to be defined as follow:

do -- (I) module block
  local package = require( 'package' )
  local _ENV = {} -- (II) self-contained environment

  -- module implementation

  package.loaded[ 'module' ] = _ENV -- (III) self-registration
end

(I) The block provides support for multiple module per file (2), and concatenation of source files (3)
(II) _ENV provides a self-contained environment 
(III) package.loaded provides self-registration


So instead of a one-liner as in 5.1, in 5.2 one now needs all of the above boilerplate (block, _ENV, package.loaded) to get functional parity. 

But life goes on, so here is a small reimplementation of module for 5.2:

--8<--

do
  local select = select  
  local package = require( 'package' )
  local _ENV = {}
  
  local function module( aName, ... )
    local aModule = package.loaded[ aName ]
  
    if aModule == nil 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
  
  package.loaded.module = module
end

-->8--


And some usage examples:

$ cat TestA.lua

do
  local print = print
  local module = require( 'module' )
  local _ENV = module( 'TestA' )
  
  print( 'TestA', _NAME, _ENV )
end


$ cat TestB.lua

do
  local print = print
  local module = require( 'module' )
  local _ENV = module( 'TestB' )
  
  print( 'TestB', _NAME, _ENV )
end


$ cat TestC.lua

do
  local print = print
  local module = require( 'module' )
  local TestA = require( 'TestA' )
  local TestB = require( 'TestB' )
  local _ENV = module( 'TestC' )
  
  
  print( TestA, TestB )
  print( 'TestC', _ENV )
end


Run from individual source:

$ lua TestC.lua
TestA	TestA	table: 0x100106150
TestB	TestB	table: 0x100106b00
table: 0x100106150	table: 0x100106b00
TestC	table: 0x100107020


Packaged as one lua file:

$ cat module.lua TestA.lua TestB.lua TestC.lua > TestAll.lua

$ lua TestAll.lua
TestA	TestA	table: 0x100104f70
TestB	TestB	table: 0x100100c50
table: 0x100104f70	table: 0x100100c50
TestC	table: 0x100100d90


Packaged as one luac file:

$ luac -o TestC.luac module.lua TestA.lua TestB.lua TestC.lua

$ lua TestC.luacTestA	
TestA	table: 0x100105b80
TestB	TestB	table: 0x100100b80
table: 0x100105b80	table: 0x100100b80
TestC	table: 0x100105ca0


While the above "works" in terms of (1), (2), (3) and (4), it doesn't strike me as a change for the better as now everyone and their dog will need to re-invent some, part, or variation of the module features, with all the additional chrome, boilerplate and incompatibilities that ensue. Looks like a big step backward altogether.

Anyway, how do people implement their modules in 5.2? With the same level of functionality as in 5.1? 

Feedbacks and suggestions welcome.