Lua require 在不同文件中多次调用 mpack 失败

给定以下完整的 Lua 文件:

-- test/file1_spec.lua
local mpack = require('mpack')
print(mpack)

如果使用 busted 执行该文件,则可以正常工作。

如果将文件更新为在两个地方都加载 mpack:

-- test/file1_spec.lua
local mpack = require('mpack')
print(mpack)
local mpack2 = require('mpack')
print(mpack2)

它仍然可以正常工作。但是如果我添加第二个文件(除了上面的文件之外):

-- test/file2_spec.lua
local mpack = require('mpack')
print(mpack)

那么在此第二个文件中加载 mpack 会导致以下错误:

test/file2_spec.lua:1: attempt to index a mpack.NIL value

require 如何工作?如何在不同的 Lua 文件中加载 mpack?

点赞
用户9783845
用户9783845

mpack 模块本身存在问题,由于某些原因无法加载两次:

-- demo.lua
require('mpack')
-- 从缓存中移除已加载的包,否则包将不会重新加载
package.loaded['mpack'] = nil
require('mpack')
$ lua demo.lua
lua: attempt to index a mpack.NIL value

busted 也会出现这种情况,因为 busted 在测试之间刷新包缓存:

测试环境隔离会保存全局表 _G 和当前加载的包 package.loaded,在 insulate 块完成时将其恢复为其原始状态。

默认情况下,每个测试文件在单独的 insulate 块中运行,可以使用 --no-auto-insulate 标志禁用。

因此,您有几个选项:

  1. 使用 busted --no-auto-insulate 标志。我不建议这样做,因为它完全禁用了隔离。

  2. 使用 busted -e 'require("mpack")'。使用 -e 参数传递的表达式将在任何测试之前执行,因此隔离机制不会删除已缓存的包。

  3. 使用 expose 块:

    ``` -- spec/__init_spec.lua -- 文件名以下划线开头,以确保在任何其他 spec 文件之前处理它。我不知道如何以正确的方式做到这一点(如果可能的话)。

expose('preload mpack module', function() require('mpack') end)

```

请查看https://olivinelabs.com/busted/#defining-tests,“描述:隔离和公开块”部分了解详情。

我稍后会检查 mpack 源代码,也许我可以解决这个问题。

更新:Lua 参考手册中关于 package.loaded 的描述:

表示 require 控制的模块是否已加载的表。当您要求模块 modname 时,如果 package.loaded[modname] 不为 false,则 require 简单地返回存储在那里的值。

https://www.lua.org/manual/5.3/manual.html#pdf-package.loaded

2020-05-28 23:30:12