jekyllでhaml

Octopressからjekyllに移行したときにhamlサポートがうんぬんと書いたのだが、その後、hamlサポートを自作した。この実装のポイントは以下の通り。

  • hamlコードを記述できる{% haml %} ... {% endhaml %}を追加する
  • 拡張子が.hamlのファイルを処理する際、自動的に本文全体を上のブロックで包む

結果として.hamlファイルはhaml処理されることとなる。

おかしなやり方だけれども一応は理由がある。

hamlサポート自体はいくつもあるのだけど、以前書いたように、hamlレベルで制御構造を書こうとするととたんにいびつな形になってしまう。これはjekyllが大きくliquidに依存しているところに後付けでhamlサポートを加えているためである。そうしたhamlサポート実装におけるhaml処理ともともとのliquid処理とでは、処理のタイミングや与えられるデータに大きな違いができてしまう。

jekyll(やOctopress)の記事は、liquidによるテンプレート展開→コンバータによるHTML変換という二段階で行われる。テンプレート展開が行われるとき、記事やレイアウトの本文のほかに数種類のデータが渡される。

  • サイトのメタ情報(_config.ymlやカテゴリのリストなど記事個別ではなくサイト全体の情報)
  • 処理対象(記事自体)のメタ情報(関連記事など)
  • 対象ファイル(記事やレイアウト)それぞれのYAMLヘッダ情報
  • 対象ファイル内(のliquidレベル)で定義されたデータ

記事は、記事本体→レイアウト→レイアウト→…→レイアウトという入れ子構造になっている。テンプレート展開は一度だけでなく入れ子の階層分だけ繰り返し実施され、上述の各データはその都度——基本的には前段階から引き継ぎながら生成される。

他方、コンバータによるHTML変換はすべてのレイアウト適用を終えてから行われる。コンバータに与えられるは最終的な記事本文のみであり、そのほかにはグローバルな情報としての「サイトのメタ情報」がある程度となる。

hamlはテンプレート機能として見ればliquidと同列といえるのだが、hamlサポートをコンバータで実装すればliquidよりも見劣りしたものとなる。

  • レイアウト間でのデータ受け渡しに関われないから、レイアウトの分割・共用を効果的に行うのが難しい
  • 基本的に個々の記事のメタ情報にアクセスすることができないため、hamlレベルでの制御構造を記述しにくい
  • liquid処理に与えられる各種データはその都度生成されていて、その一部についてはコンバータからはまったくアクセスできない

結局、jekyllはliquidを前提にしていて、その度合いがかなり強い。ならばいっそliquidをまるごとhamlで差し替えられかというとそれも難しそうである。プラグインを使いまわせないなど、jekyllとは別ものになってしまうだろう。

そこで本実装では与えられる情報の違いをなくすため、そしてhaml処理がliquid処理と同じタイミングで行われるようにするため、haml処理のためのliquidタグを作成することにした。それに加えてliquid処理に与えられる、つまりliquidレベルで参照できる各種のメタ情報に、まったく同じとはいかないまでもそれなりに容易にアクセスできる手段をあわせて作成した。

以上によりliquidレベルでできることはほとんどhamlでもできるようになっている、はずである。

ただ、このやり方にも問題がある。haml処理をliquid処理のタイミングで行う都合上、HTML変換により空白が出現するケースがある。中間データに空白が出現することでインデントが乱れる結果となればhamlレベルでエラーが発生する。

このことはもしかするとhaml側でうまく対処できるのかもしれないが、実のところよくわかっていない。というか、あまり深く考えていない。現状ではhaml側の全体設定で対処というごく場当たり的な対応をしている。