lua-users home
lua-l archive

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

Put more simply: how would you rewrite the following suite of files so that the user can "require 'master'" and not spam the global namespace with "MASTER", but still have all the assertions pass?

    ### _test_usage_.lua
    require 'master'
    ### master.lua
    MASTER = {}
    require 'simple'
    require 'multi'
    require 'shared1'
    require 'shared2'
    require 'reference'
    ### simple.lua
    MASTER.Simple = {}
    function MASTER:simple() end
    ### multi.lua
    MASTER.Multi1 = {}
    MASTER.Multi2 = {}
    ### shared1.lua
    MASTER.Shared = {}
    ### shared2.lua
    function MASTER.Shared:go() end
    ### reference.lua
    function MASTER.Simple:ref1() return MASTER.Multi1 end
    function MASTER.Simple:ref2() MASTER:simple()      end

On Feb 18, 2013, at 10:32 AM, Gavin Kistner <> wrote:

On Feb 18, 2013, at 09:59 AM, Justin Cormack <> wrote:
all requires should be assigning to a local variable.
local scxml = {}

scxml.state = require "lib/state"
scxml.event = require "lib/event"

return scxml
This works for the simplest cases I supplied where each file adds exactly one completely independent table to the master. However, I have three more cases that aren't quite as clean:
* Multiple Datatypes per File
* Multiple Files Augmenting the Same Table
* One File Referencing Tables from Another

1) Multiple Datatypes per File
One of the file declares a few (currently-global) new datatypes that are used by various methods throughout. Would you recommend:

    # lxsc.lua
    local LXSC = {}
    ...require others...
    for name,t in pairs(require('lib/datatypes') do LXSC[name]=t end
    return LXSC

    # lib/datatypes.lua
    local Queue = {}; ...
    local OrderedSet = {}; ...
    local List = {}; ...
    return {Queue=Queue, OrderedSet=OrderedSet, List=List}

This is easily worked around by making one file per 'object', but that feels like an ugly burden. Further, while this makes these classes available on the master LXSC table, there is no way for the sub-tables to access this master. Which brings me more explicitly to problem #2:

2) Multiple Files Augmenting the Same Table
Some of the files do not add a new table, but augment another existing table. For example:

    # lxsc.lua
    LXSC = {}
    require 'lib/scxml'
    require 'lib/runtime'

    # lib/scxml.lua
    LXSC.SCXML = {}

    # lib/runtime.lua
    function LXSC.SCXML:go() ... end -- modify a table defined elsewhere

If there was only one case like this, I could 'invert' the hierarchy like so:

    # lxsc.lua
    local LXSC = {}
    LXSC.SCXML = require 'lib/runtime'
    return LXSC

    # lib/runtime.lua
    local SCXML = require 'lib/scxml'
    function SCXML:go() ... end -- modify a table defined elsewhere
    return SCXML

    # lib/scxml.lua
    local SCXML = {}
    return SCXML

...but that technique does not work when multiple files augment the same datatype. Is there a pattern that allows multiple files to work on the same common table without polluting the global namespace?

3) One File Referencing Tables from Another
Various files and methods need to talk to other high-level objects in the system. For example:

    # lib/parse.lua
    function LXSC:parse(...) -- augments the master table
      local name = getSomeNameString()
      local object = LXSC[name]() -- dynamically picks methods from the master table

    # lib/transition.lua
    function Transition:addTarget(...)
      self.targets = LXSC.List() -- accesses a datatype from the namespace

How would I cause the master table to be exposed to each child file that needs to access it?

Is setfenv() the proper way to go about all this? Is there something better?

On Mon, Feb 18, 2013 at 2:43 PM, Gavin Kistner <> wrote:
On Feb 17, 2013, at 10:15 PM, Miles Bader <> wrote:

> Gavin Kistner <> writes:
>> * Adds only a single `SLAXML` key to the environment; there is no spam
>> of utility functions polluting the global namespace.
> It should not add _any_ keys to the global environment.
>> ## Usage
>>    require 'slaxml'
> local slaxml = require 'slaxml'

Thank you for the suggestion. I've updated the library to use this pattern.

This works fine for this project where I only have two files. How would others suggest enforcing the same pattern for a different project that has many files all augmenting the same table?

For example, in LXSC[1] I currently have 10+ files like so:


and I use this to build the common object like so:

    # lxsc.lua
    LXSC = { VERSION="0.3.1" }
    require 'lib/state'
    require 'lib/scxml'
    require 'lib/event'

    # lib/event.lua
    LXSC.Event = { ... }

    # lib/scxml.lua
    LXSC.SCXML = { ... }

    # lib/state.lua
    LXSC.State = { ... }

How might I modify this small multiple of files to work together in a way that doesn't spam the global namespace?

I can't do something like:

    # lxsc.lua
    local LXSC = { VERSION="0.3.1" }
    require 'lib/state'
    return LXSC

    # lib/state.lua
    local LXSC = require 'lxsc'
    LXSC.State = { ... }

…because that causes a loop in the loader. Should I instead do this?

    LXSC = { VERSION="0.3.1" } # Spam the global for now
    require 'lib/state'
    require 'lib/scxml'
    require 'lib/event'
    local LXSC = LXSC
    _G.LXSC = nil # remove the global spam
    return LXSC

Your experienced advice is requested :)