预处理器扩展

这个 Preprocessor 扩展在 AsciiDoc 源被解析之前运行。具体来说,它在 Document 实例被创建并初始化 PreprocessorReader 以开始读取源文档的行之后运行。

如果预处理器扩展从 reader 中读取行,它将产生副作用。其中一个副作用是头部文档属性可能无法正确解释。另一个是它可能会干扰行号跟踪。如果扩展添加或删除了行,解析器可能会产生误导性的行号信息。因此,如果可能,应避免在预处理器扩展中与 reader 交互。

预处理器扩展仍然可以用于修改 Document 对象上的选项,在这种情况下没有副作用。它也可以安全地用作事件监听器,也许是为了运行其他代码。通过读取实际 AsciiDoc 文档上方的行,也可能避免副作用,这在本页的示例中有所显示。这样做是安全的,因为这些行不会被解释为 AsciiDoc。

作为一种变通方法,您可以使用 Asciidoctor Reducer 来安全地读取和解析文档的源行,而独立于当前的文档 reader。

在调用预处理器扩展之前,Asciidoctor 会将主文档的源文本分割成行并 对它们进行规范化。然后,它会根据这些行创建一个 PreprocessorReader 实例。

Asciidoctor 然后会将 Document 和 PreprocessorReader 实例传递给扩展的 Asciidoctor::Extensions::Processor#process 方法。如果扩展从 reader 中读取行,这些行将首先被 Asciidoctor 的内部预处理器进行预处理。扩展可以修改 Reader 并返回相同的 Reader(或 falsy,这是等效的)或一个新的 Reader 实例来替换它。但是,如上所述,在从原始 PreprocessorReader 实例读取行时要小心,因为它可能产生副作用。

预处理器扩展示例

目的

从文档顶部剥离前端内容,这些内容将被 Jekyll 等网站生成器使用。

此扩展模拟了当从 API 或 CLI 设置了 skip-front-matter 属性时的内置行为。有关详细信息,请参阅 Skip Front Matter

sample-with-front-matter.adoc

---
tags: [announcement, website]
---
= Document Title

content

[subs=+attributes]
.Captured front matter
----
---
{front-matter}
---
----

FrontMatterPreprocessor

class FrontMatterPreprocessor < Asciidoctor::Extensions::Preprocessor
  def process document, reader
    lines = reader.lines # get raw lines
    if lines.first == '---'
      front_matter = []
      original_lines = lines.dup
      lines.shift
      while !lines.empty? && lines.first != '---'
        front_matter << lines.shift
      end

      if (first = lines.first).nil? || first != '---'
        lines = original_lines
      else
        lines.shift
        document.attributes['front-matter'] = front_matter * ?\n
        # advance the reader by number of lines taken
        (front_matter.length + 2).times { reader.advance }
      end
    end
    reader
  end
end

用法

Asciidoctor::Extensions.register do
  preprocessor FrontMatterPreprocessor
end

Asciidoctor.convert_file 'sample-with-front-matter.adoc', safe: :safe