NO TEST, NO LIFE. NO DOC, NO LIFE
uupaa.js や mofmof.js には {@hoge 〜 }@hoge のようなコードブロックを切り落として Minify する機能があるので、「ソースコードにテストもドキュメントも全部埋め込むことが可能だな〜」って3年程前から考えてました。
そこで、Function.prototype.spec というメソッドを追加し、これにスペックを書き貯めたらどうだろうか(?)とか考えました。
たとえば
Array.range(1,7) で [1..7] 的な連続した数値の配列を生成する Array.range 関数があったとすると
// Array.range - range generator function Array_range(begin, // @param Number: begin end, // @param Number: end filter) { // @param Function/Number(= 1): filter or skip count // @return Array: [Number, ...] // @raise: Error("BAD_ARG") // @see: Array#range var rv = [], ri = 0, i = begin, iz = end, skip = 1; if (Type.isFunction(filter)) { for (; i <= iz; ++i) { if (filter(i) === true) { rv[ri++] = i; } } return rv; } if (Type.isNumber(filter)) { skip = filter; } if (skip <= 0) { throw new Error("BAD_ARG"); } for (; i <= iz; i += skip) { rv[ri++] = i; } return rv; }
この場合、スペックは以下のような感じで記述してます。
//{@spec Array.range.spec({ desc: ["Function", "range generator"], begin: ["Number", "begin"], end: ["Number", "end"], filter: ["Function/Number(= 1)","filter or skip count"], ret: ["Array", "[Number, ...]"], raise: 'Error("BAD_ARG")', see: "Array#range" }); //}@spec
まだ荒削りだけど、
- Function.prototype.spec._spec にスペック一覧が保存されている
- Function.prototype.spec._src に関数を実行可能な形(改行やコメントも含んだ文字列)で格納している
- node.js 上で走らせて、html + css に落とし込めば、ドキュメントが生成できる
- 関数がソースコードに書かれた文字列そのままの形で取り出せるから、ドキュメント上で関数を実行するインタプリタも付けられる
- spec に基づき IN と OUT をチェックする assert を自動生成することも可能
とか考えてました。
jsdoc だと、かゆいところに手が届かないので、こういうことになってしまうわけですが。まぁこれはこれで
Function.prototype.spec の実装はこんな感じ
// Function.prototype.spec - add function spec function Function_spec(hash) { // reserved:{ desc, ret, see, test } Function_spec._spec || (Function_spec._spec = {}, Function_spec._src = {}); var fnName = this.name, // function name i, iz, ary; // pick up function.name [IE6][IE7][IE8][IE9][Opera9][Opera10.1x] if (!fnName) { fnName = this + ""; fnName = fnName.slice(9, fnName.indexOf("(")); // ) } Function_spec._spec[fnName] = hash; Function_spec._src[fnName] = this + ""; if ("test" in hash) { ary = hash.test; for (i = 0, iz = ary.length; i < iz; i += 3) { ary[i].test(ary[i + 1], ary[i + 2] || ""); } } }
通常利用時は {@spec 〜 }@spec コードブロックを削除して minify する感じです。
//{@spec Function.prototype.spec || (Function.prototype.spec = Function_spec); String.prototype.test || (String.prototype.test = String_test); //}@spec
String.prototype.test() は類似検索と深度探索を行う、テスト君です。
http://mofmof-js.googlecode.com/svn/trunk/test/object.js.htm をブラウザで表示し、ブラウザのコンソールを見てみると、(↓)のようなセルフテストの結果が出力されます。これをやってるのが、String#test() です。
これも1つのワンソース・マルチユース。テストもドキュメントもコードに埋め込んでしまえば良いのではないのでしょうか?