最小抽象ファイルシステムの仕様案を最初に出したのは、6月3日「最小抽象ファイルシステムの仕様案」で、ほぼ固まったのが7月7日「最小抽象ファイルシステム、そろそろ実装」です。このあいだの変更は以外に少なくて、次のメタデータ周りの事項です。
- ファイルメタデータとディレクトリメタデータを集約して1種類にした。
- メタデータ項目から、readOnlyとhiddenを落とした。
- メタデータ操作APIを落とした。
一方、Catyのコマンド記述のための構文も試案ができました。そこで、最小抽象ファイルシステムのAPIをコマンド宣言の形式で書いてみます。APIはコマンドセットじゃないけど、意味的には同じようなもんです。
/** 最小抽象ファイルシステムの仕様
* 型とコマンド(関数)
*/
module caty.mafs
provides type // 共通の型
[TimeStamp, Binary]
provides type // 固有の型
[Path, AuthoriToken, Metadata,
DirectoryEntry, DirectoryEntryList]
privides command // 読み取り用
[readFile, readDirectory, getMetadata]
privides command // 書き込み/変更用
[createFile, createDirectory, // 生成
deleteFile, deleteDirectory, delete, // 削除
writeFile // 更新/書き込み
]
;
/*
* 型の定義
*/
/** タイムスタンプ */
type TimeStamp = opaque;
/** バイナリデータ */
type Binary = opaque;
/** mafsのパス
* http://d.hatena.ne.jp/m-hiyama/20090608/1244419502 を参照
*/
type Path = string(remark = "mafsのパス");
/** 認可トークン=アクセス権限 */
type AuthoriToken = opaque;
/** ファイルとディレクトリのメタデータ */
type Metadata = object {
/** 内容のバイトサイズ */
"contentLength" : integer(minimum = 0),
/** 内容のメディアタイプ
* @default "application/octet-stream"
*/
"contentType" : string(remark = "MIMEタイプ")?,
/** ファイルが作られた時
* 省略されると不明を意味する
*/
"created" : TimeStamp?,
/** ファイルが最後に変更された時 */
"lastModified" : TimeStamp,
/** 内容がテキストデータかどうか
* @default false
*/
"isText" : boolean?,
/** 内容がテキストのとき、その文字エンコーディングスキーム
* @default "utf-8"
*/
"textEncoding" : string(remark = "文字エンコーディングスキーム")?,
/** 実行可能ファイルかどうか
* @default false
*/
"executable" : boolean?
};
/** ディレクトリエントリー */
type DirectoryEntry = object {
/** フィイルのベース名 */
"name" : string(remark = "ファイルのベース名"),
/** ファイル/ディレクトリのメタデータ */
"metadata" : Metadata
};
type DirectoryEntryList = array [ DirectoryEntry* ];
/*
* コマンド(実際は関数だけど)
* 例外の記述は省略
*/
/*
* 読み取り用
*/
/** パスで指定されたファイルの内容を読む */
command readFile [AuthoriToken, Path]
:: void -> Binary;
/** パスで指定されたディレクトリの内容を読む */
command readDirectory [AuthoriToken, Path]
:: void -> DirectoryEntryList;
/** パスで指定されたファイル/ディレクトリのメタデータを取得 */
command getMetadata [AuthoriToken, Path]
:: void -> Metadata;
/*
* 書き込み/変更用
*/
/** パスで指定されたファイルを新規作成 */
command createFile [AuthoriToken, Path]
:: void -> void;
/** パスで指定されたディレクトリを新規作成 */
command createDirectory [AuthoriToken, Path]
:: void -> void;
/** パスで指定されたファイルを削除 */
command deleteFile [AuthoriToken, Path]
:: void -> void;
/** パスで指定されたディレクトリを削除 */
command deleteDirectory [AuthoriToken, Path]
:: void -> void;
/** パスで指定されたファイル/ディレクトリを削除 */
command delete [AuthoriToken, Path]
:: void -> void;
/** パスで指定されたファイルの内容を上書きする */
command writeFile [AuthoriToken, Path, Binary]
:: void -> void;ちょっと感想を書きます。mafsに関する感想じゃなくて、型定義/コマンド宣言構文に関する感想。
- 頭部(モジュール宣言文)の構文はハッキリ決めてなかったのですが、こんな感じでしょう。
- TimeStamp型とBinary型は、caty.mafs以外のもっと一般的なモジュールで定義されるべきでしょう。caty.mafs:Binaryより、caty:Binary、あるいは単にBinaryが自然でしょう。
- 「/**」はドキュメンテーションコメントの開始です。ドキュメンテーションコメントは、直後の構文要素に関係づけられます。javadocやEDocと似たツールが必要です。
- ドキュメンテーションコメント内は、プレーンテキスト、またはCreole wiki構文でいいかな、と思ってますが、スキーマ内でデフォルト値を書けないので、@default とか使ってみました。アットマークタグをほんとにサポートするかどうかは未定です。
- 「詮索は不要、中身を見るな」という意味で opaque というキーワードを付け足しました。あるレベルのアプリケーションにとって詳細が不要なときに、これは必要ですね。
- opaqueは、データの構造に関する情報を意図的に提供しないのですが、「まだ定義してない」ということを表すdeferredキーワードも必要でしょう。
- 空なオプション{}、空なプレーン引数[]は、やっぱり省略できたほうがいいですね。
- 上の例では使ってませんが、API記述で使うにはアノテーションも必要そうです。例えば、読み取り関数には @reader、更新関数には @updater とか。
- JSONスキーマの代替構文としてはじまったCaty/Jcentric型定義ですが、IDL(Interface Definition Language)として利用することになりそうです。もう少し拡張すれば、IDLとしての体裁が整うでしょう。