概要
- スライド: Cushion - 状態遷移表ライブラリ
- 7年前に公開した記事の状態遷移表ライブラリを独立させ、dubパッケージのライブラリとして公開
- 通信のハンドシェイク、画面遷移、イベント管理なんかに最適
どんなライブラリか?
状態によってふるまいが変わるプログラムの設計・実装の補助を行うためのライブラリです。
以下の表は状態遷移表の一例です。各記号は、わかりやすさのためにつけてあり、□で表の名前、▽で状態、〇でイベント、・で処理を表現しています。
□音楽プレイヤー | ▽停止 | ▽再生 | ▽一時停止 |
---|---|---|---|
〇開始ボタン | ▽再生 ・音楽を再生する |
▽一時停止 ・音楽を停止する |
▽再生 ・音楽を再生する |
〇停止ボタン | ▽停止 ・音楽を停止する ・最初に戻る |
▽停止 ・最初に戻る |
▽▽▽な状態で、〇〇〇なイベントが起こったら、・・・な処理を実行して、次の状態になることを示す表□□□というイメージです。
この表を、CSV形式で作成し、直接D言語のコードに変換してしまうのが、状態遷移表ライブラリcushionです。
使い方
dubのプロジェクト設定にdependencies
と、stringImports
を追加します。
{
"//" : " ...",
"dependencies": {
"cushion": "~><current-version>"
},
"//" : " ..."
}
次に、状態遷移表を書きます。
例: https://github.com/shoo/cushion/blob/master/examples/stmtest/views/MusicPlayer.stm.csv
表は、CSV形式で、1つのセルに改行を含む、UTF-8形式の文字コードで保存します。
状態遷移表を書く時は、表計算ソフトを使うといいと思います。EXCELでやる場合は、サンプルに挙げたxlsmファイルを使うといいかもしれません。UTF-8でCSVにエクスポートするVBAを書きました。(クソが…ッ
状態遷移表は、状態遷移を記載する表と、自然言語(日本語)→D言語の変換表の2部構成です。
変換表は以下のようなイメージ。
日本語 | 変換後のD言語 |
---|---|
〇開始ボタン | onStart |
・音楽を停止する | player.stopMusic(); |
例: https://github.com/shoo/cushion/blob/master/examples/stmtest/views/MusicPlayer.map.csv
ソースコードの内部でcushionをimportして、以下のようにします。
import cushion;
mixin(loadStmFromCsv!"MusicPlayer");
auto stm = makeStm();
ここで作られるstm
というオブジェクトに、イベントstm.put(Event.play)
って感じに伝えてあげることで、状態遷移表に記載した処理が動作します。
中身はどうなってるの?
おおざっぱに言うと、以下のようなことをしています。コンパイル時に。
- CSVをstd.csvでパース
- 状態遷移表を日本語からD言語のコードに置換表で置換
- 状態とイベントのenumを作成
- 状態×イベントの「遷移先の状態」テーブルを作成
- 各セルごとに1つ関数を作成
- 状態×イベントの関数テーブルを作成
あとは、状態×イベントごとに呼び出すテーブルの列×行を変えています。
このような、外部ファイルに保存したDSLをコンパイル時にパースしてD言語に置き換えてstring mixin、みたいなのは、D言語だからこそできる仕組みといえるかもしれませんね。
ちなみに、これを行っているのはこのファイル(CSVのパース)とこのファイル(コード生成)です。
今後の展望
特に考えていません。
アイデア自体は7年以上前に固まっており、今回単品で使えるようにしただけで、割と枯れています。
私が一人で使用している分には、特に問題なく使えていますし。
ただ、いつまでもバージョン0.0.0というわけにもいかないと思うので、適当なところで1.0.0にしたいと思います。
「こんな使い方したいのだけど・・・」みたいな相談や、できないことがあったらIssueに登録してください。日本語でOKです。
余談
イキってフォーラムでアナウンスしたら、@trusted
警察に絡まれました。
状態遷移表に記載したコードがunsafeであっても、@trusted
によって握りつぶされてしまうというものですが、今のところこれにまじめに取り組むつもりはありません。(メリット以上に利便性を損なうと考えているため)
今後D言語がデフォルトで@safe
になった場合に改めて考えます。