假设我有一个项目,其文件夹结构如下:
| main.lua
|
|---<model> // this is a folder
| |a.lua
| |b.lua
|
|---<view>
|a.lua
|b.lua
型号/a.loa要求模型/b.loarequire "b"
视图/a.loa请求查看/b.loarequire "b"
main.loa请求模型和视图中的文件。
现在我在正确加载这些模块时遇到了问题。我知道我可以通过将require调用更改为:来修复它
型号/a.loa:require "model.b"
视图/a.loa:require "view.b"
但如果我这样做,每次更改文件夹结构时都必须修改这些文件。
所以我的问题是:
- 如何在模块文件中没有硬代码路径的情况下修复模块路径问题
- 为什么Lua不使用Node.js的模块搜索规则,这看起来更容易
当require
是一个模块时,require
中的字符串参数会传递到您可以使用变量参数语法...
访问的模块中。您可以使用它来包括与require
ed的当前模块位于相同路径中的其他依赖模块,而无需使其依赖于固定的硬编码模块名称。
举个例子,而不是做:
-- model/a.lua
require "model.b"
和
-- view/a.lua
require "view.b"
你可以做:
-- model/a.lua
local thispath = select('1', ...):match(".+%.") or ""
require(thispath.."b")
和
-- view/a.lua
local thispath = select('1', ...):match(".+%.") or ""
require(thispath.."b")
现在,如果您更改目录结构,例如将view
移动到类似control/subcontrol/foobar
的位置,那么control/subcontrol/foobar/a.lua
(以前的view/a.lua
)现在将尝试要求使用control/subcontrol/foobar/b.lua
并"做正确的事情"。
当然,main.lua
仍然需要完全限定路径,因为您需要一些方法来消除model/a.lua
和view/a.lua
之间的歧义。
如何在模块文件中没有硬代码路径的情况下修复模块路径问题?
我没有更好的跨平台解决方案,也许你应该尽早规划文件夹结构。
为什么Lua不使用Node.js的模块搜索规则,这看起来更容易?
因为Lua尽量只依赖ANSI C,这真的很成功。在ANSI C中,没有这样的目录概念。
您可以使用以下几种方法。
您可以将相对路径添加到此SO答案中的package.path
。在您的情况下,您可能希望在main.lua
中添加与访问文件的各种方式相对应的路径。这将使在将目录结构更改为一个文件时所需的所有更改保持在本地。
您可以使用debug.getinfo
向package.path
添加绝对路径——这可能会稍微容易一些,因为您不需要考虑所有的相对访问,但在更改目录结构时,您仍然需要在main.lua
中这样做,并且您需要对debug.getinfo
返回的值进行字符串操作,以剥离模块名称并添加子目录名称。
> lunit = require "lunit"
> info = debug.getinfo(lunit.run, "S")
> =info.source
@/usr/local/share/lua/5.2/lunit.lua
> =info.short_src
/usr/local/share/lua/5.2/lunit.lua
解决方案是将main.lua
(项目根)的文件夹添加到main.lua
中的package.path
中。
一种支持1级深度文件夹的天真方法:
-- main.lua
package.path = package.path .. ";../?.lua"
注意(项目根目录)中的
require
s将查找项目根目录之外的文件,这是不可取的。
使用某些库(例如:路径、penlight)来解析绝对路径并添加它的更好方法是:
-- main.lua
local projectRoot = lib.abspath(".")
package.path = package.path .. ";" .. projectRoot .. "/?.lua"
然后在源文件中使用文件夹名称来确定文件的范围:
-- model/a.lua
require "model.b"
-- you can even do this
require "view.b"
和
-- view/a.lua
require "view.b"