T4

えー、更新がかなり久しぶりになってしまいました。
ちょうど2カ月ぶりですね。
なんかもう記事の書き方を忘れてしまいました。


そのようなどうでもいいことは置いておいて、さっそく今回のトピックスの紹介です。
その名も「T4」
何の略かというと「Text Template Transformation Toolkit」の略だそうです。
もちろんターミネーター4ではありません。


この名前の時点でどのようなことを行うものなのか想像がつくかもしれません。
はてなキーワードにも一応どのようなものかの解説があるようです。
が、この解説に対して一つツッコミたいところがあるのですがそれはおいおい別の記事で。


このT4の機能をごく簡単に説明してしまうと
「テキストを生成する」
ということです。
このテキストというのはメモ帳なので開ける普通のテキストを指します。
なのでもちろん拡張子が違うだけの各言語のソースコードXMLファイルなども含まれます。


言葉で説明するより実物のソースコードを提示した方が速いと思うので早速T4のコードを示してみます。

<#@ template language="C#" #>
<#@ output extension=".txt" encoding="Shift_JIS" #>
Hello World!!

<#
for(int i = 0;i < 10;++i)
{
#>
<#=i#>_<#=System.DateTime.Now#>
<#
}
#>

このようにして作成し上記のコードをもとにファイル生成を行った結果を示します。

Hello World!!

1_09/07/2009 02:22:29
2_09/07/2009 02:22:29
3_09/07/2009 02:22:29
4_09/07/2009 02:22:29
5_09/07/2009 02:22:29
6_09/07/2009 02:22:29
7_09/07/2009 02:22:29
8_09/07/2009 02:22:29
9_09/07/2009 02:22:29
10_09/07/2009 02:22:29


コードと結果を示したのはいいですが、どうやってこれを実行すればいいのかをまだ書いていませんでした。
ので開発と実行の環境を解説します。


まず開発の環境ですが、僕はVisual Studio2008のProfessionalを使用しています。
このバージョンであれば特に追加で何かをインストールする必要はないはずです。
ほかのバージョンやvs2005については確認することができないので確かな情報ではないのですが、
各バージョンにあったVisual Stuido SDKというものをインストールすれば環境は整うと思います。


次にC++以外のプロジェクトを作成します。C++以外のプロジェクトというのはC#VB.NETのことです。
プロジェクトが作成できれば、
「プロジェクト」メニューの「新しい項目の追加」もしくは
ソリューションエクスプローラでプロジェクト名を右クリックし「追加」→「新しい項目」とクリックしていくと新しい項目の追加ダイアログが出ます。


ここまではごく当たり前の手順です。
ですが次の手順は少し特殊(なのかな?)なので僕は最初少し戸惑いました。
どのような手順かというと、

  1. ダイアログ左側のカテゴリから全般を選択
  2. 右側のテンプレートの中からテキストファイルを選択
  3. ファイル名の拡張子を「txt」から「tt」に変更(ファイル名は任意でok)
という手順を踏みます。


T4には現状テンプレートがないようなので一旦テキストファイルを選択し拡張子をT4を表す「tt」に変更する必要があります。


次に実行環境ですが、こちらもVisual Studio上で行えます。
方法はソリューションエクスプローラ上の先ほど作成したT4のファイルを右クリックし『カスタムツールの実行」を選択するだけです。
編集途中の場合であれば、そのファイルを保存するだけで自動的にカスタムツールは実行されテキスト生成が行われます。


環境を説明したところでコードに戻ります。

<#@ template language="C#" #>
<#@ output extension=".txt" encoding="Shift_JIS"#>
Hello World!!

<#
for(int i = 0;i < 10;++i)
{
#>
<#=i + 1#>_<#=System.DateTime.Now#>
<#
}
#>
Hello World!!

1_09/07/2009 02:22:29
2_09/07/2009 02:22:29
3_09/07/2009 02:22:29
4_09/07/2009 02:22:29
5_09/07/2009 02:22:29
6_09/07/2009 02:22:29
7_09/07/2009 02:22:29
8_09/07/2009 02:22:29
9_09/07/2009 02:22:29
10_09/07/2009 02:22:29

コードにはC#のような部分とT4特有の部分が含まれています。
このコードを上から順に解説していきます。


まず1行目と2行めはそれぞれ<#@ #>で囲まれています。このタグで囲まれたものを『ディレクティブ』と呼びます。
CやC++が分かる方であれば、#defineのようなプリプロセッサみたいなものと思ってもらえると理解しやすいかもしれません。(実際はかなり別物ですが)
このディレクティブにはさまざまな種類があるので、今回は書いてある二つだけを説明します。


templateディレクティブはこのコードそのものの情報やオプションを指定します。
今回は記述する言語にC#を利用しているということを表す「language="C#"」というものを指定しています。ほかに指定できる言語に「VB」がありこれを指定した場合は次の部分にあるfor文をVBの構文で書くことができます。
templateディレクティブにはまだほかにも指定できるオプションがありますがそれらについて今回は触れません。


次にoutputディレクティブです。これは理解しやすいと思います。
extensionで出力するファイルの拡張子を指定し、encodingで保存する文字コードを指定します。


次に続くのはHello World!!の文字と空行です。
そしてこの二行はそのまま生成されたファイルに反映されています。
このようにどのタグにも囲まれていない部分に書かれている文字(改行だけの行を含む)はそのままファイルへ出力されます。


次の行からは慣れないとなかなか見にくい部分に入るのですが、真ん中の部分を省いてみると

<#
for(int i = 0;i < 10;++i)
{
}
#>

このように<# #>で囲まれたC#のfor文であることが分かります。<# #>で囲まれた部分を標準制御ブロックと呼び、上のlanguageで指定した言語を利用して制御文を書くことができます。
そしてもう一度全体を見ます。

<#
for(int i = 0;i < 10;++i)
{
#>
<#=i + 1#>_<#= System.DateTime.Now#>
<#
}
#>

注目してほしいのはforループ開始直後と終了直前の部分に制御ブロックの終了タグと開始タグがあるということです。
こうすることで真ん中の<#=i + 1#>_<#=System.DateTime.Now #>と書かれている行がHello World!!のようにそのままファイルに出力される行になります。


ですが結果の出力を見てわかるとおりそのままの形で出力はされません。
ここで今回利用した最後のタグである<#= #>が威力を発揮します。
これは式制御ブロックと呼ばれ、その名の通り<#= #>の中にある式(変数やプロパティ、メソッド呼び出しなど)を評価し、結果を文字列に変換して(ToStringメソッドが利用される)その文字列をファイルに出力します。
なので最初の式制御ブロックでforループの制御変数であるiを含んだ i + 1 が評価されて出力、次に単純に_が出力、最後にもう一つの式制御ブロックの中でDateTimeクラスの静的プロパティであるNowが評価され実行したタイミングの時間が10回出力されるという結果になります。


これで今回提示したコードの解説はすべて終わりです。
正直今回説明したレベルではT4に大した使い道はありません。
思いつくのは数値計算などを高速化するためあらかじめ計算済みな静的なテーブルを用意するとき、そのテーブルの自動生成をするというようなことです。
このような場合.NetのMathクラスの関数を利用することができます。


MathクラスやDateTimeクラスが使えたようにT4では.Netの豊富なライブラリを利用することができます。
次回はライブラリを使う方法について解説しようと思います。