In the Java LuaJ library I would like to know how to require or import a lua script of functions in another lua script called by a lua closure through Java. For example this does not work:
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();
}
And the input stream here refers to the contents of another lua:
import 'mycoolmathfunctions'
-- or maybe require mycoolmathfunctions ?
return sum({1, 2, 3})
-- or maybe mycoolmathfunctions.sum({1, 2, 3}) ?
How do I do this?
Lua offers a higher-level function to load and run libraries, called require . Roughly, require does the same job as dofile , but with two important differences. First, require searches for the file in a path; second, require controls whether a file has already been run to avoid duplicating the work.
Lua can be used with primary programming languages like C, C++, Java, C#, etc.. and other scripting languages like Perl and Ruby, further extending its usability.
The dofile builtin function can be used to execute a chunk of code stored in a file. In the following example, we have two files main. lua and sayit.
In the Java LuaJ library I would like to know how to require or import a lua script of functions in another lua script called by a lua closure through Java.
You can place your Lua libraries as resources in your Java packages. Then on your lua script that requires another lua script, you require
them relative to your package path.
Here's an example:
Here's our import-me.lua
:
-- make our sample module table global
my_imported = {}
function my_imported.printHello()
print "Hello!"
end
return my_imported
Which is then imported in our sample-that-imports.lua
:
require "com.example.import-me"
my_imported.printHello()
Then we run our sample-that-imports.lua
in our SampleMain
Java class:
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();
}
}
Now to answer your other problems,
For example this does not work…
I've noticed on your Java code that you've assumed that calling loadfile()
would automatically run your lua script. Furthermore, you've assumed that loadfile()
is used for loading your lua modules. However, this isn't how it is supposed to be used.
Your loadfile()
should be able to return a LuaValue
that you need to call()
to run the script itself. You could even safely cast it to a LuaClosure
because this is what loadfile()
actually returns.
To fix your Java code above, you can use this,
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();
}
I will assume in the above code that you are already using require
in the InputStream
(containing a lua script) that you have passed with the above method. If not then, you can do the following changes:
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();
}
In the above changes, I am assuming that your lua module (in our example import-me.lua
) automatically creates a global space for itself (in our example, the my_imported
table). If not, you could do this final touch:
...
LuaValue chunk = globals.load("my_imported = require 'com.example.import-me';");
...
You also should reuse your Globals
(returned by JsePlatform.standardGlobals()
) unless you really want to create a new Globals
table every time you call your method. Furthermore, if you really don't need an InputStream
, and simply wants to load the file itself from its file path (or resource path in your Java package path), you can simplify everything into this:
public static LuaValue runLuaFile(Globals globals, String luafile) {
return globals.loadfile(luafile).call();
}
Or to ensure that our lua module is always imported (or has been require
'd) by our 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();
}
Again, you must specify the complete resource path for our lua file. Here's a sample Java snippet using our simplified method above:
Globals globals = JsePlatform.standardGlobals();
runLuaFile(globals, "com/example/sample-that-imports.lua");
I hope this helps!
You've mentioned in the comments that you need to import lua modules from InputStream
s. There are 2 ways to achieve that:
require
mechanism, you'll have a lot of problems to face.package.preload
, mapped with a key as its name (to be used by require
).We'll use the second method above, as this is exactly what lua's require
mechanism really intends. Here's how to implement it using 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);
}
The above utility method pre-loads an InputStream
to be used by require
. Here's an example usage:
Somewhere in the beginning of everything, we initialize stuffs:
...
preloadLuaModule(globals, "sample_module", sampleModuleInputStream);
...
And our sampleModuleInputStream
above is a lua module with the following content:
-- make our sample module table global
sample_module = {}
function sample_module.printHi()
print "Hi!"
end
return sample_module
Then we could simply use require "sample_module"
anywhere we like, be it in a Lua script or in Java using LuaJ:
globals.get("require").call("sample_module");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With