views:

44

answers:

1

I'm trying to use raw Lua files for configuration purposes, but don't want the config files polluting the global namespace.

The problem I'm running into is that dofile always seems to execute in the real global environment, so external files just throw all their declarations into _G.

Here's an example main file, with comments indicating my wishful thinking.

function myFunc()
    print("In the sandbox:")
    print("Should be 1:", a)  -- falls back to _G for lookup
    a = 2  -- instantiating new global for sandbox
    print("Should be 2:", a)  -- from sandbox
    print("Should still be 1:", _G.a)  -- from host environment

    dofile("loading.lua")  -- here's where things go wrong

    print "\nBack in the sandbox:"
    print("Should be 3:", a)  -- changed by loadfile
    print("Should STILL be 1:", _G.a)  -- unchanged
end

a = 1
local newgt = {} -- new environment
setmetatable(newgt, {__index = _G})
setfenv(myFunc, newgt)
myFunc()

print("\nOutside of the sandbox:")
print("Should be 1: ", a)  -- in theory, has never changed

And the file it's loading (loading.lua:

print ("\nLoading file...")

print("Should be 2: ", a) -- coming from the sandbox environment
a = 3
print("Should be 3: ", a) -- made a change to the environment

And finally the output I'm seeing:

In the sandbox:
Should be 1: 1
Should be 2: 2
Should still be 1: 1

Loading file...
Should be 2:  1
Should be 3:  3

Back in the sandbox:
Should be 3: 2
Should STILL be 1: 3

Outside of the sandbox:
Should be 1:  3
+4  A: 

The problem you describe is also discussed on this page Dofile Namespace Proposal. The solution seemed to be the following replacement for dofile:

function myapp.import(name)
  local f,e = loadfile(name)
  if not f then error(e, 2) end
  setfenv(f, getfenv(2))
  return f()
end

See also: Sand Boxes

gwell
Thanks for the link. To encapsulate the learnings from that page which are relevant to this question: `dofile` **always** operates in the global namespace, ignoring the environment of its calling function. Attempts to directly affect it with `setfenv` raise an error. That same restriction doesn't apply to an anonymous compiled function that gets returned from `loadfile`, so using the code above, you get around this limitation.
SJML
@SJML, exactly. My understanding is that `dofile` is a bit like the stock `print`. It's there for its huge convenience to the novice and learner, especially at the interactive prompt. Serious code would either avoid the function or redefine it to work safely in the real world.
RBerteig