More than 1 year has passed since last update.

JekyllはLiquidというテンプレートエンジンを採用しています.Liquidは表現力をあえて制限することで危険なコードをテンプレートに埋め込めないようになっています.そのため,テンプレートで何かおもしろいことをしようとすると,新しいプラグインを書かなければならないことがよくあります.ところが,Jekyllのプラグインの書き方に関するドキュメントはそれほど多くないため,ここに書き方をメモしておきます.

Case Study 1: Echo

最初に引数をそのまま表示するタグを作ってみます.タグは Liquid::Tag を継承して作ります.

_plugins/echotag.rb
# coding: utf-8

module Jekyll
  class EchoTag < Liquid::Tag
    def initialize(tag_name, markup, tokens)
      super
      @arg = markup
    end

    def render(context)
      @arg
    end
  end
end

Liquid::Template.register_tag("echo", Jekyll::EchoTag)

これを _plugins/echotag.rb に配置して,ページの中で {% echo hello %} と書くと hello が出力されます.

EchoTag#initialize の第二引数にタグの引数が渡されます.それを EchoTag#render メソッドで返すようにすれば echo タグを実装できます.

Case Study 2: RSS Feed

ここでは,RSSを使って外部のサイトから更新情報を取ってきてページに埋め込むタグを例として解説していきます.

先に使用例を示します. {% feed URL %}{% endfeed %} で囲った間では entries という配列を参照でき,その中にエントリのURLとタイトルが納められています.

<section>
  <h1>CoffeeScript の話題</h1>
  {% feed http://qiita.com/tags/CoffeeScript/feed.atom %}
  <ul>
    {% for entry in entries %}
    <li>
      <a href="{{entry.url | xml_escape}}">
        {{entry.title | escape}}
      </a>
    </li>
    {% endfor %}
  </ul>
  {% endfeed %}
</section>

このように閉じタグがあるようなタグは Liquid::Tag ではなく Liquid::Block を継承します.プラグインのコードは以下のようになります.

_plugins/feedtag.rb
# coding: utf-8

require "open-uri"
require "feed-normalizer"

module Jekyll
  class FeedTag < Liquid::Block
    def initialize(tag_name, markup, tokens)
      super
      @url = markup.strip
    end

    def render(context)
      entries = fetch_feed(@url)
      context.stack do
        context["entries"] = entries
        return super
      end
    end

    def fetch_feed(url)
      open(url) do |f|
        feed = FeedNormalizer::FeedNormalizer.parse(f)
        return feed.entries.map {|entry| {
            "url" => entry.url,
            "title" => entry.title,
          }
        }
      end
    end
  end
end

Liquid::Template.register_tag("feed", Jekyll::FeedTag)

initializeメソッドの第二引数がタグの引数であることはechoの場合と同じです.

fetch_feedメソッドでは,urlを開いてRSSフィードをパースしてハッシュの配列にしています.Liquidはto_liquidメソッドを持っているオブジェクトしかテンプレートに渡せません.ArrayやHashはLiquidがto_liquidメソッドを定義してくれるため,これらに変換しておけば,テンプレートの中でその変数を参照することができます.

renderメソッドでは,fetch_feedを呼び出したあと,2つのことを行っています.

まず,テンプレートの中で entries を参照するために,contextentries を登録しています.ただし,何も考えずに登録すると,{% endfeed %} の後でも entries を参照できてしまうため,context["entries"] = entriescontext.stack doend で囲う必要があります.

次に,super を呼び出して,親クラスにタグで囲われた部分をレンダリングをさせます.(super はオーバーライドしているメソッドを呼び出す構文です.詳しくはリファレンスを参照.)

補足

site変数を取得する方法

site = context.registers[:site]

baseurlを取得する方法

site.config["baseurl"]

site は上述の方法で取得する.

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.