如何组织Lua模块路径并编写“require”调用而不失灵活性?

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

| main.lua
|
|---<model> // 这是一个文件夹
|    |a.lua
|    |b.lua
|
|---<view>
     |a.lua
     |b.lua

model/a.lua 要求 model/b.lua: require "b"

view/a.lua 要求 view/b.lua: require "b"

main.lua 要求 modelview 中的文件。


现在我有问题,无法正确加载这些模块。我知道可以通过更改 require 调用来解决:

model/a.luarequire "model.b"

view/a.luarequire "view.b"

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

所以我的问题是:

  1. 如何在不在模块文件中硬编码路径的情况下解决模块路径问题?
  2. 为什么 Lua 没有使用 Node.js 的模块搜索规则,看起来更容易一些?
点赞
用户1009479
用户1009479

如何在模块文件中不硬编码路径的情况下解决模块路径问题?

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

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

因为 Lua 尽最大努力依赖于 ANSI C,这非常成功。在 ANSI C 中,没有目录的概念。

2013-08-09 16:30:41
用户33252
用户33252

你可以使用一些方法。

你可以添加相对路径到package.path,就像这个SO回答中所示。在你的情况下,你需要在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
2013-08-09 19:49:57
用户234175
用户234175

当您 require 一个模块时,require 命令中的字符串参数传递给该模块,您可以使用变量参数语法 ... 访问它。您可以使用这种方法来包含其他依赖模块,这些模块与当前模块在 相同的路径 中而无需使其依赖于一个固定的硬编码模块名称。

例如,您可以这样做:

-- 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 之间的歧义。

2013-08-10 01:25:14
用户665507
用户665507

解决方法是将main.lua文件夹(项目根目录)添加到main.lua中的package.path中。

一种支持一级深度文件夹的幼稚方法:

-- main.lua
package.path = package.path .. ";../?.lua"

注意,在(项目根目录)中使用的require函数将在项目根目录之外查找文件,这是不可取的。

更好的方法是使用一些库(如:[paths](https://github.com/torch/paths),“penlight”)解析绝对路径并将其添加:

-- main.lua
local projectRoot = lib.abspath(".")
package.path = package.path .. ";" .. projectRoot .. "/?.lua"

然后在源中使用文件夹名称来作用域文件:

-- model/a.lua
require "model.b"
-- 你甚至可以这样做
require "view.b"

-- view/a.lua
require "view.b"
2016-08-07 01:37:47