Walking the Asciidoctor document tree

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Walking the Asciidoctor document tree

mojavelinux
Administrator
While playing around with extension points in Asciidoctor, I hacked together these two classes that walk the Asciidoctor document tree. The NodeVisitor simply visits each node, whereas the NodeTransformer allows the node to be removed or replaced. I though these might come in handy while shaving your docs. Enjoy!

require 'asciidoctor'

source_file = ARGV.first

doc = Asciidoctor.load_file(source_file, :safe => :safe, :header_footer => true)

class NodeTransformer
  def traverse node
    if node.is_a? Asciidoctor::AbstractBlock
      context = node.context
      dispatch = "visit_#{context}".to_sym

      if respond_to? dispatch
        result = send dispatch, node
      else
        result = visit node
      end

      if result.nil?
        node.parent.blocks.delete node
        return
      elsif result != node
        index = node.parent.blocks.find_index node
        node.parent.blocks.delete_at index
        node.parent.blocks.insert index, result
        return
      end

      if node.blocks?
        node.blocks.each do |child|
          traverse child
        end
      end
    end
  end

  def visit node
    node
  end
end

class NodeVisitor
  def traverse node
    if node.is_a? Asciidoctor::AbstractBlock
      context = node.context
      dispatch = "visit_#{context}".to_sym

      if respond_to? dispatch
        send dispatch, node
      else
        visit node
      end

      if node.blocks?
        node.blocks.each do |child|
          traverse child
        end
      end
    end
  end

  def visit node
    node
  end
end

class SampleNodeTransformer < NodeTransformer
  def visit_image node
    # keep node:
    #node

    # delete node:
    # nil

    # replace node:
    Asciidoctor::Block.new(node.parent, :paragraph, :source => 'This image has been replaced!')
  end
end

SampleNodeTransformer.new().traverse(doc)

puts doc.render

-Dan

p.s. I'm considering adding these two classes into the Asciidoctor Extensions package once I refine them a bit. They will be essential when implementing a Treeprocessor.