こなさんみんばんわ。

Jekyll で自作のプラグインを作って色々やってると、そのプラグインの中で Markdown から HTML への変換を走らせたくなる時がよくありますよね。特にタグ・ブロックを追加するものでは、ブロックの開始タグと終了タグの間のテキストをいちいち HTML で書くのは面倒ですから、そこは Markdown で書いて変換したいところです。以下はあまり実用性のないサンプルコードですが1

<!--
例えば {% note %} 〜 {% endnote %} 間を
<div class="note"><p>NOTE:</p> 〜 </div> に
変換する Liquid Tag Block プラグインがあるとして

    {% note %}
    何らかの**テキスト**がここにある
    {% endnote %}

が下のようになるように Markdown to HTML 変換を入れたい
-->
<div class="note">
  <p>NOTE:</p>
  <p>何らかの<strong>テキスト</strong>がここにある</p>
</div>

このようなのを実現するために、下のプラグイン・スケルトンの render メソッドのどこかに変換コードを入れたいと。

module Jekyll
  class NoteTagBlock < Liquid::Block
    def initialize(tag_name, markup, tokens)
      super
    end
    def render(context)
      text = super
      # text に変換などを施して出力を返す何らかの処理
    end
  end
end
Liquid::Template.register_tag("note", Jekyll::NoteTagBlock)

こういう場合にとりあえず真っ先に思いつくのは、Jekyll デフォルトの Markdown レンダラー2である Kramdownrequire するというものでしょうか。

def render(context)
  require 'kramdown'
  text = super
  html = Kramdowm::Document.new(text).to_html
  # その他必要な処理
end

もちろんこれでも望んだことは実現できるのですが、Jekyll がサポートする Markdown レンダラーは他にもあって、人によってはこのレンダラーを変更している場合があります。そうすると 1 つのページを出力するのに、タグ・ブロック内の変換で使用するレンダラー (Kramdown) とそれ以外の部分で使うレンダラーが混在することになりますよね。場合によっては出力する HTML コードまで変わる可能性もあるので、それではちょっとまずいと思う訳です。

ということで、Kramdown 決め打ちではなく実際に使っている Markdown レンダラーを使用する方法がないものかと思って色々調べているうちに、Jekyll::Site オブジェクトの中に find_converter_instance というメソッドがあるというのを知りました。以前は getConverterImpl として実装されていたものの書き換えのようです。

使い方はこのことを知るに至った Stack Overflow のトピックに書いてあります。context.registers[:site]site オブジェクトにアクセスして、このメソッドに Jekyll::Converter::Markdown クラスを渡すとサイトで使用している Markdown レンダラーのインスタンスが返ってくるので、その convert メソッドにテキストを渡すと HTML 変換されたものが得られます(…で合ってる?😅)

def render(context)
  text = super
  site = context.registers[:site]
  converter = site.find_converter_instance(::Jekyll::Converters::Markdown)
  html = converter.convert(text)
  # その他必要な処理
end

そんな訳で、自分だけで使うプラグインなら Kramdown 決め打ちでもいいかと思いますが、公開して人に使ってもらうようなプラグインを作る時には find_converter_instance メソッドを使った方がよさそうかなー、いいんじゃないかなー、というお話でした。

久しぶりに目次がない記事を書いたでござるの巻。

  1. なぜ実用性がないかというと、これくらいだったらプラグイン作るまでもなく <div class="note" markdown="1">〜 で済むからですね。涙 

  2. Markdown「コンバーター」だったり「エンジン」だったり「プロセッサー」だったりと人によって呼び方がさまざまですが、この記事では「レンダラー」で統一しております。