In the Lua world Lua Modules are installed using LuaRocks. With LuaTeX these modules are normally installed in the scripts
folder (under MikTeX windows).
What tools are available for downloading and installing normal Lua packages? How can one avoid conflicts? For example in the minimal below the kpse.lookup
returns the correct file path both with a directory prefix and without. Wouldn't this create a conflict, if two packages offer a Utilities
module?
%!TEX TS-program = lualatex
\documentclass{article}
\usepackage{luatexbase}
\usepackage{luacode}
\begin{document}
\begin{luacode}
local path = "luaotfload/"
local filename = "mkstatus"
local src = path..filename
local filename = path.."mkstatus"
local srcdots = "luaotfload.mkstatus"
local f = kpse.lookup(filename, {format = "lua"})
local f1 = kpse.lookup(src, {format = "lua"})
-- success
tex.print("\\par",f)
tex.print("\\par",f1)
-- local mkstatus = require("mkstatus")
\end{luacode}
\end{document}
Is there a standard way for writing and installing modules for LuaTeX?
Best Answer
Lua modules have evolved and since Lua 5.2 you do not need the keyword
module
. Most probably you have seen modules written asmymodule.lua
:Do not use this format as it is now depreciated.
Minimal module example
A Lua module is typically written so that it just returns a table. It is also saved in a file with the module's name. So if you have a module
test
, you should save it astest.lua
Using the module
The module can be called by using the
require()
function. The convention here is to use a local variable with the same name as the module's name. If the module name has dots then use the name after the last dot.The reason for the convention, is that it helps as a mnemonic for the module's name in long code, so you do not have to scroll up to see where it originated.
Submodules and packages
Lua allows module names to be hierarchical, using a dot to separate name levels. For instance a module named
languages.greek
is a submodule of the modulelanguages
. A package is a complete tree of modules and it is the unit of distribution in Lua.From the point of view of Lua, submodules in the same package have no explicit relationship. Requiring a module does not automatically load any of its submodules; requiring
languages.greek
will loadgreek
and not thelanguages
andgreek
modules. It is good practice, if the package requires all the modules to write an initialization module that then loads the balance of the modules.The folder structure should follow a
russian dolls
approach with the main module saved in a file with the modules name.Where to develop modules
It is in my opinion a better practice to develop LuaTeX modules using an IDE such as ZeroBrane Studio or your favourite editor such as Vim or Emacs. The modules should be able to work independently of the LuaTeX engine, to enable proper testing. More about this later.
Documenting the Modules
While developing the modules for a package, my own experience leads me to believe that it is better to have them as self documented lua using luadoc or Ldoc, rather than heading straight into the
ltxdoc\docstrip
method. This enables the use of an IDE and the code development flows easier. Once you are satisfied with the code this can be transferred into a |.dtx| for easy distribution. This is easily generated as the rest of the package files using:A module besides its Lua comment strings might have build-in identification tables, for example:
One can also use luatexbase style for versioning and loading and registering the modules. This brings us back to paths, which is a pain when developing in Lua and LuaTeX.
Paths
More precisely, when LuaTeX asks for
foo.bar
(orfoo.bar.lua
), it first looks for filefoo/bar
using Kpathsea with the extension.lua
, and then forfoo.bar
, removing the possible extension. So in order for a module to be found it needs to be in a directory whereKpathsea
looks for Lua files. If you only have one file, you can locate it in the same folder as your |.tex| files. When you require a file thatkpathsea
cannot find the error message will point you to all the directories that were searched and this can give you a hint as to where you need to locate modules to have them accessible to LuaTeX.Installing Lua packages (from Lua repositories such as Luarocks) will not automatically make them available to LuaTeX. So far the best method I have found, is to use
git
to install them. For example to install penlight, which has a set of useful utilities on your machine navigate to your\scripts
directory in your distribution and type:After the installation, you will have to update the distribution database.
Separation of concerns
Many utilities and modules, written for LuaTeX might have a utility outside the TeX world so it is good practice, in my opinion to split the pure Lua code in its own module and any code exporting to LuaTeX in a separate module. Lua talks to TeX via one of the
tex.print
and or similar for nodes and these should preferably be in different modules. Also it is good practice to also have some testing Lua code.Here is a somewhat longer example to illustrate the discussion. Create a MWE as follows:
This MWE will be our test of the module in
LuaLaTeX
. The interface Lua package we will create a moudle calledcmd
that it will create macros using\def
s orcsname
. The code is below.Note the use of
print
for both printing within a document or during pure Lua tests. We simply test iftex
is available and redefine theprint
function.Its Lua tests can be at a separate file or module (if we have a lot of tests). We name thsi file
test_cmd
In summary any module should have an associated module code for
TeX
and also for testing. A LuaTeX package should consist of-Lua Modules (this we have not created in the example above)
-Associated Lua Modules interfacing with LuaTeX (as per example above)
-Testing modules (both for TeX as well as Lua)
The above has been my own personal experience so far, don't treat them as cast in stone. The LuaTeX Team has opened such a pandora's box and for the first time one can start thinking of proper well structured code. No amount of
TeX
hacking can ever replace complicated programming such as properly internationalizing a package or obtainingjson
responses from a website and then printing a table using Lua.