编写、测试和发布一个AsciidoctorJ扩展的方法

98 阅读2分钟

AsciidoctorJ的API暴露了一系列的扩展点。一个扩展点可以操作Asciidoc文档的生成结果。例如,一个扩展点的实现 Postprocessor插入自定义的页脚文本。

一个标签式代码块需要插入动态行为和自定义样式。为此,我们需要在生成的HTML文档的标签中加入CSS和JavaScript。该 DocinfoProcessor扩展点可以直接操作文档的页眉和页脚,很适合我们的用例。

清单1显示了一个实现了抽象类DocinfoProcessor 的类。这个代码例子省略了详细的实现细节,例如,如何从classpath中读取文件。关于更多的细节,请看该类的完整源代码

TabbedCodeBlockDocinfoProcessor.java

import org.asciidoctor.ast.Document;
import org.asciidoctor.extension.DocinfoProcessor;

import java.util.Map;

public class TabbedCodeBlockDocinfoProcessor extends DocinfoProcessor {
    public static final String TABBED_CODE_CSS_FILE_PATH_ATTRIBUTE = "tabbed-code-css-path";
    public static final String TABBED_CODE_JS_FILE_PATH_ATTRIBUTE = "tabbed-code-js-path";
    public static final String DEFAULT_CSS_FILE_PATH = "/codeBlockSwitch.css";
    public static final String DEFAULT_JS_FILE_PATH = "/codeBlockSwitch.js";

    @Override
    public String process(Document document) {
        if (document.isBasebackend("html")) {
            Map attributes = document.getAttributes();
            String cssPath = getCssPath(attributes, TABBED_CODE_CSS_FILE_PATH_ATTRIBUTE, DEFAULT_CSS_FILE_PATH);
            String jsPath = getCssPath(attributes, TABBED_CODE_JS_FILE_PATH_ATTRIBUTE, DEFAULT_JS_FILE_PATH);
            String css = readFileContentsFromClasspath(cssPath);
            String js = readFileContentsFromClasspath(jsPath);
            return modifyHeadHtml(css, js);
        }

        return null;
    }

    ...
}

清单1.DocinfoProcessor的一个实现

我想指出这个代码例子中两个值得注意的部分。你可能已经注意到,process 方法只处理HTML处理。我们这样做的原因很简单。将一个标签式的代码块添加到其他后端,如PDF文件,将需要不同的处理方式。默认情况下,该类使用一个预定义的CSS和JavaScript文件,该文件随扩展的分发而来。另外,终端用户也可以设置一个属性,用于提供自定义的样式或JavaScript行为。

每个你想提供给Asciidoctor处理器的扩展都需要注册。你可以通过实现一个类型为ExtensionRegistry 的类来做到这一点。清单2演示了一个将TabbedCodeBlockDocinfoProcessor 添加到扩展注册表的实现。

TabbedCodeBlockExtension.java

import org.asciidoctor.Asciidoctor;
import org.asciidoctor.extension.JavaExtensionRegistry;
import org.asciidoctor.extension.spi.ExtensionRegistry;

public class TabbedCodeBlockExtension implements ExtensionRegistry {
    @Override
    public void register(Asciidoctor asciidoctor) {
        JavaExtensionRegistry javaExtensionRegistry = asciidoctor.javaExtensionRegistry();
        javaExtensionRegistry.docinfoProcessor(TabbedCodeBlockDocinfoProcessor.class);
    }
}

清单2.在扩展注册表中注册DocinfoProcessor

我们还没有完成。你还需要创建一个名为org.asciidoctor.extension.spi.ExtensionRegistry 的文件,并将其指向扩展实现,以便Asciidoctor能够发现它。

META-INF/services/org.asciidoctor.extension.spi.ExtensionRegistry

com.bmuschko.asciidoctorj.tabbedcode.TabbedCodeBlockExtension

清单3.让扩展可以被发现

就这样,你写了第一个AsciidoctorJ扩展。接下来,我们将专注于测试、发布和使用扩展的重要方面。