mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-16 13:31:18 +00:00
Typo, symlinks
This commit is contained in:
1 parent
ba4e3bab5c
commit
9a472731d8
4 files changed
+469
-237
No files matched your search
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
* CPTrace.j
|
||||
*
|
||||
* Created by cacaodev
|
||||
* Copyright 2012 <cacaodev@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
var patchedClassesAndSelectors = [],
|
||||
globalStack = [],
|
||||
globalLevel = 0;
|
||||
|
||||
var Tracer = function()
|
||||
{
|
||||
this.td = 0;
|
||||
this.tc = 0;
|
||||
this.displayFunction = nil;
|
||||
};
|
||||
|
||||
Tracer.prototype.log = function()
|
||||
{
|
||||
var c = globalStack.length;
|
||||
|
||||
for (var i = 0; i < c; i++)
|
||||
{
|
||||
var trace = globalStack.shift();
|
||||
this.displayFunction(trace.receiver, trace.selector, trace.args, trace.duration, this.td, this.tc, trace.level);
|
||||
}
|
||||
};
|
||||
|
||||
var defaultDisplay = function(receiver, selector, args, duration, total_duration, total_count, level)
|
||||
{
|
||||
var message = objj_message(receiver, selector, args),
|
||||
// WARNING: average duration only supported for root calls.
|
||||
avg_message = (level == 0) ? (" , avg = " + (ROUND(100 * total_duration / total_count) / 100) + " ms") : "";
|
||||
|
||||
console.log(indent(level) + message + " in " + duration + " ms" + avg_message);
|
||||
};
|
||||
|
||||
var indent = function(n)
|
||||
{
|
||||
var str = "";
|
||||
while (n--)
|
||||
str += " ";
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
var objj_message = function(receiver, selector, args)
|
||||
{
|
||||
var c = args.length,
|
||||
sel = selector.split(":"),
|
||||
rdesc = receiver ? [receiver description] : "<null>";
|
||||
|
||||
while (c--)
|
||||
sel.splice(c + 1, 0, ":" + [args[c] description] + " ");
|
||||
|
||||
var joined = sel.join("");
|
||||
|
||||
if (args.length)
|
||||
joined = joined.substring(0, joined.length - 1);
|
||||
|
||||
return ("[" + rdesc + " " + joined + "]");
|
||||
};
|
||||
|
||||
function CPTrace(aClassName, aSelector, displayFunction)
|
||||
{
|
||||
var aclass = CPClassFromString(aClassName);
|
||||
|
||||
if (aclass)
|
||||
_CPTraceClass(aclass, aSelector, displayFunction);
|
||||
else if (typeof(objj_getClassList) != 'undefined')
|
||||
{
|
||||
var classes = [],
|
||||
patchednum = 0,
|
||||
numclasses = objj_getClassList(classes, 400),
|
||||
regex = new RegExp(aClassName);
|
||||
|
||||
while (numclasses--)
|
||||
{
|
||||
var cls = classes[numclasses];
|
||||
if (regex.test(cls))
|
||||
{
|
||||
console.log("Patching " + cls + " -" + aSelector);
|
||||
_CPTraceClass(cls, aSelector, displayFunction);
|
||||
patchednum++;
|
||||
}
|
||||
}
|
||||
|
||||
if (patchednum == 0)
|
||||
console.log("Could not find any class matching '" + aClassName + "'");
|
||||
else
|
||||
console.log("Patched " + patchednum + " classes matching " + aClassName);
|
||||
}
|
||||
else
|
||||
[CPException raise:CPInvalidArgumentException reason:("Unknown class name '" + aClassName + "'")];
|
||||
}
|
||||
|
||||
var _CPTraceClass = function(aClass, aSelector, displayFunction)
|
||||
{
|
||||
if (![aClass instancesRespondToSelector:aSelector])
|
||||
[CPException raise:CPInvalidArgumentException reason:(aClass + " does not respond to '" + aSelector + "'")];
|
||||
|
||||
var superclass = aClass;
|
||||
while (![superclass instancesImplementsSelector:aSelector] && superclass != [CPObject class])
|
||||
superclass = [superclass superclass];
|
||||
|
||||
var patchUniqueString = (superclass + "_" + aSelector);
|
||||
if ([patchedClassesAndSelectors containsObject:patchUniqueString])
|
||||
{
|
||||
if (superclass == aClass)
|
||||
console.log(superclass + " -" + aSelector + " is already patched. Ignoring.");
|
||||
else
|
||||
console.log("-" + aSelector + " is implemented in a superclass of " + aClass + " (" + superclass + ") where it's already patched. Ignoring.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var patched_sel = CPSelectorFromString("patched_" + CPStringFromSelector(aSelector)),
|
||||
tracer = new Tracer();
|
||||
|
||||
tracer.displayFunction = displayFunction ? displayFunction : defaultDisplay;
|
||||
|
||||
class_addMethod(aClass, patched_sel, function()
|
||||
{
|
||||
var orig_arguments = arguments,
|
||||
receiver = orig_arguments[0],
|
||||
selector = orig_arguments[1],
|
||||
args = [];
|
||||
|
||||
for (var i = 2; i < orig_arguments.length; i++)
|
||||
args.push(orig_arguments[i]);
|
||||
|
||||
orig_arguments[1] = patched_sel;
|
||||
|
||||
var trace = {receiver:receiver, selector:selector, args:args, start:(new Date()), level:globalLevel};
|
||||
globalStack.push(trace);
|
||||
globalLevel++;
|
||||
|
||||
objj_msgSend.apply(objj_msgSend, orig_arguments);
|
||||
|
||||
var duration = (trace.duration = new Date() - trace.start);
|
||||
globalLevel--;
|
||||
if (globalLevel == 0)
|
||||
{
|
||||
if (duration > 0)
|
||||
tracer.tc++;
|
||||
tracer.td += trace.duration;
|
||||
tracer.log();
|
||||
}
|
||||
|
||||
}, "");
|
||||
|
||||
Swizzle(aClass, aSelector, patched_sel);
|
||||
[patchedClassesAndSelectors addObject:patchUniqueString];
|
||||
};
|
||||
|
||||
function CPTraceStop(aClass, aSelector)
|
||||
{
|
||||
var patchUniqueString = (aClass + "_" + aSelector);
|
||||
if (![patchedClassesAndSelectors containsObject:patchUniqueString])
|
||||
return;
|
||||
|
||||
var patched_sel = CPSelectorFromString("patched_" + CPStringFromSelector(aSelector));
|
||||
Swizzle(CPClassFromString(aClass), patched_sel, aSelector);
|
||||
[patchedClassesAndSelectors removeObject:patchUniqueString];
|
||||
}
|
||||
|
||||
var Swizzle = function(aClass, orig_sel, new_sel)
|
||||
{
|
||||
var origMethod = class_getInstanceMethod(aClass, orig_sel),
|
||||
newMethod = class_getInstanceMethod(aClass, new_sel);
|
||||
|
||||
// This check should be in class_addMethod : Don't add and return NO and if method already exists.
|
||||
if (getMethodNoSuper(aClass, orig_sel) == NULL)
|
||||
{
|
||||
class_addMethod(aClass, orig_sel, method_getImplementation(newMethod), "");
|
||||
class_replaceMethod(aClass, new_sel, method_getImplementation(origMethod), "");
|
||||
}
|
||||
else
|
||||
method_exchangeImplementations(origMethod, newMethod);
|
||||
|
||||
/*
|
||||
if (class_addMethod(aClass, orig_sel, method_getImplementation(newMethod), ""))
|
||||
class_replaceMethod(aClass, new_sel, method_getImplementation(origMethod), "");
|
||||
else
|
||||
method_exchangeImplementations(origMethod, newMethod);
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
var getMethodNoSuper = function(cls, sel)
|
||||
{
|
||||
var method_list = cls.method_list,
|
||||
count = method_list.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var mthd = method_list[count];
|
||||
if (mthd.name == sel)
|
||||
return mthd;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@implementation CPObject (instancesImplementsSelector)
|
||||
|
||||
- (BOOL)instancesImplementsSelector:(SEL)aSelector
|
||||
{
|
||||
var methods = class_copyMethodList(self),
|
||||
count = methods.length;
|
||||
|
||||
while (count--)
|
||||
if (method_getName(methods[count]) === aSelector)
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -87,7 +87,7 @@ CPLogRegister(CPLogConsole)
|
||||
column = [tableView columnForView:sender],
|
||||
identifier = [[[tableView tableColumns] objectAtIndex:column] identifier];
|
||||
|
||||
CPLog.debug(_cmd + " from "sender + " row = " + row + " column = " + column);
|
||||
CPLog.debug(_cmd + " from " + sender + " row = " + row + " column = " + column);
|
||||
content[row][identifier] = [sender doubleValue];
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/Volumes/GAMMA/DEVELOPPEMENT/cappuccino/cacaodev/Tests/Manual/TableTest/CPTrace.j
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* CPTrace.j
|
||||
*
|
||||
* Created by cacaodev
|
||||
* Copyright 2012 <cacaodev@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
var patchedClassesAndSelectors = [],
|
||||
globalStack = [],
|
||||
globalLevel = 0;
|
||||
|
||||
var Tracer = function()
|
||||
{
|
||||
this.td = 0;
|
||||
this.tc = 0;
|
||||
this.displayFunction = nil;
|
||||
};
|
||||
|
||||
Tracer.prototype.log = function()
|
||||
{
|
||||
var c = globalStack.length;
|
||||
|
||||
for (var i = 0; i < c; i++)
|
||||
{
|
||||
var trace = globalStack.shift();
|
||||
this.displayFunction(trace.receiver, trace.selector, trace.args, trace.duration, this.td, this.tc, trace.level);
|
||||
}
|
||||
};
|
||||
|
||||
var defaultDisplay = function(receiver, selector, args, duration, total_duration, total_count, level)
|
||||
{
|
||||
var message = objj_message(receiver, selector, args),
|
||||
// WARNING: average duration only supported for root calls.
|
||||
avg_message = (level == 0) ? (" , avg = " + (ROUND(100 * total_duration / total_count) / 100) + " ms") : "";
|
||||
|
||||
console.log(indent(level) + message + " in " + duration + " ms" + avg_message);
|
||||
};
|
||||
|
||||
var indent = function(n)
|
||||
{
|
||||
var str = "";
|
||||
while (n--)
|
||||
str += " ";
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
var objj_message = function(receiver, selector, args)
|
||||
{
|
||||
var c = args.length,
|
||||
sel = selector.split(":"),
|
||||
rdesc = receiver ? [receiver description] : "<null>";
|
||||
|
||||
while (c--)
|
||||
sel.splice(c + 1, 0, ":" + [args[c] description] + " ");
|
||||
|
||||
var joined = sel.join("");
|
||||
|
||||
if (args.length)
|
||||
joined = joined.substring(0, joined.length - 1);
|
||||
|
||||
return ("[" + rdesc + " " + joined + "]");
|
||||
};
|
||||
|
||||
function CPTrace(aClassName, aSelector, displayFunction)
|
||||
{
|
||||
var aclass = CPClassFromString(aClassName);
|
||||
|
||||
if (aclass)
|
||||
_CPTraceClass(aclass, aSelector, displayFunction);
|
||||
else if (typeof(objj_getClassList) != 'undefined')
|
||||
{
|
||||
var classes = [],
|
||||
patchednum = 0,
|
||||
numclasses = objj_getClassList(classes, 400),
|
||||
regex = new RegExp(aClassName);
|
||||
|
||||
while (numclasses--)
|
||||
{
|
||||
var cls = classes[numclasses];
|
||||
if (regex.test(cls))
|
||||
{
|
||||
console.log("Patching " + cls + " -" + aSelector);
|
||||
_CPTraceClass(cls, aSelector, displayFunction);
|
||||
patchednum++;
|
||||
}
|
||||
}
|
||||
|
||||
if (patchednum == 0)
|
||||
console.log("Could not find any class matching '" + aClassName + "'");
|
||||
else
|
||||
console.log("Patched " + patchednum + " classes matching " + aClassName);
|
||||
}
|
||||
else
|
||||
[CPException raise:CPInvalidArgumentException reason:("Unknown class name '" + aClassName + "'")];
|
||||
}
|
||||
|
||||
var _CPTraceClass = function(aClass, aSelector, displayFunction)
|
||||
{
|
||||
if (![aClass instancesRespondToSelector:aSelector])
|
||||
[CPException raise:CPInvalidArgumentException reason:(aClass + " does not respond to '" + aSelector + "'")];
|
||||
|
||||
var superclass = aClass;
|
||||
while (![superclass instancesImplementsSelector:aSelector] && superclass != [CPObject class])
|
||||
superclass = [superclass superclass];
|
||||
|
||||
var patchUniqueString = (superclass + "_" + aSelector);
|
||||
if ([patchedClassesAndSelectors containsObject:patchUniqueString])
|
||||
{
|
||||
if (superclass == aClass)
|
||||
console.log(superclass + " -" + aSelector + " is already patched. Ignoring.");
|
||||
else
|
||||
console.log("-" + aSelector + " is implemented in a superclass of " + aClass + " (" + superclass + ") where it's already patched. Ignoring.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var patched_sel = CPSelectorFromString("patched_" + CPStringFromSelector(aSelector)),
|
||||
tracer = new Tracer();
|
||||
|
||||
tracer.displayFunction = displayFunction ? displayFunction : defaultDisplay;
|
||||
|
||||
class_addMethod(aClass, patched_sel, function()
|
||||
{
|
||||
var orig_arguments = arguments,
|
||||
receiver = orig_arguments[0],
|
||||
selector = orig_arguments[1],
|
||||
args = [];
|
||||
|
||||
for (var i = 2; i < orig_arguments.length; i++)
|
||||
args.push(orig_arguments[i]);
|
||||
|
||||
orig_arguments[1] = patched_sel;
|
||||
|
||||
var trace = {receiver:receiver, selector:selector, args:args, start:(new Date()), level:globalLevel};
|
||||
globalStack.push(trace);
|
||||
globalLevel++;
|
||||
|
||||
objj_msgSend.apply(objj_msgSend, orig_arguments);
|
||||
|
||||
var duration = (trace.duration = new Date() - trace.start);
|
||||
globalLevel--;
|
||||
if (globalLevel == 0)
|
||||
{
|
||||
if (duration > 0)
|
||||
tracer.tc++;
|
||||
tracer.td += trace.duration;
|
||||
tracer.log();
|
||||
}
|
||||
|
||||
}, "");
|
||||
|
||||
Swizzle(aClass, aSelector, patched_sel);
|
||||
[patchedClassesAndSelectors addObject:patchUniqueString];
|
||||
};
|
||||
|
||||
function CPTraceStop(aClass, aSelector)
|
||||
{
|
||||
var patchUniqueString = (aClass + "_" + aSelector);
|
||||
if (![patchedClassesAndSelectors containsObject:patchUniqueString])
|
||||
return;
|
||||
|
||||
var patched_sel = CPSelectorFromString("patched_" + CPStringFromSelector(aSelector));
|
||||
Swizzle(CPClassFromString(aClass), patched_sel, aSelector);
|
||||
[patchedClassesAndSelectors removeObject:patchUniqueString];
|
||||
}
|
||||
|
||||
var Swizzle = function(aClass, orig_sel, new_sel)
|
||||
{
|
||||
var origMethod = class_getInstanceMethod(aClass, orig_sel),
|
||||
newMethod = class_getInstanceMethod(aClass, new_sel);
|
||||
|
||||
// This check should be in class_addMethod : Don't add and return NO and if method already exists.
|
||||
if (getMethodNoSuper(aClass, orig_sel) == NULL)
|
||||
{
|
||||
class_addMethod(aClass, orig_sel, method_getImplementation(newMethod), "");
|
||||
class_replaceMethod(aClass, new_sel, method_getImplementation(origMethod), "");
|
||||
}
|
||||
else
|
||||
method_exchangeImplementations(origMethod, newMethod);
|
||||
|
||||
/*
|
||||
if (class_addMethod(aClass, orig_sel, method_getImplementation(newMethod), ""))
|
||||
class_replaceMethod(aClass, new_sel, method_getImplementation(origMethod), "");
|
||||
else
|
||||
method_exchangeImplementations(origMethod, newMethod);
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
var getMethodNoSuper = function(cls, sel)
|
||||
{
|
||||
var method_list = cls.method_list,
|
||||
count = method_list.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var mthd = method_list[count];
|
||||
if (mthd.name == sel)
|
||||
return mthd;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@implementation CPObject (instancesImplementsSelector)
|
||||
|
||||
- (BOOL)instancesImplementsSelector:(SEL)aSelector
|
||||
{
|
||||
var methods = class_copyMethodList(self),
|
||||
count = methods.length;
|
||||
|
||||
while (count--)
|
||||
if (method_getName(methods[count]) === aSelector)
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1 +0,0 @@
|
||||
/Volumes/GAMMA/DEVELOPPEMENT/cappuccino/cacaodev/Tests/Manual/TableTest/CPTrace.j
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* CPTrace.j
|
||||
*
|
||||
* Created by cacaodev
|
||||
* Copyright 2012 <cacaodev@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
var patchedClassesAndSelectors = [],
|
||||
globalStack = [],
|
||||
globalLevel = 0;
|
||||
|
||||
var Tracer = function()
|
||||
{
|
||||
this.td = 0;
|
||||
this.tc = 0;
|
||||
this.displayFunction = nil;
|
||||
};
|
||||
|
||||
Tracer.prototype.log = function()
|
||||
{
|
||||
var c = globalStack.length;
|
||||
|
||||
for (var i = 0; i < c; i++)
|
||||
{
|
||||
var trace = globalStack.shift();
|
||||
this.displayFunction(trace.receiver, trace.selector, trace.args, trace.duration, this.td, this.tc, trace.level);
|
||||
}
|
||||
};
|
||||
|
||||
var defaultDisplay = function(receiver, selector, args, duration, total_duration, total_count, level)
|
||||
{
|
||||
var message = objj_message(receiver, selector, args),
|
||||
// WARNING: average duration only supported for root calls.
|
||||
avg_message = (level == 0) ? (" , avg = " + (ROUND(100 * total_duration / total_count) / 100) + " ms") : "";
|
||||
|
||||
console.log(indent(level) + message + " in " + duration + " ms" + avg_message);
|
||||
};
|
||||
|
||||
var indent = function(n)
|
||||
{
|
||||
var str = "";
|
||||
while (n--)
|
||||
str += " ";
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
var objj_message = function(receiver, selector, args)
|
||||
{
|
||||
var c = args.length,
|
||||
sel = selector.split(":"),
|
||||
rdesc = receiver ? [receiver description] : "<null>";
|
||||
|
||||
while (c--)
|
||||
sel.splice(c + 1, 0, ":" + [args[c] description] + " ");
|
||||
|
||||
var joined = sel.join("");
|
||||
|
||||
if (args.length)
|
||||
joined = joined.substring(0, joined.length - 1);
|
||||
|
||||
return ("[" + rdesc + " " + joined + "]");
|
||||
};
|
||||
|
||||
function CPTrace(aClassName, aSelector, displayFunction)
|
||||
{
|
||||
var aclass = CPClassFromString(aClassName);
|
||||
|
||||
if (aclass)
|
||||
_CPTraceClass(aclass, aSelector, displayFunction);
|
||||
else if (typeof(objj_getClassList) != 'undefined')
|
||||
{
|
||||
var classes = [],
|
||||
patchednum = 0,
|
||||
numclasses = objj_getClassList(classes, 400),
|
||||
regex = new RegExp(aClassName);
|
||||
|
||||
while (numclasses--)
|
||||
{
|
||||
var cls = classes[numclasses];
|
||||
if (regex.test(cls))
|
||||
{
|
||||
console.log("Patching " + cls + " -" + aSelector);
|
||||
_CPTraceClass(cls, aSelector, displayFunction);
|
||||
patchednum++;
|
||||
}
|
||||
}
|
||||
|
||||
if (patchednum == 0)
|
||||
console.log("Could not find any class matching '" + aClassName + "'");
|
||||
else
|
||||
console.log("Patched " + patchednum + " classes matching " + aClassName);
|
||||
}
|
||||
else
|
||||
[CPException raise:CPInvalidArgumentException reason:("Unknown class name '" + aClassName + "'")];
|
||||
}
|
||||
|
||||
var _CPTraceClass = function(aClass, aSelector, displayFunction)
|
||||
{
|
||||
if (![aClass instancesRespondToSelector:aSelector])
|
||||
[CPException raise:CPInvalidArgumentException reason:(aClass + " does not respond to '" + aSelector + "'")];
|
||||
|
||||
var superclass = aClass;
|
||||
while (![superclass instancesImplementsSelector:aSelector] && superclass != [CPObject class])
|
||||
superclass = [superclass superclass];
|
||||
|
||||
var patchUniqueString = (superclass + "_" + aSelector);
|
||||
if ([patchedClassesAndSelectors containsObject:patchUniqueString])
|
||||
{
|
||||
if (superclass == aClass)
|
||||
console.log(superclass + " -" + aSelector + " is already patched. Ignoring.");
|
||||
else
|
||||
console.log("-" + aSelector + " is implemented in a superclass of " + aClass + " (" + superclass + ") where it's already patched. Ignoring.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var patched_sel = CPSelectorFromString("patched_" + CPStringFromSelector(aSelector)),
|
||||
tracer = new Tracer();
|
||||
|
||||
tracer.displayFunction = displayFunction ? displayFunction : defaultDisplay;
|
||||
|
||||
class_addMethod(aClass, patched_sel, function()
|
||||
{
|
||||
var orig_arguments = arguments,
|
||||
receiver = orig_arguments[0],
|
||||
selector = orig_arguments[1],
|
||||
args = [];
|
||||
|
||||
for (var i = 2; i < orig_arguments.length; i++)
|
||||
args.push(orig_arguments[i]);
|
||||
|
||||
orig_arguments[1] = patched_sel;
|
||||
|
||||
var trace = {receiver:receiver, selector:selector, args:args, start:(new Date()), level:globalLevel};
|
||||
globalStack.push(trace);
|
||||
globalLevel++;
|
||||
|
||||
objj_msgSend.apply(objj_msgSend, orig_arguments);
|
||||
|
||||
var duration = (trace.duration = new Date() - trace.start);
|
||||
globalLevel--;
|
||||
if (globalLevel == 0)
|
||||
{
|
||||
if (duration > 0)
|
||||
tracer.tc++;
|
||||
tracer.td += trace.duration;
|
||||
tracer.log();
|
||||
}
|
||||
|
||||
}, "");
|
||||
|
||||
Swizzle(aClass, aSelector, patched_sel);
|
||||
[patchedClassesAndSelectors addObject:patchUniqueString];
|
||||
};
|
||||
|
||||
function CPTraceStop(aClass, aSelector)
|
||||
{
|
||||
var patchUniqueString = (aClass + "_" + aSelector);
|
||||
if (![patchedClassesAndSelectors containsObject:patchUniqueString])
|
||||
return;
|
||||
|
||||
var patched_sel = CPSelectorFromString("patched_" + CPStringFromSelector(aSelector));
|
||||
Swizzle(CPClassFromString(aClass), patched_sel, aSelector);
|
||||
[patchedClassesAndSelectors removeObject:patchUniqueString];
|
||||
}
|
||||
|
||||
var Swizzle = function(aClass, orig_sel, new_sel)
|
||||
{
|
||||
var origMethod = class_getInstanceMethod(aClass, orig_sel),
|
||||
newMethod = class_getInstanceMethod(aClass, new_sel);
|
||||
|
||||
// This check should be in class_addMethod : Don't add and return NO and if method already exists.
|
||||
if (getMethodNoSuper(aClass, orig_sel) == NULL)
|
||||
{
|
||||
class_addMethod(aClass, orig_sel, method_getImplementation(newMethod), "");
|
||||
class_replaceMethod(aClass, new_sel, method_getImplementation(origMethod), "");
|
||||
}
|
||||
else
|
||||
method_exchangeImplementations(origMethod, newMethod);
|
||||
|
||||
/*
|
||||
if (class_addMethod(aClass, orig_sel, method_getImplementation(newMethod), ""))
|
||||
class_replaceMethod(aClass, new_sel, method_getImplementation(origMethod), "");
|
||||
else
|
||||
method_exchangeImplementations(origMethod, newMethod);
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
var getMethodNoSuper = function(cls, sel)
|
||||
{
|
||||
var method_list = cls.method_list,
|
||||
count = method_list.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var mthd = method_list[count];
|
||||
if (mthd.name == sel)
|
||||
return mthd;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@implementation CPObject (instancesImplementsSelector)
|
||||
|
||||
- (BOOL)instancesImplementsSelector:(SEL)aSelector
|
||||
{
|
||||
var methods = class_copyMethodList(self),
|
||||
count = methods.length;
|
||||
|
||||
while (count--)
|
||||
if (method_getName(methods[count]) === aSelector)
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in new issue
Block a user