Penの完成
さて、このテンプレートから生成されるState.csにはイベントを表現するclassであるknock、writeそしてContextが定義されていません。さらに、状態と事象の組に応じたアクションはテンプレートで与えておらず、これらはすべて外付けになります。アクションについてはpartial methodで差し込むことができるようにしてあります。生成されたState.csと以下に示すProgram.csとで、アプリケーション完成です。
using System;
// イベント: knock
public class knock {}
// 引数を持ったイベント: write
public class write {
public string msg;
public write(string s) { msg = s; }
}
// コンテキスト
public interface Context {
void do_write(string s);
}
// enabed状態でwriteイベントが起こったときのアクションを追加する
partial class enabled {
partial void _action_(write evt, Context ctx, ref State transition) {
ctx.do_write(evt.msg);
}
}
// ノック式ボールペン: コンテキストを実装し,Stateを内包させる。
public class Pen : Context {
State s = State.disabled();
public void do_write(string s) { Console.Write(s); }
public void knock() { s = s.handle(new knock(),this); }
public void write(string msg) { s = s.handle(new write(msg), this); }
}
class Program {
static void Main() {
Pen pen = new Pen();
pen.write("はじめは書けないけど");
pen.knock();
pen.write("一度ノックすれば書けます。");
pen.knock();
pen.write("も一度ノックすると書けなくなります。");
pen.knock();
pen.write("ノック式ボールペンてばそんなもの。");
Console.WriteLine();
}
}
partial method定義するアクション関数「_action_」に小さなオマケを仕込みました。第3引数には遷移先状態が引き渡されますが、こいつをrefによる参照渡しにしておきました。この値を書き換えることでアクションの結果に応じて遷移先を変更できます。partial class enabledを以下のようなコードに変更することで「'。'で終わる文字列を書くと自動的にペン先の引っ込む"いらんことしぃなPen」を作ることができます。
// enabed状態でwriteイベントが起こったときのアクションを追加する
partial class enabled {
partial void _action_(write evt, Context ctx, ref State transition) {
ctx.do_write(evt.msg);
// '。'で終わる文字列を書くと遷移先をdisabledに変更する
if (evt.msg.EndsWith("。")) transition = State.disabled();
}
}
また、各StateにはそのStateに入るとき/そのStateから抜けるときに必ず行う入場動作/退場動作をpartial method「_enter_(Context ctx)/_exit_(Context ctx)」で定義できます。
C++コードを生成するには
C#やVB.NETコードであれば.cs/.vbを1つ生成すればお終いなのですが、C++となると1つのテンプレートから.hと.cppを吐かせなくてはなりません。ここでは、コマンドラインからTextTransform.exeを起動し.h/.cppを生成します。
TextTransform.exeのコマンドライン・オプション「-I」によって、<#@ include file="~" #>で展開されるテンプレートの置かれたディレクトリを指定できます。すなわち、生成ルールの異なる2つのテンプレートをそれぞれ異なるディレクトリに(同じファイル名で)置いておき、-Iオプションでディレクトリを指定することで異なるコードを生成させます、さらに-outオプションで生成ファイル名を指定しています。ダウンロード用サンプルファイルの、Pen_T4_cppプロジェクトにあるtransform.batをご覧ください。
set t4="c:\Program Files\Common Files\Microsoft Shared\TextTemplating\10.0\TextTransform.exe" : set t4="c:\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\10.0\TextTransform.exe" %t4% -I t4/h -out State.h State.tt %t4% -I t4/cpp -out State.cpp State.tt
いかがでしょうか。状態遷移表さえ用意すればT4 templateが主要なコードを生成してくれ、残るアクションを追加するだけでアプリケーションが動き出します。生成されるコードが定型的であるほどコード生成のルール(テンプレート)を起こすのが楽ですし、一度テンプレートを起こしておけば何度でも使い回せます。今回は、テンプレート内に配列の形で用意した状態遷移表からC#/C++コードを生成しましたが、例えばHTML、XML、CSVなどなどを生成させることもできますし、アセンブリ(DLL)からメタ情報を抽出し加工することもできそうです。
楽をするためなら苦労を厭わないのがプログラマの信条かと存じます。T4 templateで「コードを書く」コードを書いてみませんか?
