9

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

| main.lua
|
|---<model> // this is a folder
|    |a.lua
|    |b.lua
|
|---<view>
     |a.lua
     |b.lua

model/a.lua 需要model /b.luarequire "b"

view/a.lua 需要view /b.luarequire "b"

main.lua 需要modelview中的文件。


现在我无法正确加载这些模块。我知道我可以通过将 require 调用更改为:

模型/a.luarequire "model.b"

查看/a.luarequire "view.b"

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

所以我的问题是:

  1. 如何在模块文件中没有硬代码路径的情况下解决模块路径问题?
  2. 为什么 Lua 不使用 Node.js 的模块搜索规则,看起来更简单?
4

4 回答 4

7

当你require是一个模块时,字符串参数 fromrequire被传递到你可以使用 variable-argument syntax 访问的模块...。您可以使用它来包含与当前正在编辑的模块位于同一路径require中的其他依赖模块,而无需使其依赖于固定的硬编码模块名称。

对于你的例子,而不是这样做:

-- 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, then control/subcontrol/foobar/a.lua(以前view/a.lua)现在将尝试 requirecontrol/subcontrol/foobar/b.lua并“做正确的事情”。

当然main.lua仍然需要完全限定路径,因为您需要某种方式来消除和之间的model/a.lua歧义view/a.lua

于 2013-08-10T01:25:14.450 回答
2

您可以使用几种方法。

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

您可以添加绝对路径来package.path使用debug.getinfo- 这可能会更容易一些,因为您不需要考虑所有相对访问,但是在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-09T19:49:57.793 回答
2

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

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

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

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

于 2013-08-09T16:30:41.367 回答
1

解决方案是将main.lua(项目根目录)的文件夹添加package.pathmain.lua.

一种支持 1 级深度文件夹的简单方法:

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

注意 for requires in (project root) 将在项目根目录之外查找文件,这是不可取的。

使用某些库(例如:pathspenlight)来解析绝对路径并添加它的更好方法:

-- 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"
于 2016-08-07T01:37:47.360 回答