tcpiper
tcpiper

Reputation: 2544

How to make lua search modules that are in the same folder with the module in which require is called first?

say I've a project folder like:

mxn:lab axn$ tree .
.
├── lib
│   ├── a.lua
│   └── b.lua
└── main.lua

where main.lua:

require("lib.a")

and in a.lua I just use the string "b", trying to tell lua - find a file whose name is b.lua in the same folder of a.lua first:

require("b")

and b.lua:

print('b loaded!')

then I run command lua main.lua and get error:

[Running] lua "/Users/axn/lab/main.lua"
lua: ./lib/a.lua:1: module 'b' not found:
    no field package.preload['b']
    no file './b.lua'
    no file '/usr/local/share/lua/5.1/b.lua'
    no file '/usr/local/share/lua/5.1/b/init.lua'
    no file '/usr/local/lib/lua/5.1/b.lua'
    no file '/usr/local/lib/lua/5.1/b/init.lua'
    no file './b.so'
    no file '/usr/local/lib/lua/5.1/b.so'
    no file '/usr/local/lib/lua/5.1/loadall.so'
stack traceback:
    [C]: in function 'require'
    ./lib/a.lua:1: in main chunk
    [C]: in function 'require'
    /Users/axn/lab/main.lua:1: in main chunk
    [C]: ?

I know solutions like package.path = package.path..';'..'lib/?.lua', but what if the structure changes to:

.
├── foo
│   └── lib
│       ├── a.lua
│       └── b.lua
└── main.lua

I don't want to modify the package.path again. No matter what the structrue is, require("b") in a.lua will always make lua to search b in the same folder of a.lua first.

Upvotes: 4

Views: 1684

Answers (2)

DarkWiiPlayer
DarkWiiPlayer

Reputation: 7056

Generally speaking, you shouldn't do that. Using . in require is meant for submodules, but neither a nor b are submodules of some lib module; that's just where you're putting your modules to keep them organized.

package.path exists for exactly this reason. You can just do something like this:

package.path = './lib/?.lua;./lib/?/init.lua;' .. package.path

And Lua will now search for modules in the lib directory (in addition to where it usually does).

You can also use the LUA_PATH environment variable to do this before even starting Lua.


Otherwise, if you really don't want to use the "proper" way of using package.path, try putting this at the top of a.lua:

print(...)

and it should print something like

lib.a ./lib/a.lua

That should get you to how you want it to work.

Upvotes: 3

Nicol Bolas
Nicol Bolas

Reputation: 473447

Rather than rewriting require and affecting the behavior of all code everywhere, it's best to create a special function for this purpose:

--Utility function for Lua 5.1, which table.pack can do in 5.2+
function pack_params(...)
    return {n = select("#", ...), ...}
end

local curr_local_path = ""

function require_local_path(local_path, ...)
    --Store the old paths on the stack.
    local old_path = package.path
    local old_local_path = curr_local_path

    --Build the new search path and add it to the front of the package.path.
    curr_local_path = curr_local_path .. local_path
    package.path = "./" .. curr_local_path .. "?.lua;" .. package.path

    --Perform the require, storing the results temporarily.
    local rets = pack_params(require(...))

    --Fix the prior paths.
    package.path = old_path
    curr_local_path = old_local_path

    return unpack(rets, 1, rets.n)
end

Note that this function forces you to separate the local path from the name of the module being required. The given local_path is always expected to be local to the most recent nested call of require_local_path. It is also expected to end in a / directory separator character.

If you absolutely must give it a single string rather than a separate path, I'm sure you can write a version of this which splits the given module into a base name and a local path.

Upvotes: 2

Related Questions