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.