WikiForme - 自分用Wiki記法パーサ
はてな記法、PukiWiki記法、tDiary記法などなど、世の中「なんとか記法」が溢れているわけですが、往々にして「自分にぴったり合う記法なんてどこにも無い!」という結論に達する場合が多く、結果として「なんとか記法」の乱立を生んでいるのではないでしょうか。
というわけで、自分専用のWiki記法を簡単に作れるカスタマイザブルパーサ WikiForme を作ってみました。乱立乱立!
記法を統一しようなんてムリですよね。もはや宗教論争です。自分専用の記法があればいいんです。
※2007/09/23: バージョン 0.3をリリースしました > WikiForme 0.3 リリース! - 構造化Wiki記法パーサ
※2007/09/13: バージョン 0.2をリリースしました > WikiForme 0.2 - 構造化Wiki記法パーサ
※2007/08/08: バージョン 0.1をリリースしました > WikiForme - 自分用Wiki記法パーサ バージョン0.1!
wikiforme-0.0.1.tar.gz
まだβバージョンですが、いじり倒してください。test.rbを実行してみると、test.txtに書かれたWiki風記法がHTMLに変換されます。
誰しも一度は自分専用のWiki風記法を作ってみようと思うわけですが、やれインライン要素だ、ブロック要素だ、表組みはどうする?などなど、なかなかややこしいものです。結局HTMLを手で打ったり、微妙に気に入らない記法で我慢する日々を過ごしているはず。WikiFormeを使えば、自分専用のWiki風記法を作れます。
特にWikiにこだわってHTMLを出力する必要はなく、XMLを出力したり、他のWikiの記法やTeXなどを出力しても良いでしょう。(…TeXは便利かもしれませんね) XMLに出力できると言うことは、プログラムの設定ファイルをWiki風記法で記述してもらう→XMLに変換してからロードなどなど、様々な使い方ができます。
WikiFormeの特徴は、入れ子構造を作れる点です。一般的な記法では、「章」や「節」と言った入れ子構造を作ることができませんでした(HTMLを出力する分には問題ないのですが)。WIkiFormeでは、章の中に節を入れたり、節の中に段落を入れたりできます。
たとえば以下のようなWiki風記法を、
*WikiForme! **Rubyです -Rubyで書かれています -Rubyで記法を定義します **入れ子にできます 閉じタグは要りません。 *外に出ます [インライン要素>http://viver.sourceforge.jp/]も''定義''できます。
以下のような形式に変換できます。
<section title="WikiForme!"> <subsection title="Rubyです"> <list> <item>Rubyで書かれています</item> <item>Rubyで記法を定義します</item> </list> </subsection> <subsection name="入れ子にできます"> <paragraph>閉じタグは要りません。</paragraph> </subsection> </section> <section name="外に出ます"> <a href="http://viver.sourceforge.jp/">インライン要素</a>も<strong>定義</strong>できます。 </section>
記法はRubyで定義します。一つの要素が一つのクラスに対応します。たとえば上のような記法を実現するためには、以下のようなモジュールを作ります。
module MyFormat class Section block_element "section" def containable?(instance) [Subsection, BlankLine] # 包含可能要素 end def process body = "<section title=\"#{@arg}\">" body << @children.process body << "</section>" return body end end class List1 < BlockTemplate::RecursiveListClass("list", "item", "") def block_element "list" def containable?(instance) [List2] # 包含可能要素 end def combinable?(instance) [List1] # 結合可能要素 end end # …似たような感じでSubsection、Listを作る class MyFormat block_element "myformat" def process @children.process end end Sugar = { # シンタックスシュガー "*" => Section, "**" => Subsection, "-" => List1, "--" => List2, } Document = MyFormat # 詳しくはソースコードと同梱のサンプルを end
本当はすべての要素にprocessメソッドを定義しないといけないのですが、ListやTableはよく使う(そして複雑)ので、テンプレートを用意してあります。継承するだけで使えます。
WikiFormeは、「包含可能要素」(containable?メソッド)と「結合可能要素」(combinable?メソッド)で文章構造を作ります。そして楽をするために、「シンタックスシュガー」を投入します。
パースの仕組みは単純で、包含可能であれば前の要素の子にし、包含可能でなければ前の要素を閉じます。同様に結合可能であれば前の要素と結合し、結合可能でなければ前の要素を閉じます。先の例では、SubsectionがSectionの子になっており、List1とList1が結合しています。
文章構造が完成すると、最も親(ドキュメント自体)のprocessメソッド(ここではMyFormat::process)が呼ばれます。あとは、その通りです。子の要素が変数@childrenに、結合した要素が@combinationに、テキストが@argに入っています。
ここまででは、実は↓このように書かないといけません。
\section WikiForme! \subsection Rubyです \list Rubyで書かれています \list Rubyで記法を定義します \subsection 入れ子にできます 閉じタグは要りません。
これでは面倒なので、シンタックスシュガーを割り当てて、簡単に書けるようにします。これで先の例のようになるわけです。
インライン要素もほぼ同様です。基本的な記法は、
&key{argarg}
で、シンタックスシュガーには「開始マーク」と「終了マーク」を指定します。たとえば開始マークを「[ [」、終了マークを「] ]」にしておけば、
[[WikiForme!]]
と書けます。
他にも気分次第でいろいろ。パースはWikiFormeに任せて、自分は間の文字列をどう料理するかを考えるだけでOKです。
[id: ←開始マーク id記法っぽい! 終了マーク→ ] ''開始マークと終了マークが同じでも可'' <em>←開始マーク HTMLっぽい 終了マーク→</em>