如何在不失去灵活性的情况下组织Lua模块路径并编写"require"调用?



假设我有一个项目,其文件夹结构如下:

| 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.loarequire "model.b"

视图/a.loarequire "view.b"

但如果我这样做,每次更改文件夹结构时都必须修改这些文件。

所以我的问题是:

  1. 如何在模块文件中没有硬代码路径的情况下修复模块路径问题
  2. 为什么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.luaview/a.lua之间的歧义。

如何在模块文件中没有硬代码路径的情况下修复模块路径问题?

我没有更好的跨平台解决方案,也许你应该尽早规划文件夹结构。

为什么Lua不使用Node.js的模块搜索规则,这看起来更容易?

因为Lua尽量只依赖ANSI C,这真的很成功。在ANSI C中,没有这样的目录概念。

您可以使用以下几种方法。

您可以将相对路径添加到此SO答案中的package.path。在您的情况下,您可能希望在main.lua中添加与访问文件的各种方式相对应的路径。这将使在将目录结构更改为一个文件时所需的所有更改保持在本地。

您可以使用debug.getinfopackage.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"

最新更新