こなさんみんばんわ。
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である Kramdown を require
するというものでしょうか。
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
メソッドを使った方がよさそうかなー、いいんじゃないかなー、というお話でした。
久しぶりに目次がない記事を書いたでござるの巻。