Le blog d'Archiloque

How to implement a new Asciidoctor export?

Asciidoctor is a great tool to write documentation or blog articles: the syntax is less quirky than Markdown and it supports many elements.

Several export formats are available out of the box, and when you want to export your content in a specific format you can even add your own templates.

When writing your own templates, you must create a specific file for each element type so the engine can convert it, see for example the html5 backend.

Unfortunately there’s no documentation on what attributes are available for each element type. The simplest way to find it is to peek on several examples until you can figure it out. Here’s a small script to make things easier:

  • Create a new directory called template_hack

  • Save this file as helpers.rb in the template_hack directory

require 'set'

module Asciidoctor

  # Fake template
  class DebuggerTemplate
    def render(scope, params)
      ''
    end
  end

  # Patch the converter
  class Converter::TemplateConverter

    # Handle anything, just ask!
    def handles?(name)
      unless @templates.key? name
        @templates[name] = DebuggerTemplate.new
      end
      true
    end

    def convert(node, template_name = nil, opts = {})
      @lines ||= Set.new
      log_line =  nil
      value = nil
      if node.is_a? Asciidoctor::Block
        value = node.content
        log_line =
          "#{node.class} uses #{template_name} for #{node.context}"
      elsif node.is_a? Asciidoctor::AbstractBlock
        value = node.content
        log_line =
          "#{node.class} uses #{template_name}"
      elsif node.is_a? Asciidoctor::Inline
        value = node.text
        log_line =
          "#{node.class} uses #{template_name}"
      else
        raise "Can convert #{node.class}"
      end
      if @lines.add?(log_line)
        p log_line
      end
      value
    end

  end
end
  • Use it to convert your my_ascii_file.adoc:

    asciidoctor -T template_hack/ my_ascii_file.adoc
  • Read the log to find what file you need to implement and for each one what is the ruby class that represents it:

"Convert Asciidoctor::Inline with inline_anchor template"
"Convert Asciidoctor::Inline with inline_quoted template"
"Convert Asciidoctor::Block with paragraph template for paragraph"
"Convert Asciidoctor::Block with quote template for quote"
"Convert Asciidoctor::Block with preamble template for preamble"
"Convert Asciidoctor::List with olist template"
"Convert Asciidoctor::Section with section template"
  • Implement each template by looking at the Asciidoctor class where you can find the attributes and methods you need