Nanocのフィルターを作成/改造する

カスタムフィルター

nanoc create_siteで作ったディレクトリにあるlib以下のファイルがコンテンツのコンパイル前に読み込まれるので、ここでNanocのフィルターを新しく作成したり、既存のものを上書きしたりできる。

こうしたカスタムのフィルターを作るにはNanoc3::Filterを継承(Nanoc3を使っている場合)し、runメソッドを定義/上書きすればOK。
runは引数としてコンテンツ本文とオプションパラメータを受け取る。

以下では試しにredcarpetフィルターをRedcarpet2に対応したものに改造してみた。

lib/filter_redcarpet.rb
# -*- coding: utf-8 -*-

module Nanoc3::Filters
  class Redcarpet < Nanoc3::Filter
    # for Redcarpet2
    def run(content, params={})
      markdown_options = params[:markdown_options] || {}
      render_options = params[:render_options] || {}
      render = ::Redcarpet::Render::HTML.new(render_options)
      md = ::Redcarpet::Markdown.new(render, markdown_options)
      md.render(content)
    end
  end
end

とにかくファイルを置けば読み込まれる。他で何か設定したりする必要は無い。

このフィルターを使うにはRulesに以下のように書く。

filter :redcarpet, :markdown_options => {:autolink => true}, :render_options => {:hard_wrap => true}

このように簡単にフィルターが作れるのはいいかんじ。
フィルターは複数適用できるので、ちょっとした単機能のフィルターをさくっと作ってNanocを便利にするといったことも難しくない。
カスタムタグっぽいものも簡単に作れる。

フィルターの複数適用について

フィルターを複数指定した場合は上から順に適用される。Unixのパイプのイメージ。
例えばMarkdownの中に変数を埋めたいときは、erbのフィルターをかませてやればよい。

filter :erb
filter :redcarpet, :markdown_options => {:autolink => true}, :render_options => {:hard_wrap => true}

ちなみに順番を逆にするとredcarpetによってerbのタグの「<」と「>」が実体参照にエスケープされてしまうのでうまいこと動かない。
順番は重要。

追記

新しいフィルターを登録する場合は以下のように登録する必要があった。

Nanoc3::Filter.register '::Nanoc3::Filters::CustomFilter', :custom_filter