Chienomi

PureBuilder Simply 1.9 「祝福」機能の追加とtopic path

開発::util

Blessing

PureBuilder Simply 1.9で新たに追加された「祝福」機能は、FrontmatterにRubyスクリプトで手を入れるという機能である。

これは、1.8での変更により可能になったもので、Pandocの新しいテンプレート機能を活用するものになっている。

パンくずリスト

この機能はChienomiで実際に利用しており、これによって

  • topic path
  • カテゴリ表示

のふたつの機能が入った。

実際にどのようにしているかというと、.pbsimply-bless.rbでは

#!/usr/bin/ruby

load "./.lib/categories.rb"

TOPICPATH = {
  "" => ["TOP", "/"],
  "/articles" => ["Articles", "/#Category"],
  "/override" => ["Override", "/"],
  "/archives" => ["Old Archives", "/articlelist-wp.html"]
}

ARTICLE_CATS.each do |k,v|
  TOPICPATH[["/articles", k].join("/")] = [v, ["", "articles", k, ""].join("/")]
end

PureBuilder::BLESS = ->(frontmatter) {
  content = nil
  filetype = nil
  if File.exist?(".current_document.md")
    content = File.read(".current_document.md")
    filetype = :md
  elsif File.exist?(".current_document.rst")
    content = File.read(".current_document.rst")
    filetype = :rest
  end

  url = frontmatter["page_url"].sub(/^\.?\/?/, "/")
  frontmatter["topicpath"] = []
  url = url.split("/")
  (1 .. url.length).each do |i|
    path = url[0, i].join("/")
    if v = TOPICPATH[path]
      frontmatter["topicpath"].push({"title" => v[0], "url" => v[1]})
    else
      frontmatter["topicpath"].push({"title" => frontmatter["title"]})
      break
    end
  end

  if frontmatter["category"] && url.include?("articles")
    frontmatter["category_spec"] = [ARTICLE_CATS[url[-2]], frontmatter["category"]].join("::")
  end

  if content
    if((filetype == :md && content =~ %r:\!\[.*\]\(/img/thumb/:) || filetype == :rest && content =~ %r!\.\. image:: .*?/img/thumb!)
      frontmatter["lightbox"] = true
    end
  end
}

という感じ。(WordPress分に関しては別途やっている)

テンプレート側では、カテゴリタイトルは

$if(category_spec)$
          <h2>$category_spec$</h2>
$else$
$if(category)$
          <h2>$category$</h2>
$endif$
$endif$

topic pathは

<nav id="TopicPath">
  <ul>
    <!-- TOPICPATH -->
$for(topicpath)$
$if(it.url)$
    <li><a href="${it.url}">${it.title}</a></li>
$else$
    <li>${it.title}</li>
$endif$
$endfor$
  <!-- /TOPICPATH -->
  </ul>
</nav>

という感じだ。ここらへんのファイルはGitHubで公開されているので直接観ることができる。 (生成前のeRuby版テンプレートは公開していないが)

ポイント

Pandocのテンプレートは、単純な(値があるかどうかをチェックする)ifとイテレータのforしかなく、複雑なことはできない。 テンプレートで計算的に処理したいことがあるのだが、ほんの簡単な複合条件や計算でもPandocテンプレートの前に通さねばならず、Pre Pluginsでドキュメントをいじるか、もしくはファイルごとに書くかしかなかった。

ほんのちょっとでいいからテンプレート変数に対する計算をさせてほしい、と思うことがよくある。

それを可能にするのがコレだ。 例えば、Pandocテンプレート単体ではできない「ファイルパスにxが含まれている場合」とか、「ファイルパスを/で分割して」というようなことができる。 これまでもPureBuilder Simplyでできないことはなかったが、より簡単な方法が提供されたのである。

ちなみに、生成直前であるため、処理中のドキュメントは.current_document.(ext)として存在する。ちょっと裏技チックだが、これを使ってlightboxが必要かどうかも自動判定するようになった(これまではドキュメントに含める必要があった)。

これによって、今まではPureBuilder Simplyでは割と手の込んだトリックを必要としていたtopic pathも簡単に実装できるようになった。 これでより隙のない強力なソフトウェアへと進化したと言えるのではないだろうか。