Skip to content

Write your own converter

Rodrigo Alonso edited this page Jun 23, 2017 · 3 revisions

If you find out, that you'd want to write your own converter - either for your own application or to contribute it to reverse_markdown - here's how you do it:

Lets assume that we want to support the oldish strike tag.

1. Find out if there is already a similar converter

For our strike tag this could be the del tag. Look it up in lib/converters/ and if you find one you can just register your tag as described in 4.

2. Implement and spec the new converter

Ok now, if there is no matching converter we need to implement one. First lets create the class and put it to the right place.

# lib/converters/strike.rb

module ReverseMarkdown
  module Converters
    class Strike < Base
    end
  end
end

Don't forget to require your new converter inside of you application.

Next step is to implement the convert method. It will be called whenever a matching tag was found and gets the Nokogiri representation as a parameter.

def convert(node, state = {})
  content = treat_children(node, state.merge(already_crossed_out: true))
  if content.strip.empty? || state[:already_crossed_out]
    content
  else
    "~~#{content}~~"
  end
end

The interesting bit is the call to treat_children. This method is inherited from the Converters::Base Class and performs a conversion of all child nodes.
If the content is empty we skip the whole tag, cause it looks weird if there is ~~~~ inside of your markdown in the end.

3. Spec it

Because we are dealing with tiny plain old ruby classes here it is very easy to spec them

require 'spec_helper'

describe ReverseMarkdown::Converters::Strike do
  let(:converter) { ReverseMarkdown::Converters::Strike.new }

  it 'converts a regular strike tag' do
    input = Nokogiri::XML.parse("<strike>Strike me down with all of your hatred..</strike>").root
    result = converter.convert(input)
    result.should eq "~~Strike me down with all of your hatred..~~"
  end

  it 'converts an empty strike to empty string' do
    input = Nokogiri::XML.parse("<strike></strike>").root
    result = converter.convert(input)
    result.should eq ""
  end

  it 'includes nested tags as well'
end

4. Register it

Now lets register our new converter so it can be looked up and used.

ReverseMarkdown::Converters.register :strike, ReverseMarkdown::Converters::Strike.new
ReverseMarkdown::Converters.register :del,    ReverseMarkdown::Converters::Strike.new

Because it's easy and works the same way it is possible to support the del tag as well.

5. Summary

That's it and you can see the full implementation of the strikethrough feature here: