/* advice.js * by M.Hiyama (hiyama{at}chimaira{dot}org) 2005 * URL: http://www.chimaira.org/ */ /* Thanks-To: nak2k (for some tips & tricks) */ /* 補助的な関数:_getFunctionByFQN, _setFunctionAsFQN */ function _getFunctionByFQN(fqn) { var names = fqn.split('.'); var obj = (function() {return this;}).apply(null); // global for (var i = 0, name; name = names[i] ; i++, obj = obj[name]) { if (!obj) break; } if (typeof obj == 'function') { return obj; } else { return null; } } function _setFunctionAsFQN(fqn, func) { var myName = arguments.callee.name; // エラーメッセージ用 var names = fqn.split('.'); var givenName = names.pop(); var scope = (function() {return this;}).apply(null); // global for (var i = 0, name; name = names[i] ; i++, scope = scope[name]) { if (!scope) throw new Error(myName + ":illegal function full-name"); } scope[givenName] = func; } /* addAdvice */ function addAdvice(funcFQN, advice, force_) { var myName = arguments.callee.name; // エラーメッセージ用 // 関数オブジェクトを取得 var original = _getFunctionByFQN(funcFQN); if (!original) { throw new Error(myName + ": cannot find target function."); } // その関数がアドバイスのとき if (original.isAdvice && !force_) { throw new Error(myName + ": the function is an advice," + " use force flag (specify 3rd argument)."); } // 新しいアドバイス関数を生成 var code; if (typeof advice == 'function') { code = advice.toString().replace(/\s*function \w+\([^)]*\)\s*/, ""); } else { throw new Error(myName + ": illegal advice type " + "(advice must be a function)."); } var newFunc = new Function(code); // アドバイス関数のプロパティを設定 newFunc.isAdvice = true; newFunc.original = original; newFunc.originalName = funcFQN; // もとの関数をアドバイス関数で置き換える _setFunctionAsFQN(funcFQN, newFunc); } /* removeAdvice */ function removeAdvice(funcFQN) { var myName = arguments.callee.name; // エラーメッセージ用 // 目的の関数を取得 var func = _getFunctionByFQN(funcFQN); if (!func) { throw new Error(myName + ": cannot find target function."); } // アドバイスかどうか調べる if (!func.isAdvice || typeof func.original != 'function') { return; // do nothing } // もとの関数に戻す _setFunctionAsFQN(funcFQN, func.original); // 念のためクリーンアップ delete func.isAdvice; delete func.original; delete func.originalName; }