前回、Trac に XML-RPC 経由でチケットを投稿する | Moonmile Solutions Blog で、コマンドライン版ができたので、これを windows アプリケーションから作ります。
通常、Unix/Linux の場合には、コマンド呼出をアプリケーションの内部に持って、パイプでつなげるという手法を取ります。windows アプリの場合でも、コマンドラインツールに GUI をくっ付ける場合は、そうします。
また、ライブラリとして切り出すことも可能なのですが…実は、.NET の場合には、直接コマンドラインツールを参照設定することで、ツール内にあるクラス(今回は、TracTools クラス)を使えます。クラスライブラリは DLL に限らず、普通の exe ファイルでも使えるのです…という例ですね。
今までは、COM で作ったり、DLL で関数を共通化したりという小細工が必要(設計段階で考えなくちゃいけなかったという意味で)になるのですが、.NET の場合は、exe を直接クラスライブラリとして扱えるので、適当なクラス分けさえしてあれば、windows アプリケーションとして動作させるのも簡単なのです。
# まぁ、コマンドラインツールのほうで、適度にクラス化が必要なわけですが。そのあたりが、UIDD(User Interface Driven Development)に繋がります。
windows アプリのコードは以下のようにさっくりと、
namespace TracWin
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
_trac.Setting.Url = "http://localhost:8000/trac/gokui-ios5/login/rpc";
_trac.Setting.UserName = "masuda";
_trac.Setting.Password = "masuda";
}
private string _Repoter = "masuda";
private TracTools _trac = new TracTools();
private Ticket _ti = null;
/// <summary>
/// 新規作成
/// テキストボックス等をクリアする
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonNew_Click(object sender, EventArgs e)
{
textBoxID.Text = "";
textBoxID.Enabled = true;
textBoxSummary.Text = "";
textBoxRepoter.Text = _Repoter;
textBoxOwner.Text = "someone";
textBoxDescription.Text = "";
textBoxAction.Text = "";
textBoxActionValue.Text = "";
_ti = null;
}
/// <summary>
/// 指定IDのチケットを読み込む
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonGet_Click(object sender, EventArgs e)
{
if (textBoxID.Text == "")
return;
int id = int.Parse(textBoxID.Text);
Ticket ti = _trac.TicketGet(id);
textBoxID.Enabled = false;
textBoxSummary.Text = ti.Summary;
textBoxRepoter.Text = ti.Reporter;
textBoxOwner.Text = ti.Owner;
textBoxDescription.Text = ti.Description;
_ti = ti;
}
/// <summary>
/// チケットを書き込む
/// IDが空白の場合は、新規登録。
/// IDが空白でない場合は、更新登録。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonPost_Click(object sender, EventArgs e)
{
if (textBoxID.Text == "")
{
// 新規登録
Ticket ti = new Ticket();
ti.Summary = textBoxSummary.Text;
ti.Description = textBoxDescription.Text;
ti.Reporter = textBoxRepoter.Text;
ti.Owner = textBoxOwner.Text;
int id = _trac.TicketCreate(ti);
textBoxID.Text = id.ToString();
_ti = ti;
textBoxID.Enabled = false;
}
else
{
// 更新登録
int id = int.Parse(textBoxID.Text);
Ticket ti = _ti;
ti.Description = textBoxDescription.Text;
ti.Owner = textBoxOwner.Text;
_ti = _trac.TicketUpdate(ti);
textBoxID.Enabled = false;
}
}
/// <summary>
/// 指定IDのチケットを削除
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonDelete_Click(object sender, EventArgs e)
{
if (_ti == null)
return;
_trac.TicketDelete(_ti.ID);
textBoxID.Text = "";
textBoxSummary.Text = "";
textBoxRepoter.Text = _Repoter;
textBoxOwner.Text = "someone";
textBoxDescription.Text = "";
textBoxAction.Text = "";
textBoxActionValue.Text = "";
textBoxID.Enabled = true;
_ti = null;
}
/// <summary>
/// アクションを更新
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonAction_Click(object sender, EventArgs e)
{
if (_ti == null)
return;
string act = textBoxAction.Text;
_ti = _trac.TicketUpdate(_ti, act);
}
}
}
画面もチープな感じでよいので、こんな感じ。
こんな風にプロトタイプを作る場合には、
- コマンドラインツールで動作確認
- 適度にクラス分けをしておく(特に呼び出し形式に注意)
- チープな画面で windows アプリとして作る
という流れで作ります。NUnit が絡むところは、1 と 2 の間ぐらいなのですが、1 で動作確認をしていると NUnit を使わなくてもそこそこ動作ができます。いわゆるコードの品質が上がります。
windows アプリを作る 3 の段階では、既に内部の動作確認済みなので、GUI との結合だけを確認します。
そして、その後、画面をリッチにしたり、ボタンの制御(不要なときは押せないとか)の処理を入れていきます。
こういう風に組み立てていくと、不思議な動作による手戻り…というかバグ解析が減るので、結構効率があがりますよ、という話です。あと、今回の trac を xml-rpc でアクセスするような内部動作がいまいち不明な場合、try and error が必要な場合は、こんな風に手順よくやっていったほうが結果的に早く終わります。

