最小抽象ファイルシステムの仕様案を最初に出したのは、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としての体裁が整うでしょう。