如何编写 arara 规则

如何编写 arara 规则

arara自从我上次更新我的 LaTeX 副本以来,编写规则的语法似乎已经发生了变化。

在我的旧电脑上,以下规则按预期工作:

!config
# open rule for arara
# author: A.Ellett
# requires arara 3.0+
identifier: open
name: PREVIEW
commands:
  - <arara>  @{isTrue ( isFile ("./.design/open.pdf.true"), 
                        "open -a /Applications/Skim.app ".concat(getBasename(file)).concat('".pdf"')
                        ""
                      )}
arguments: []

但在新电脑上我收到以下错误消息:

I have spotted an error in rule "open" located at
"/Users/..../arara/rules/open.yaml". I could
not parse the rule, something bad happened. This part is quite
tricky, since it involves aspects of the underlying data
serialization format. I will do my best to help you in any way I
can. There are more details available on this exception:

DETAILS ---------------------------------------------------------
com.charleskorn.kaml.IncorrectTypeException at commands[0] on
line 8, column 5: Expected an object, but got a scalar value

我不懂这啥意思。

我尝试过查看arara手册,但没找到任何有用的东西。我唯一能找到的是 <arara>不再支持提及。但这让我不知道如何重写它。

有什么建议么?

答案1

遗憾的是,我无法提供关于如何编写正确规则的速成课程,因为在非常有限的空间内需要涵盖很多内容。话虽如此,我会尝试根据您最初的规则评论各个版本中发生更改的内容,然后提供一些更新。:)

(我擅自删除了注释,以便我们可以专注于代码本身)

!config

正确,第一行必须包含对象映射元数据。

identifier: ...
name: ...

这里没有任何变化,所以我们可以开始了。

commands:

到目前为止一切顺利,这里我们有潜在的命令列表。

  - <arara> @{ ...

这不再起作用,原因有二:

  1. 我们从简单条目转向实际结构(系列 4)。每个命令(或文档中称为子任务)都包含在适当的块中。此块中唯一必需的条目是实际命令,由键表示command。因此,而不是:

    - ...
    

    它应该是:

    - command: ...
    
  2. <arara>不再使用简写形式(系列 5 中已弃用,系列 6 中已删除)。相反,我们鼓励使用 YAML 的折叠样式(文档附录涵盖了此主题)。因此,不要使用:

    - command: <arara> @{ ...
    

    它应该是:

    command: >
      @{ ...
    

继续...

isFile(...)

这种方法不再存在(可能是 4.0 系列,记不清了)。原因是我们已经用特定的硬编码方法替换了它,这些方法为toFile(...)我们提供了文件的实际表示。

"open -a /Applications/Skim.app ..."

该工具不再允许使用纯字符串来执行命令。原因之一是命令的字符串操作比较棘手、不稳定且容易出错。从第 4 系列开始,我们引入了 的概念Command,它允许您以安全的方式构建命令。因此,不要使用:

"open -a /Applications/Skim.app ..."

它应该是:

getCommand("open", "-a", "/Applications/Skim.app", ... )

继续。

arguments: []

正确,无可争论。

现在我将提出更新规则的建议。我试图遵循原始规则的思路,但做了一些修改。:)

!config
identifier: open
name: Preview

没什么新鲜事。:)

authors: []

此键是可选的,但为了完整性,我喜欢添加它,即使它是空的。它可以帮助我记住规则格式。

commands:

这里也什么也没有。

- name: Open Skim

虽然这是可选的,但我发现给每个任务添加一个名称很有用。否则,如果您在工作流程中遇到问题,该工具将使用未命名的引用,这不太容易理解。:)

  command: >
    @{

太棒了,折叠样式。现在我们可以添加规则逻辑了。

        if (exists(toFile("./.design/open.pdf.true"))) {

这里发生了三件事:

  1. .design/open.pdf.true从纯字符串转换为实际文件引用(使用toFile(...)方法)。无论文件是否存在,都可以创建文件引用。

  2. 我们使用一个名为的方法exists(...),顾名思义,该方法返回一个逻辑值,表示该文件引用是否确实存在。请注意,可以通过exists()File类中调用方法来替换此方法,因此toFile(...).exists() 在语义上是等效的。

  3. 我们将逻辑测试包装在条件中,这样当测试成立时我们可以做某些事情,否则我们可以做其他事情。

继续...

            base = getBasename(reference.getName()) + ".pdf";

为了便于阅读,我们创建了一个名为的局部变量,用于base保存当前文件的基本名称(即不带扩展名的文件名)。请注意,file不再有这个名称(我想是版本 6)。我们用一种更强大的表示法替换了它,即对当前文件的规范、绝对引用(因此得名reference)。对于这个特定目的,只需获取文件名就足够了,因此我们调用getName()它来获取它。

            return getCommand("open", "-a", "/Applications/Skim.app", base);
        }

我们使用了一种名为 的方法getCommand(...),正如操作名称所暗示的那样,获取Command要执行的内容的表示。必须明确解析要提供的每个元素(命令 + 参数)(与纯字符串方法相反,纯字符串方法是猜测)。然后我们return刚刚创建的命令。

        else {
            return [];
        }
    }

现在我们在else分支中。如果该文件不存在,则不应执行任何操作。但是什么也不做,嗯,什么也不做,我们需要告诉工具我们想要运行...什么也不做。:)如果您不返回任何内容,arara则会发出抱怨。返回任何内容的一种可能方法是提供一个空列表[],这样工具就会明白这是一个要执行的命令的空列表。

arguments: []

这里没什么可做的,我们已经完成了。:)

完整open.yaml规则,供参考:

!config
identifier: open
name: Preview
authors: []
commands:
- name: Open Skim
  command: >
    @{
        if (exists(toFile("./.design/open.pdf.true"))) {
            base = getBasename(reference.getName()) + ".pdf";
            return getCommand("open", "-a", "/Applications/Skim.app", base);
        }
        else {
            return [];
        }
    }
arguments: []

希望能帮助到你。:)

相关内容