/** * Copyright (c) 2006 JC Wichman | www.Objectpainters.com * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated * documentation files (the "Software"), to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and * to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Taking our ClassFinder trick just a little bit further, we implemented a FunctionFinder, which does the same as * the ClassFinder but then at the class level (the ClassFinder actually worked at the package level, going through * packages, finding classes. The FunctionFinder goes through a class' functions, adding information to them. * * It is probably easiest to use this class through the ClassFinder. * Note that this class will not be able to copy with reassigning functions to other functions etc (the information * returned will not be correct). * * @todo make sure the ASSetPropFlags go back to a good default * @todo make sure the added properties are hidden from for in loops! * * @author J.C. Wichman, www.objectpainters.com * $LastChangedDate: 2006-09-01 15:02:56 +0200 (vr, 01 sep 2006) $ * $Rev: 97 $ * @leading op */ class objectpainters.library.reflect.FunctionFinder { private static var nameField:String = "objectpainters.library.reflect.FunctionFinder_____emaNnoitcnuf"; //use a name not likely to cause a name collision private static var classField:String = "objectpainters.library.reflect.FunctionFinder_____ssalCniotcnuf"; //use a name not likely to cause a name collision /** * Registers a class, causing it to be processed, which will add extra details to each function in a class. * * @param classObject the class object to recurse * @param showRegistration show the functions we have found through a trace or not */ public static function registerClass (classObject : Function) { FunctionFinder.functionPusher (classObject); } /** * @param obj the function to return the name for * @return the given's function's name */ public static function getFunctionName (obj : Function):String { return obj[FunctionFinder.nameField]; } /** * @param obj the function to return the class for * @return the given's function's class (the class it was defined in, not the scope it's running in) */ public static function getFunctionClass (obj : Function):String { return obj[FunctionFinder.classField]; } /** * Unprotects the given object, iterates over all it's functions and reprotects the object. * During iteration, function name info and defining class info are added to the iterated function. * * @param node the class being iterated * @param showRegistration show any functions found through trace */ private static function functionPusher (classObj : Function) { if (classObj.constructor == null) { throw new Error ("Given node is a function, but not a class."); } //just safeguarding.... var unprotected:Number = 0; //for (var childNode in classObj) { // unprotected++; // trace(childNode); //} var unprotectedList:Array = new Array (); for (var childNode:String in classObj.prototype) { unprotected++; //trace(childNode); unprotectedList.push(childNode); } //_global.ASSetPropFlags(node,null,0, 1); //first the statics for (var propName:String in classObj) { if (classObj[propName] instanceof Function) { FunctionFinder.assignNameAndClass (classObj[propName], propName, classObj); } } //_global.ASSetPropFlags(node,null,1, 1); _global.ASSetPropFlags(classObj.prototype,null,0, 1); for (var propName:String in classObj.prototype) { if (classObj.prototype[propName] instanceof Function) { //FunctionFinder.assignNameAndClass (classObj.prototype[propName], propName, Function (classObj.prototype)); FunctionFinder.assignNameAndClass (classObj.prototype[propName], propName, classObj); } } //protect everything _global.ASSetPropFlags(classObj.prototype,null,1, 1); //unprotect those that where unprotected in the first place _global.ASSetPropFlags(classObj.prototype,unprotectedList,0, 1); //trace("-----------------"); var unprotected2:Number = 0; //for (var childNode in classObj) {unprotected2++; // trace(childNode); // } for (var childNode:String in classObj.prototype) {unprotected2++; // trace(childNode); } //trace (unprotected+" vs "+unprotected2); if (unprotected != unprotected2) { trace("FunctionFinder problem detected."); } } /** * Assign a name and a class to the target, using the static fields nameField and classField. * * @param target the target to assign the info to * @param name the name of the target * @param theClass the class which defines the target */ private static function assignNameAndClass (target:Function, name:String, theClass:Function) { target[FunctionFinder.nameField] = name; target[FunctionFinder.classField] = theClass; _global.ASSetPropFlags(target,[FunctionFinder.nameField, FunctionFinder.classField],1, 1); } /** * @param caller the object we wish to represent as string * @return a string representation of the given caller, "?" if we cannot identify it */ public static function getCallerAsString(caller:Object):String { if (caller == null) { return null; } else if (typeof(caller) == "string") { return String("*"+caller); } else { var functionName:String = FunctionFinder.getFunctionName (Function(caller)); if (functionName == null) { return null; } else { return functionName; } } } }