StringTemplateを結構気に入った。
Velocityをずっと使ってきたけど、次からはこっちを使おうかなぁ。
↓みたいにテンプレートを分割して定義して、それを組み合わせれるのが素敵。
group field;
vardef(type, name) ::=<<
$type$ $name$;
>>
field(mod, type, name) ::=<<
$mod$ $vardef(type=type, name=name)$
>>
vardefというテンプレートとfieldというテンプレートが定義されてる。
vardef("int", "i")だと "int i;"が出力される。
field("private", "int", "i")だと"private int i;"が出力される。
fieldの中でvardefを呼び出してるのがポイント。
C#側からは、StringTemplateGroupとStringTemplateクラスを使って処理をやる。
コードはこんな感じ。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Antlr.StringTemplate;
using Antlr.StringTemplate.Language;
using System.IO;
using System.Reflection;
namespace StringTemplateTest2
{
class Program
{
static void Main(string[] args)
{
// さっきのテンプレートを、StringTemplateTest2.Templates.field.stgとして
// 埋め込まれたリソースに入れ込んでる
var r = new StreamReader(
Assembly.GetExecutingAssembly().GetManifestResourceStream(
"StringTemplateTest2.Templates.field.stg"));
// StringTemplateGroupを作って
var group = new StringTemplateGroup(r, typeof(DefaultTemplateLexer));
// vardefを取り出してパラメータをセットして出力
var vardef = group.GetInstanceOf("vardef");
vardef.SetAttribute("type", "int");
vardef.SetAttribute("name", "i");
Console.WriteLine(vardef.ToString()); // int i;
// fieldを取り出してパラメータをセットして出力
var field = group.GetInstanceOf("field");
field.SetAttribute("mod", "private");
field.SetAttribute("type", "int");
field.SetAttribute("name", "i");
Console.WriteLine(field.ToString()); // private int i;
}
}
}
Velocityだと、こういう風に細かく定義とかできなかったと思う。
因みに、vardef.stとfield.stというファイルにわけてテンプレートを定義してFilesというフォルダに入れても大丈夫。
StringTemplateGroupを作るときに、グループ名(適当),ルートフォルダ,DefaultTemplateLexerを渡して作るだけ。
後の部分はさっきと同じで、同じ実行結果が得られる。
var group = new StringTemplateGroup(
"field", "Files", typeof(DefaultTemplateLexer));
vardef.stとfield.stは↓のようになる。
vardef.st
$type$ $name$;
field.st
$mod$ $vardef(name=name,type=type)$