Lua 模块的最佳实践

Lua 模块的最佳实践

在 Lua 世界中,Lua 模块使用 LuaRocks 安装。使用 LuaTeX,这些模块通常安装在文件夹中scripts(在 MikTeX 窗口下)。

有哪些工具可用于下载和安装普通 Lua 包?如何避免冲突?例如,在下面的最小化中,返回kpse.lookup带有目录前缀和不带有目录前缀的正确文件路径。如果两个包都提供模块,这不会造成冲突吗Utilities

%!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}

是否有一种为 LuaTeX 编写和安装模块的标准方法?

答案1

Lua 模块已经发展起来,从 Lua 5.2 开始,您不再需要关键字module。您很可能见过这样写的模块mymodule.lua

   module("mymodule", package.seeall)
        function foo() -- create it as if it's a global function
        print("Hello World!")
    end

请勿使用此格式,因为它现已不再使用。

最小模块示例

Lua 模块通常被编写为只返回一个表。它还保存在具有模块名称的文件中。因此,如果您有一个模块test,则应将其保存为test.lua

-- Module test (saved under test.lua)
local M = M or {}
M.test = function ()
      return "a test"
end
return M

使用模块

可以使用require()函数调用模块。此处的惯例是使用与模块名称同名的局部变量。如果模块名称有点,则使用最后一个点后面的名称。

local test = require"test"

约定的原因是,它有助于帮助记忆长代码中的模块名称,因此您不必向上滚动来查看它的来源。

子模块和包

Lua 允许模块名称分层,使用点分隔名称级别。例如,名为的模块languages.greek是模块的子模块languages包裹是一个完整的模块树,是Lua中的分布单位。

从 Lua 的角度来看,同一个包中的子模块没有明确的关系。 要求一个模块不会自动加载其任何子模块;要求languages.greek将加载greek而不是languagesgreek模块。 如果包要求所有模块,则编写一个初始化模块,然后加载模块的平衡,这是一种很好的做法。

文件夹结构应该遵循一种russian dolls方法,将主模块保存在具有模块名称的文件中。

在哪里开发模块

我认为使用以下 IDE 开发 LuaTeX 模块是一种更好的做法ZeroBrane工作室或者您最喜欢的编辑器,例如 Vim 或 Emacs。模块应该能够独立于 LuaTeX 引擎工作,以便进行适当的测试。稍后将详细介绍这一点。

记录模块

在开发包的模块时,我自己的经验让我相信最好将它们作为自文档化的 lua 使用卢阿多克或者目录,而不是直接进入ltxdoc\docstrip方法。这样就可以使用 IDE 和代码开发流量更容易。一旦您对代码满意,就可以将其转换为 |.dtx| 以便于分发。这很容易生成,就像使用以下方法生成的其余包文件一样:

\nopreamble\nopostamble
\generate{
  \file{mymodule.lua}{\from{\jobname.dtx}{mymodule}}
}

模块除了其 Lua 注释字符串之外,可能还具有内置标识表,例如:

-- module name
-- cldr based greek translation strings for territories
-- as defined by unicode

local m = m or {}

  m =  {
    el =  {
      identity =  {
        version =  {
          _cldrVersion = "26",
          _number = "$Revision: 10809 $",
          _version = '1.01',
          _author = "some name"
        },
        generation =  {
          _date = "$Date= 2014_08_14 15=10=07 _0500 (Thu, 14 Aug 2014) $"
        },
       },
  ...
  return m

也可以使用luatexbase版本控制和模块加载与注册的样式。这又把我们带回到路径问题,这在使用 Lua 和 LuaTeX 进行开发时很麻烦。

路径

更准确地说,当 LuaTeX 请求foo.bar(或foo.bar.lua)时,它首先查找文件foo/bar)时,它首先使用帕西阿使用扩展名.lua,然后对于foo.bar,删除可能的扩展名。因此,为了找到模块,它需要位于Kpathsea查找 Lua 文件的目录中。如果您只有一个文件,您可以在与 |.tex| 文件相同的文件夹中找到它。当您需要无法找到的文件时,kpathsea错误消息将指向所有搜索过的目录,这可以提示您需要在哪里找到模块才能让 LuaTeX 访问它们。

安装 Lua 软件包(来自 Lua 存储库,例如卢阿罗克斯)不会自动将它们提供给 LuaTeX。到目前为止,我发现最好的方法是使用git安装它们。例如安装笔灯,它有一组有用的实用程序,在您的机器上导航到您的\scripts发行版中的目录并输入:

 git clone https://github.com/stevedonovan/Penlight.git 

安装后,您必须更新分发数据库。

关注点分离

为 LuaTeX 编写的许多实用程序和模块可能在 TeX 世界之外有一个实用程序,因此我认为将纯 Lua 代码拆分在其自己的模块中并将任何导出到 LuaTeX 的代码拆分在单独的模块中是一种很好的tex.print做法。Lua 通过节点之一或类似节点与 TeX 对话,这些节点最好位于不同的模块中。此外,最好也有一些测试 Lua 代码。

下面是一个较长的例子来说明讨论。创建 MWE 如下:

%!TEX TS-program = lualatex
\documentclass{article}
\usepackage{luatexbase}
\usepackage{luacode}
\begin{document}

\begin{luacode}
local f = kpse.lookup('cmd', {format = "lua"})
-- success
tex.print("\\par",f)
local cmd = require("cmd")
local csname, def = cmd.csname, cmd.def
csname('test', 'this is a test in csname')

def('test', 'this is a test')
\end{luacode}

\test
\makeatletter
\@test
\end{document}

这个 MWE 将是我们对 中的模块的测试LuaLaTeX。我们将在 Lua 接口包中创建一个名为 的模块cmd,它将使用\defs 或创建宏csname。代码如下。

---
-- module cmd
-- 
-- require main  (not provided in example)
local m = m or {}
local print = print

if type(tex)== "table" then   
   print = tex.print
end

m.csname = function (a, b) 
  return print("\\expandafter\\gdef\\csname"..'@'..a.."\\endcsname{"..b.."}")
end  

m.def = function (a, b) 
  return print("\\gdef\\"..a.."{"..b.."}")
end  

return m

print请注意,在文档中或纯 Lua 测试期间,都使用 进行打印。我们只是测试是否tex可用并重新定义该print函数。

它的 Lua 测试可以放在单独的文件或模块中(如果我们有很多测试)。我们将该文件命名为test_cmd

--- cmd_test

local cmd = require("cmd")

local csname, def = cmd.csname, cmd.def
csname('test', 'this is a test in csname')

def('test', 'this is a test')

总之,任何模块都应该有一个相关的模块代码,用于TeX测试。LuaTeX 包应该包含以下内容

-Lua 模块(我们在上面的例子中没有创建)

- 与 LuaTeX 接口的相关 Lua 模块(如上例所示)

-测试模块(针对 TeX 和 Lua)

以上是我迄今为止的个人经历,不要把它们视为一成不变的。LuaTeX 团队打开了这样一个潘多拉魔盒,人们第一次可以开始思考正确的结构良好的代码。再多的TeX黑客攻击也无法取代复杂的编程,比如正确的国际化一个包或json从一个网站获取响应,然后使用 Lua 打印表格。

相关内容