Luaj: как импортировать или требовать библиотеку функций Lua

В Java LuaJ library Я хотел бы знать, как требовать или импортировать функции lua script в другой lua script вызванный закрытием lua через Java. Например, это не работает:

public static LuaValue runInputStreamLua(InputStream inputStream) throws Exception {
    Prototype luaScriptPrototype = LuaC.instance.compile(inputStream, "");
    Globals luaScriptStandardGlobals = JsePlatform.standardGlobals();
    luaScriptStandardGlobals.loadfile("mycoolmathfunctions.lua");
    LuaClosure luaClosure = new LuaClosure(luaScriptPrototype, luaScriptStandardGlobals);
    return luaClosure.call();
}

И входной поток здесь относится к содержимому другого lua:

import 'mycoolmathfunctions'
-- or maybe require mycoolmathfunctions ?

return sum({1, 2, 3})
-- or maybe mycoolmathfunctions.sum({1, 2, 3}) ?

Как это сделать?

Ответы

Ответ 1

В библиотеке Java LuaJ я хотел бы знать, как требовать или импортировать функции lua script в другой lua script, вызванный закрытием lua через Java.

Вы можете разместить свои библиотеки Lua в качестве ресурсов в своих пакетах Java. Затем на вашем lua script, который требует другого lua script, вы require их относительно вашего пути к пакетам.

Вот пример:

введите описание изображения здесь

Здесь наш import-me.lua:

-- make our sample module table global
my_imported = {}

function my_imported.printHello()
    print "Hello!"
end

return my_imported

который затем импортируется в наш sample-that-imports.lua:

require "com.example.import-me"

my_imported.printHello()

Затем мы запускаем наш sample-that-imports.lua в нашем классе SampleMain Java:

package com.example;
...
public class SampleMain {

    public static void main(String[] args) {
        Globals globals = JsePlatform.standardGlobals();

        // Again, we load the lua scripts relative to our package path
        LuaValue chunk = globals.loadfile("com/example/sample-that-imports.lua");
        chunk.call();

        // We could even use our imported library here
        chunk = globals.load("my_imported.printHello()");
        chunk.call();
    }
}

Теперь, чтобы ответить на ваши другие проблемы,

Например, это не работает & hellip;

Я заметил на вашем Java-коде, что вы предположили, что вызов loadfile() будет автоматически запускать ваш lua script. Кроме того, вы предположили, что loadfile() используется для загрузки ваших модулей lua. Однако это не то, как предполагается, что он будет использоваться.

Ваш loadfile() должен иметь возможность вернуть LuaValue, который вам нужен, чтобы call() запустить сам script. Вы даже можете безопасно применить его к LuaClosure, потому что это то, что действительно возвращает loadfile().

Чтобы исправить код Java выше, вы можете использовать его,

public static LuaValue runInputStreamLua(InputStream inputStream) throws Exception {
    Prototype luaScriptPrototype = LuaC.instance.compile(inputStream, "");
    Globals globals = JsePlatform.standardGlobals();
    LuaClosure luaClosure = new LuaClosure(luaScriptPrototype, globals);
    return luaClosure.call();
}

В приведенном выше коде предполагается, что вы уже используете require в InputStream (содержащий lua script), который вы передали с помощью вышеуказанного метода. Если нет, вы можете сделать следующие изменения:

public static LuaValue runInputStreamLua(InputStream inputStream) throws Exception {
    Prototype luaScriptPrototype = LuaC.instance.compile(inputStream, "");
    Globals globals = JsePlatform.standardGlobals();

    LuaValue chunk = globals.load("require 'com.example.import-me';");
    chunk.call();

    LuaClosure luaClosure = new LuaClosure(luaScriptPrototype, globals);
    return luaClosure.call();
}

В приведенных выше изменениях я предполагаю, что ваш модуль lua (в нашем примере import-me.lua) автоматически создает глобальное пространство для себя (в нашем примере таблица my_imported). Если нет, вы можете сделать это последнее касание:

...
LuaValue chunk = globals.load("my_imported = require 'com.example.import-me';");
...


Вы также должны повторно использовать Globals (возвращенный JsePlatform.standardGlobals()), если вы действительно не хотите создавать новую таблицу Globals каждый раз, когда вы вызываете свой метод. Кроме того, если вам действительно не нужен InputStream, и он просто хочет загрузить файл из своего пути к файлу (или путь к ресурсу в вашем пути к пакету Java), вы можете упростить все это:

public static LuaValue runLuaFile(Globals globals, String luafile) {
    return globals.loadfile(luafile).call();
}

Или для обеспечения того, чтобы наш модуль lua всегда был импортирован (или был require 'd) нашими lua script,

public static LuaValue runLuaFile(Globals globals, String luafile) {
    LuaValue chunk = globals.load("require 'com.example.import-me';");
    chunk.call();
    chunk = globals.loadfile(luafile);
    return chunk.call();
}

Опять же, вы должны указать полный путь к ресурсу для нашего lua файла. Здесь образец фрагмента Java, используя наш упрощенный метод выше:

Globals globals = JsePlatform.standardGlobals();
runLuaFile(globals, "com/example/sample-that-imports.lua");

Надеюсь, это поможет!


Изменить:

Вы упомянули в комментариях, что вам нужно импортировать модули lua из InputStream s. Есть два способа добиться этого:

  • Первым из них является загрузка и запуск модулей lua, которые вам нужны, например простые сценарии lua, - и если в случае, если модули lua, которые вам нужны, совместимы только с lua require, у вас будет много проблемы.
  • Второй, самый простой и эффективный способ - просто загрузить модуль, поместить его в таблицу lua package.preload, отображая ключ как его имя (которое будет использоваться require).

Мы будем использовать второй метод выше, поскольку это именно то, что действительно предполагает механизм lua require. Здесь, как реализовать его с помощью LuaJ:

public static void preloadLuaModule(Globals globals, String modname, InputStream is) {
    LuaValue module = globals.load(is, modname, "bt", globals);
    globals.get("package").get("preload").set(modname, module);
}

Вышеуказанный метод утилиты предварительно загружает InputStream, который будет использоваться require. Вот пример использования:

Где-то в начале всего, мы инициализируем вещи:

...
preloadLuaModule(globals, "sample_module", sampleModuleInputStream);
...

И наш sampleModuleInputStream выше - модуль lua со следующим содержимым:

-- make our sample module table global
sample_module = {}

function sample_module.printHi()
    print "Hi!"
end

return sample_module

Тогда мы могли бы просто использовать require "sample_module" где угодно, будь то в Lua script или на Java, используя LuaJ:

globals.get("require").call("sample_module");