Я написал скрипт для горячей перезагрузки уже require
ed модулей. Однако это работает лишь частично...
Мой подход к этой задаче довольно прост. Я изменил функцию Lua require
, чтобы она запоминала загруженные модули вместе с меткой времени и путем к файлу. Затем я использую сценарий оболочки, чтобы наблюдать за временем модификации этих файлов и повторно запрашивать их, если они изменились. Я просто dofile()
и, если ошибок не происходит, я беру возвращаемое значение и (повторно) присваиваю его package.loaded[<module>]
. Все идет нормально.
Все это отлично работает, когда я использую глобальные переменные, например. foo = require "foobar"
, но когда я использую локальные назначения, такие как local foo = require "foobar"
, моя горячая замена выходит из строя (частично)!
Кажется, что пакет выгружается, как и предполагалось, однако локальная переменная (из приведенного выше назначения) по-прежнему содержит старую ссылку или старое значение, полученное при первом вызове require.
Моя идея состояла в том, чтобы использовать функции Lua debug.getlocal
и debug.setlocal
для поиска всех локальных переменных (значений вверх в стеке) и обновления их значений/ссылок.
НО я получаю сообщение об ошибке, что значение, которое я хочу изменить, находится "вне диапазона"... Может ли кто-нибудь помочь мне, пожалуйста? Что мне делать или как я могу обойти это?
Полный код находится на Gist, однако важные/уместные фрагменты...
- функция
local_upvalues()
в строке 27, которая собирает все доступные значения upvalue
local function local_upvalues()
local upvalues = {}
local failures = 0
local thread = 0
while true do
thread = thread + 1
local index = 0
while true do
index = index + 1
local success, name, value = pcall(debug.getlocal, thread, index)
if success and name ~= nil then
table.insert(upvalues, {
name = name,
value = value,
thread = thread,
index = index
})
else
if index == 1 then failures = failures + 1 end
break
end
end
if failures > 1 then break end
end
return upvalues
end
- и
debug.setlocal()
в строке 89, которая пытается обновить upvalue, содержащее ссылку на устаревший модуль.
-- update module references of local upvalues
for count, upvalue in ipairs(local_upvalues()) do
if upvalue.value == package.loaded[resource] then
-- print(upvalue.name, "updated from", upvalue.value, "to", message)
table.foreach(debug.getinfo(1), print)
print(upvalue.name, upvalue.thread, upvalue.index)
debug.setlocal(upvalue.thread, upvalue.index, message)
end
end
package.loaded[resource] = message -- update the absolete module