Chienomi

PureBuilder Simply 3.3 / JSONoutとテーマインストール

開発::util

PureBuilder Simplyは7ヶ月ぶりのリリースとなる3.3.0が登場した。

今回のPureBuilder Simplyは予定されていた2つの機能、JSONoutとテーマインストールを追加した。 JSONoutはPureBuilder Simplyの利用幅を広げる機能、テーマ機能は一般ユーザーの敷居を下げる機能だ。

JSONout

JSONoutは、従来は出力形式がHTMLに限られていたが、これに加えてJSONでの出力ができるようになったものだ。

JSON出力はfrontmatterオブジェクトとレンダリングされたbodyからなる。 SPAなどウェブアプリケーションからより扱いやすくするのが目的だ。

ボディをレンダリングしないのは、さすがにPureBuilder Simplyである必要性が怪しいため、サポートしない。 もしそういうニーズがあるのなら考えるかもしれないが……

jsonoutが真である場合、JSON形式で出力する。

jsonout_includeを指定することでfrontmatterに含めるものを、jsonout_excludeを指定することでfrontmatterに含めないものを指定できる。 両方指定した場合はホワイトリスト方式のjsonout_includeが優先。 今のところincludeをexcludeできるようにはなっていない。パターン指定したりはできないためだ。

「シンプル故に懐が広い」はPureBuilder Simplyの特徴のひとつなので、ウェブアプリケーションフレンドリーな構造を追加した。

これを実現するために、これまで単純にメソッドの一部分だった出力処理を複数のメソッドに分割しており、JSON以外の形式への対応も容易になった。

テーマインストール

概要

従来は「リポジトリからコピーしてね」という形式だったテーマの導入を、pbsimply-initに統合した。 加えて、サードパーティテーマにも対応。

テーマファイル (非Rubyファイル) の場所を知る

これを実現するために重要だったのはファイルの場所を知ることだ。 RubyGemsのファイル構成はバンドルしたそのときと変わらない。 そのため、そのファイルの位置から相対的にテーマとして扱うためのファイル群のパスを知ることができる。

そのために利用できそうなのは$0__FILE__だ。

$0はコマンドのパスとなる。 これは通常の意味での$0ではなく、Rubyに渡された実行ファイルの引数を意味する。

例えば、

#!/bin/ruby

p __FILE__

として、これをtest.rbとする。

ruby test.rbならtest.rbになるし、ruby ./test.rbなら./test.rbになる。 また、ruby foo/../test.rbならfoo/../test.rbになる。

これが実行ファイルであった場合はどうかというと、カーネルによりshebangが解釈され、このshebang解釈では$PATH以下にある実行されるファイルの絶対パスに展開される。 このため、test.rbと実行すると/usr/local/bin/test.rbのようになる。

では__FILE__はどうか。

例えば、a/test.rba/testlib.rbrequire_relative./testlib.rbとして読むとする。 この場合testlib.rbの中ではtestlib.rbの絶対パスになる。

実行ファイルもライブラリも、シンボリックリンクである場合シンボリックリンクのパスになる。 ただし、require_relativeするとき、自身のシンボリックリンクは解決された状態を起点にする。

このため、単に__FILE__を基準にファイルを探そうとすると、シンボリックリンク化されている場合にうまく動作しない。 RubyGemsはライブラリも含めた構成になっているのが普通なので、bin/配下をコピーした場合は動かないのも仕方のない話だが、通常はシンボリックリンクするのは動くものなので、シンボリックリンクすることが動かなくなるのはあまり良くない。

なので、File.readlink(__FILE__)すれば良いのだが、__FILE__がシンボリックリンクでない場合にエラーになる。

また、ライブラリであれば__FILE__は常に絶対パスになっているが、実行ファイルだとどのように実行されたかによって絶対パスでない場合がある。

以上を踏まえ

pwd = __FILE__
pwd = File.readlink __FILE__ if File.symlink? __FILE__
pwd = File.expand_path(pwd)
$GemRoot = pwd

で自分のディレクトリが分かる。 $GemRoot/themesは実行ファイルから見れば../themesになるため、ここまで含めて

pwd = __FILE__
pwd = File.readlink __FILE__ if File.symlink? __FILE__
pwd = File.join(File.dirname(pwd), "..")
pwd = File.expand_path(pwd)
@gemroot = pwd
@themes_root = File.join(pwd, "themes")

とすることで目的のファイルを発見できる。

ここまですれば配置規則と動作を規定すれば難しいことではない。

利用方法

使い方はとても簡単で、pbsimply-init-tオプションが追加された。

テーマはプロセッサ/テーマ名という構成になっており、pandoc/paperのように指定する。

また、この機能の利便性を考え、上書きインストールが可能になった。 これはインストールプロセスを今存在するファイルを無視して実行するものである。 .pbsimply.yamlも上書きされることには注意が必要だ。 上書きインストールを行う場合は-fオプションを使用する。

さらに、-sオプションを指定するとソースのみインストールするようになった。

つまり、

pbsimply-init foo

とした場合、foo/Sourcefoo/Buildが生成されるわけだが、

pbsimply-init -s foo

とした場合、fooにソースがインストールされた状態になる。

テーマの移植と制作

実はテーマ機能までであれば6月くらいにできていたのだが、リリースまでは随分時間がかかった。 主な理由は、従来存在したテーマを移植するのが面倒だったからだ。

従来、docroot-sampleというディレクトリ以下にコピーして使用するためのテーマが置かれていたが、これをテーマ機能に統合するため、新しいテーマ機能の形式に合わせてtheme以下に配置する必要があった。

これをシンプルに実現するため、base_themeという機能が必要になった。

テーマの設定は.theme.yamlファイルによって定義されているが、initial_control.base_themeを指定することで、テーマインストール時に先にベーステーマをインストールするようになっている。 従来、docroot-sampleはベーステーマをコピーしてから使いたいテーマをコピーするというレイヤー構造になっていたため、この機能が必要だったのだ。

この機能を実現する手順が少し面倒で、これに1ヶ月くらいかかった。

で、そこまでやるにはやったのだが、docroot-sampleを今の形式に変換する作業が面倒で放置していたのだ。 なお、実際に作業をやった感じでは、全体で15分くらいでできるようなものだった。

旧来のテーマであるpandoc/bloggy, pandoc/practical, pandoc/warmは従来のままだが、新たにpandoc/cooldarkpandoc/paperを追加した。 これらのテーマは急造であるため、クオリティはまだ高くない。 ただ、制作には1日がかりであったため、リリース時の最後の壁となった。

contribution theme募集中

theme機能を追加したことで、ユーザーがテーマを制作することが容易になった。

そこで、user contributionテーマを受け付けている。

テーマ制作については、ポータルサイトのテーマのページを見てもらえば良いと思うのだが、基本的には.pbsimply.yaml.theme.yaml以外はPureBuilder Simplyの雛形プロジェクトを作れば良いだけだ。

プロセッサ別にテーマを書けるようになったため、好みの(あるいはハードルの低い)プロセッサのテーマを作ることもできる。

とりあえずは任意の既存のテーマ(purebuilder-simplyリポジトリのthemesディレクトリ以下にあるもの)をコピーして使うところから始めると良いだろう。

投稿待っています!