Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Performance optimizations for flow controllers and interceptors. #270

Closed
wants to merge 1 commit into from

3 participants

Simon Arbuckle divdavem Fabio Crisci
Simon Arbuckle
Collaborator

No description provided.

divdavem divdavem referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
divdavem divdavem referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Simon Arbuckle simonarbuckle referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
src/aria/core/JsObject.js
((34 lines not shown))
+ allInterceptors[i] = interceptedMethods;
+ }
+ }
+ },
+
+ /**
+ * Either adds an interceptor to all methods (for a callback) or targets specific methods to be intercepted.
+ * @param {Object} interfaceMethods all methods for the interface
+ * @param {Object|aria.core.JsObject.Callback} interceptor either a callback or an object/class which will
+ * receive notifications
+ * @return {Object} interceptedMethods
+ */
+ __interceptMethods : function (interfaceMethods, interceptor, allInterceptors) {
+ var interceptedMethods = allInterceptors || {};
+ var normCb = (interceptor.$classpath) ? interceptor : this.$normCallback(interceptor);
+ if (interceptor.$Callback || typeof(normCb.fn) == "function") {
Fabio Crisci
piuccio added a note

Probably it's about time that we implement an aria.utils.Type.isCallback. This check is hard to read and JsDoc might be misleading.

Object|aria.core.JsObject.Callback but actually we allow aria.core.JsObject|aria.core.JsObject.Callback

Plain objects are normalized and considered as callbacks

Simon Arbuckle Collaborator

Thanks for the feedback, I will implement a new utility function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/aria/core/JsObject.js
((48 lines not shown))
+ var normCb = (interceptor.$classpath) ? interceptor : this.$normCallback(interceptor);
+ if (interceptor.$Callback || typeof(normCb.fn) == "function") {
+ // for a callback, intercept all methods of an interface
+ for (var i in interfaceMethods) {
+ if (interfaceMethods.hasOwnProperty(i)) {
+ (interceptedMethods[i] || (interceptedMethods[i] = [])).push(interceptor);
+ }
+ }
+ } else {
+ // for a class object, intercept specific methods containing onMethodNameCallBegin,
+ // onMethodNameCallback, onMethodNameCallEnd
+ var interceptorMethodBegin, interceptorMethodCallBack, interceptorMethodEnd;
+ for (var m in interfaceMethods) {
+ if (interfaceMethods.hasOwnProperty(m)) {
+ var capitalizedMethodName = "on" + aria.utils.String.capitalize(m);
+ if ((interceptor[capitalizedMethodName + "CallBegin"]
Fabio Crisci
piuccio added a note

Way too many ||. I'd prefer to have a method isInterceptable or something similar, and let the compiler optimize inlining. It would be readable

Simon Arbuckle Collaborator

Thanks for the feedback.

I will implement a utility method to contain the || but it will still be the same number of them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Simon Arbuckle simonarbuckle referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Simon Arbuckle simonarbuckle referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
divdavem divdavem referenced this pull request from a commit in divdavem/ariatemplates
Simon Arbuckle simonarbuckle refactor #270 Performance optimizations for flow controllers and inte…
…rceptors.
b134d52
divdavem
Collaborator

Integrated with b134d52

divdavem divdavem closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
166 src/aria/core/JsObject.js
View
@@ -18,11 +18,24 @@
var disposeTag = Aria.FRAMEWORK_PREFIX + 'isDisposed';
/**
- * Private method used to remove callbacks from a map of callbacks (either listeners or interceptors), associated to
- * a given scope and function (optional)
- * @param {Object} callbacksMap map of callbacks, which can be currently: obj._listeners or obj.__$interceptors
- * @param {String} name [mandatory] name in the map, may be the event name (if callbacksMap == _listeners) or the
- * interface name (if callbacksMap == __$interceptors)
+ * Private method to remove interceptors.
+ * @param {Object} allInterceptors obj.__$interceptors
+ * @param {String} name [mandatory] name interface name
+ * @param {Object} scope [optional] if specified, only interceptors with that scope will be removed
+ * @param {Function} fn [optional] if specified, only interceptors with that function will be removed
+ */
+ var __removeInterceptorCallback = function (allInterceptors, name, scope, fn) {
+ for (var i in allInterceptors[name]) {
+ if (allInterceptors[name].hasOwnProperty(i)) {
+ __removeCallback(allInterceptors[name], i, scope, fn);
+ }
+ }
+ };
+
+ /**
+ * Private method used to remove callbacks from a map of callbacks associated to a given scope and function
+ * @param {Object} callbacksMap map of callbacks, which can be currently: obj._listeners
+ * @param {String} name [mandatory] name in the map, may be the event name (if callbacksMap == _listeners)
* @param {Object} scope [optional] if specified, only callbacks with that scope will be removed
* @param {Function} fn [optional] if specified, only callbacks with that function will be removed
* @param {Object} src [optional] if the method is called from an interface wrapper, must be the reference of the
@@ -34,7 +47,9 @@
if (callbacksMap == null) {
return; // nothing to remove
}
+
var arr = callbacksMap[name];
+
if (arr) {
var length = arr.length, removeThis = false, newList = null, cb;
for (var i = 0; i < length; i++) {
@@ -75,13 +90,30 @@
};
/**
+ * Interceptor dispatch function.
+ * @param {Object} interc interceptor instance
+ * @param {Object} info interceptor parameters
+ */
+ var __callInterceptorMethod = function (info) {
+ var methodName = aria.utils.String.capitalize(info.method);
+ var fctRef = this["on" + methodName + info.step];
+ if (fctRef) {
+ return fctRef.call(this, info);
+ }
+ fctRef = this["on" + info.method + info.step];
+ if (fctRef) {
+ return fctRef.call(this, info);
+ }
+ };
+
+ /**
* Recursive method to call wrappers. This method should be called with "this" refering to the object whose method
* is called.
*/
var __callWrapper = function (args, commonInfo, interceptorIndex) {
if (interceptorIndex >= commonInfo.nbInterceptors) {
// end of recursion: call the real method:
- return this[commonInfo.method].apply(this, args)
+ return this[commonInfo.method].apply(this, args);
}
var interc = commonInfo.interceptors[interceptorIndex];
if (interc.removed) {
@@ -139,8 +171,7 @@
var __callbackWrapper = function (res, args) {
var interc = args.interc;
if (interc.removed) {
- // the interceptor was removed in the mean time, call the original
- // callback directly
+ // the interceptor was removed in the mean time, call the original callback directly
return this.$callback(args.origCb, res);
}
var info = args.info;
@@ -154,7 +185,63 @@
return info.returnValue;
}
return this.$callback(args.origCb, info.callbackResult);
- }
+ };
+
+ /**
+ * Determines if a method has been intercepted: the interceptor contains on[methodName]CallBegin,
+ * on[methodName]Callback, on[methodName]CallEnd.
+ * @param {String} methodName the method name that could be intercepted.
+ * @param {Object} interceptor contains an intercepting method for the methodName.
+ * @return {Boolean} true if method has been intercepted
+ */
+ var __hasBeenIntercepted = function (methodName, interceptor) {
+ var capitalizedMethodName = "on" + aria.utils.String.capitalize(methodName);
+ if ((interceptor[capitalizedMethodName + "CallBegin"] || interceptor[capitalizedMethodName + "Callback"] || interceptor[capitalizedMethodName
+ + "CallEnd"])
+ || (interceptor["on" + methodName + "CallBegin"] || interceptor["on" + methodName + "Callback"] || interceptor["on"
+ + methodName + "CallEnd"])) {
+ return true;
+ }
+ return false;
+ };
+
+ /**
+ * Adds an interceptor to all methods.
+ * @param {Object} interfaceMethods all methods for the interface
+ * @param {aria.core.JsObject.Callback} interceptor a callback which will receive notifications
+ * @return {Object} interceptedMethods
+ */
+ var __interceptCallback = function (interfaceMethods, interceptor, allInterceptors) {
+ var interceptedMethods = allInterceptors || {};
+ // for a callback, intercept all methods of an interface
+ for (var i in interfaceMethods) {
+ if (interfaceMethods.hasOwnProperty(i)) {
+ (interceptedMethods[i] || (interceptedMethods[i] = [])).push(interceptor);
+ }
+ }
+ return interceptedMethods;
+ };
+
+ /**
+ * Targets specific methods to be intercepted.
+ * @param {Object} interfaceMethods all methods for the interface
+ * @param {Object} interceptor an object/class which will receive notifications
+ * @return {Object} interceptedMethods
+ */
+ var __interceptObject = function (interfaceMethods, interceptor, allInterceptors) {
+ var interceptedMethods = allInterceptors || {};
+ // for a class object, intercept specific methods
+ var interceptorMethodBegin, interceptorMethodCallBack, interceptorMethodEnd;
+ for (var m in interfaceMethods) {
+ if (interfaceMethods.hasOwnProperty(m) && __hasBeenIntercepted(m, interceptor)) {
+ (interceptedMethods[m] || (interceptedMethods[m] = [])).push({
+ fn : __callInterceptorMethod,
+ scope : interceptor
+ });
+ }
+ }
+ return interceptedMethods;
+ };
/**
* @class aria.core.JsObject Base class from which derive all Js classes defined through Aria.classDefinition()
@@ -185,7 +272,7 @@
* @param {Object} sdef the superclass class definition
*/
$init : function (p, def, sdef) {
- p.$on = p.$addListeners // shortcut
+ p.$on = p.$addListeners; // shortcut
},
/**
@@ -251,8 +338,7 @@
* @param {Object} obj An optional object to be inspected in the logged message
*/
$logDebug : function (msg, msgArgs, obj) {
- // replaced by the true logging function when
- // aria.core.Log is loaded
+ // replaced by the true logging function when aria.core.Log is loaded
return "";
},
@@ -263,8 +349,7 @@
* @param {Object} obj An optional object to be inspected in the logged message
*/
$logInfo : function (msg, msgArgs, obj) {
- // replaced by the true logging function when
- // aria.core.Log is loaded
+ // replaced by the true logging function when aria.core.Log is loaded
return "";
},
@@ -275,8 +360,7 @@
* @param {Object} obj An optional object to be inspected in the logged message
*/
$logWarn : function (msg, msgArgs, obj) {
- // replaced by the true logging function when
- // aria.core.Log is loaded
+ // replaced by the true logging function when aria.core.Log is loaded
return "";
},
@@ -414,41 +498,39 @@
/**
* Add an interceptor callback on an interface specified by its classpath.
* @param {String} itf [mandatory] interface which will be intercepted
- * @param {aria.core.JsObject.Callback} cb callback which will receive notifications
+ * @param {Object|aria.core.JsObject.Callback} interceptor either a callback or an object/class which will
+ * receive notifications
*/
- $addInterceptor : function (itf, cb) {
+ $addInterceptor : function (itf, interceptor) {
// get the interface constructor:
var itfCstr = this.$interfaces[itf];
if (!itfCstr) {
this.$logError(this.INTERFACE_NOT_SUPPORTED, [itf, this.$classpath]);
return;
}
- cb = this.$normCallback(cb);
var allInterceptors = this.__$interceptors;
if (allInterceptors == null) {
allInterceptors = {};
this.__$interceptors = allInterceptors;
}
+ var interceptMethods = (aria.utils.Type.isCallback(interceptor))
+ ? __interceptCallback
+ : __interceptObject;
+
var itfs = itfCstr.prototype.$interfaces;
- // add the interceptor on all base interfaces of the
- // interface
for (var i in itfs) {
if (itfs.hasOwnProperty(i)) {
- var interceptors = allInterceptors[i];
- if (!interceptors) {
- allInterceptors[i] = [cb];
- } else {
- interceptors.push(cb);
- }
+ var interceptedMethods = interceptMethods(itfs[i].interfaceDefinition.$interface, interceptor, allInterceptors[i]);
+ allInterceptors[i] = interceptedMethods;
}
}
},
/**
- * Remove interceptor callbacks on an interface.
- * @param {String} interface [mandatory] interface which is intercepted
- * @param {Object} scope [optional] scope of the callbacks to remove
- * @param {Function} function [optional] function in the callbacks to remove
+ * Remove interceptor callbacks or interceptor objects on an interface.
+ * @param {String} itf [mandatory] interface which is intercepted
+ * @param {Object} scope [optional] scope of the callbacks/objects to remove
+ * @param {Function} fn [optional] function in the callbacks to remove
*/
$removeInterceptors : function (itf, scope, fn) {
var itfCstr = this.$interfaces[itf];
@@ -457,11 +539,10 @@
return;
}
var itfs = itfCstr.prototype.$interfaces;
- // also remove the interceptor on all base interfaces of
- // the interface
+ // also remove the interceptor on all base interfaces of the interface
for (var i in itfs) {
if (itfs.hasOwnProperty(i)) {
- __removeCallback(allInterceptors, i, scope, fn);
+ __removeInterceptorCallback(allInterceptors, i, scope, fn);
}
}
},
@@ -477,9 +558,9 @@
*/
$call : function (interfaceName, methodName, args, asyncCbParam) {
var interceptors;
- if (this.__$interceptors == null || (interceptors = this.__$interceptors[interfaceName]) == null) {
- // no interceptor for that interface: do not waste
- // time and call the method directly:
+ if (this.__$interceptors == null || this.__$interceptors[interfaceName] == null
+ || (interceptors = this.__$interceptors[interfaceName][methodName]) == null) {
+ // no interceptor for that interface: call the method directly:
return this[methodName].apply(this, args);
}
return __callWrapper.call(this, args, {
@@ -496,7 +577,6 @@
* following arguments should be provided:<br/>
*
* <pre>
- *
* fn: {Function} [mandatory] callback function
* scope: {Object} [mandatory] object on wich the callback will be called
* args: {Object} [optional] argument object that will be passed to the callback as 2nd argument (1st argument is the event object)
@@ -554,8 +634,7 @@
fn : lsn,
scope : defaultScope,
once : lstCfg[evt].listenOnce
- // we keep track of listeners which are meant to
- // be called just once
+ // we keep track of listeners which are meant to be called just once
};
} else {
// make a copy of lsn before changing it
@@ -564,8 +643,7 @@
scope : lsn.scope,
args : lsn.args,
once : lstCfg[evt].listenOnce
- // we keep track of listeners which are meant to
- // be called just once
+ // we keep track of listeners which are meant to be called just once
};
// lsn is an object as in 'start' or 'end' samples set default scope
if (!lsn.scope) {
@@ -616,7 +694,7 @@
var lsnRm = lstCfg[evt];
if (typeof(lsnRm) == 'function') {
if (defaultScope == null) {
- this.$logError(this.MISSING_SCOPE, evt)
+ this.$logError(this.MISSING_SCOPE, evt);
continue;
}
__removeCallback(this._listeners, evt, defaultScope, lsnRm, itfWrap);
@@ -625,7 +703,7 @@
lsnRm.scope = defaultScope;
}
if (lsnRm.scope == null) {
- this.$logError(this.MISSING_SCOPE, evt)
+ this.$logError(this.MISSING_SCOPE, evt);
continue;
}
__removeCallback(this._listeners, evt, lsnRm.scope, lsnRm.fn, itfWrap, lsnRm.firstOnly);
16 src/aria/templates/FlowCtrl.js
View
@@ -39,22 +39,6 @@ Aria.classDefinition({
$publicInterfaceName : 'aria.templates.IFlowCtrl',
/**
- * Interceptor dispatch function.
- * @param {Object} param interceptor parameters
- */
- interceptModuleCtrl : function (param) {
- var methodName = aria.utils.String.capitalize(param.method);
- var fctRef = this["on" + methodName + param.step];
- if (fctRef) {
- return fctRef.call(this, param);
- }
- fctRef = this["on" + param.method + param.step];
- if (fctRef) {
- return fctRef.call(this, param);
- }
- },
-
- /**
* Called when the flow controller is initialized, to set the module controller associated to this flow
* controller. Note that this is before the module controller init method has been called.
* @param {Object} moduleCtrl Public interface of the flow controller.
33 src/aria/templates/ModuleCtrlFactory.js
View
@@ -73,7 +73,7 @@
};
// define here some methods for JSLint.
- var createInstanceAndCheckFlow, createFlowCtrlAndCustomModules, attachListenersAndInit, callFinalCallback, loadSubModules;
+ var createModuleCtrl, createInstanceAndCheckFlow, createFlowCtrlAndCustomModules, attachListenersAndInit, callFinalCallback, getModulePrivateInfo, getModulePrivateInfoMethodRes, getModulePrivateInfoWithCheck, putElementAtRefPath, putSubModuleAtRefPath, subModuleLoaded, loadSubModules, reloadModuleCtrlCb;
/**
* Load a module controller. First check if module is available.
@@ -97,7 +97,7 @@
* </ul>
* @private
*/
- var createModuleCtrl = function (args) {
+ createModuleCtrl = function (args) {
var moduleCtrlConstr = Aria.getClassRef(args.desc.classpath);
if (!moduleCtrlConstr) {
// try to load the module controller
@@ -125,7 +125,7 @@
* @param {Object} args loadModuleCtrl state information (see createModuleCtrl for more information)
* @private
*/
- var createInstanceAndCheckFlow = function (args) {
+ createInstanceAndCheckFlow = function (args) {
try {
var moduleClasspath = args.desc.classpath;
var moduleCtrlConstr = args.moduleCtrlConstr;
@@ -189,7 +189,7 @@
* @param {Object} args loadModuleCtrl state information (see createModuleCtrl for more information)
* @private
*/
- var createFlowCtrlAndCustomModules = function (args) {
+ createFlowCtrlAndCustomModules = function (args) {
try {
var moduleCtrlPrivate = args.moduleCtrlPrivate;
@@ -209,10 +209,7 @@
flowCtrlPrivate = new args.flowCtrlConstr();
flowCtrlPrivate.setModuleCtrl(moduleCtrl);
- moduleCtrlPrivate.$addInterceptor(moduleCtrlPrivate.$publicInterfaceName, {
- fn : flowCtrlPrivate.interceptModuleCtrl,
- scope : flowCtrlPrivate
- });
+ moduleCtrlPrivate.$addInterceptor(moduleCtrlPrivate.$publicInterfaceName, flowCtrlPrivate);
flowCtrl = flowCtrlPrivate.$publicInterface();
}
@@ -267,7 +264,7 @@
* @param {Object} args loadModuleCtrl state information (see createModuleCtrl for more information)
* @private
*/
- var attachListenersAndInit = function (unused, args) {
+ attachListenersAndInit = function (unused, args) {
try {
var registerListeners = args.registerListeners;
if (registerListeners) {
@@ -300,7 +297,7 @@
* @param {Object} args loadModuleCtrl state information (see createModuleCtrl for more information)
* @private
*/
- var callFinalCallback = function (unused, args) {
+ callFinalCallback = function (unused, args) {
this.$callback(args.cb, args.res);
};
@@ -309,7 +306,7 @@
* @param {Object} moduleCtrl module controller public interface wrapper or whole object
* @private
*/
- var getModulePrivateInfo = function (moduleCtrl) {
+ getModulePrivateInfo = function (moduleCtrl) {
var k = moduleCtrl[MODULECTRL_ID_PROPERTY];
var res = modulesPrivateInfo[k];
if (!res) {
@@ -320,7 +317,7 @@
}
return res;
};
- var getModulePrivateInfoMethodRes = getModulePrivateInfo;
+ getModulePrivateInfoMethodRes = getModulePrivateInfo;
/**
* Return module private information linked to the module controller passed as a parameter. The parameter is checked
@@ -328,7 +325,7 @@
* @param {Object} moduleCtrlPrivate module controller whole object
* @private
*/
- var getModulePrivateInfoWithCheck = function (moduleCtrlPrivate, functionName) {
+ getModulePrivateInfoWithCheck = function (moduleCtrlPrivate, functionName) {
var res = getModulePrivateInfo(moduleCtrlPrivate);
if (!res) {
return null;
@@ -352,7 +349,7 @@
* @param {Number} arrayIndex If specified, put the element in an array at the specified path
* @return {Boolean} true if element already exists
*/
- var putElementAtRefPath = function (targetObject, element, pathArray, arrayIndex) {
+ putElementAtRefPath = function (targetObject, element, pathArray, arrayIndex) {
// if refpath contains multiple intermediate objects, let's create them
var size = pathArray.length, name;
for (var i = 0; i < size - 1; i++) {
@@ -396,7 +393,7 @@
* @param {Boolean} customModule whether the sub-module is a custom module
* @private
*/
- var putSubModuleAtRefPath = function (parentModule, subModuleDesc, subModuleCtrl, customModule) {
+ putSubModuleAtRefPath = function (parentModule, subModuleDesc, subModuleCtrl, customModule) {
var ref = subModuleDesc.refpath;
var parentPrivate = parentModule.moduleCtrlPrivate;
var parentData = parentModule.moduleCtrl.getData();
@@ -450,7 +447,7 @@
* @param {Object} args
* @private
*/
- var subModuleLoaded = function (subModule, args) {
+ subModuleLoaded = function (subModule, args) {
var common = args.common;
var subModuleDesc = args.subModuleDesc;
var subModuleCtrl = subModule.moduleCtrl;
@@ -488,7 +485,7 @@
* one of these classpaths, loading this sub-module will fail.
* @private
*/
- var loadSubModules = function (parentModuleInfo, subModulesDescArray, cb, customModules, recursionCheck) {
+ loadSubModules = function (parentModuleInfo, subModulesDescArray, cb, customModules, recursionCheck) {
var subModulesDescArrayLength = subModulesDescArray.length;
if (subModulesDescArrayLength === 0) {
this.$callback(cb, {
@@ -589,7 +586,7 @@
* @param {Object} result of sub-module load. Contains a subModules array.
* @paran {Object} args object containing objectLoading, oldModuleCtrl, oldFlowCtrl and callback
*/
- var reloadModuleCtrlCb = function (res, args) {
+ reloadModuleCtrlCb = function (res, args) {
var objectLoading = args.objectLoading;
var newModuleCtrl = res.subModules[0];
if (newModuleCtrl) {
19 src/aria/utils/Type.js
View
@@ -92,7 +92,8 @@ Aria.classDefinition({
// http://www.quirksmode.org/dom/w3c_core.html#nodeinformation
if (object) {
var nodeName = object.nodeName;
- return object === Aria.$window || aria.utils.Type.isString(nodeName) || object === Aria.$frameworkWindow;
+ return object === Aria.$window || aria.utils.Type.isString(nodeName)
+ || object === Aria.$frameworkWindow;
} else {
return false;
}
@@ -145,6 +146,22 @@ Aria.classDefinition({
*/
isContainer : function (value) {
return (this.isObject(value) || this.isArray(value)) && !(value instanceof aria.core.JsObject);
+ },
+
+ /**
+ * Check if the object is a callback
+ * @param {Object} value
+ * @return {Boolean}
+ */
+ isCallback : function (value) {
+ if (value.$Callback) {
+ return true;
+ }
+ if (value.$classpath) {
+ return false;
+ }
+ var normCb = this.$normCallback(value);
+ return typeof(normCb.fn) == "function";
}
}
});
134 test/aria/core/JsObjectTest.js
View
@@ -17,7 +17,7 @@ Aria.classDefinition({
$classpath : 'test.aria.core.JsObjectTest',
$extends : 'aria.jsunit.TestCase',
$dependencies : ['test.aria.core.test.ClassA', 'test.aria.core.test.ClassB', 'test.aria.core.test.TestClass',
- 'test.aria.core.test.ImplementInterface1', 'test.aria.core.test.Interface1'],
+ 'test.aria.core.test.ImplementInterface1', 'test.aria.core.test.Interface1', 'test.aria.core.test.MyFlow'],
$constructor : function () {
this.$TestCase.constructor.call(this);
},
@@ -27,7 +27,7 @@ Aria.classDefinition({
this._oldAlert = Aria.$window.alert;
Aria.$window.alert = function (msg) {
that._myMethod.call(that, msg);
- }
+ };
},
tearDown : function () {
@@ -42,11 +42,11 @@ Aria.classDefinition({
* Test event definition on a base class
*/
testEventsDefinition1 : function () {
- var ca = new test.aria.core.test.ClassA()
+ var ca = new test.aria.core.test.ClassA();
- this.assertTrue(ca.$events["start"] != null)
- this.assertTrue(ca.$events["end"].properties.endCount != null)
- this.assertTrue(ca.$events["begin"] == null)
+ this.assertTrue(ca.$events["start"] != null);
+ this.assertTrue(ca.$events["end"].properties.endCount != null);
+ this.assertTrue(ca.$events["begin"] == null);
ca.$dispose(); // call the destructor (mandatory when discarding an object)
},
@@ -55,11 +55,11 @@ Aria.classDefinition({
* Test event defintion on a sub-class
*/
testEventsDefinition2 : function () {
- var cb = new test.aria.core.test.ClassB()
+ var cb = new test.aria.core.test.ClassB();
- this.assertTrue(cb.$events["start"] != null)
- this.assertTrue(cb.$events["end"].properties.endCount != null)
- this.assertTrue(cb.$events["begin"] != null)
+ this.assertTrue(cb.$events["start"] != null);
+ this.assertTrue(cb.$events["end"].properties.endCount != null);
+ this.assertTrue(cb.$events["begin"] != null);
cb.$dispose(); // call the destructor (mandatory when discarding an object)
},
@@ -68,13 +68,13 @@ Aria.classDefinition({
* Test the $assert function
*/
testAssert : function () {
- this.assertTrue(this.$assert(1, true))
- this.assertFalse(this.$assert(2, false))
+ this.assertTrue(this.$assert(1, true));
+ this.assertFalse(this.$assert(2, false));
this.assertErrorInLogs(this.ASSERT_FAILURE);
- this.assertTrue(this.$assert(3, {}))
- this.assertFalse(this.$assert(4, null))
+ this.assertTrue(this.$assert(3, {}));
+ this.assertFalse(this.$assert(4, null));
this.assertErrorInLogs(this.ASSERT_FAILURE);
- this.assertFalse(this.$assert())
+ this.assertFalse(this.$assert());
this.assertErrorInLogs(this.ASSERT_FAILURE);
},
@@ -112,13 +112,113 @@ Aria.classDefinition({
this.assertTrue(results == "return value intercepted");
obj.$removeInterceptors('');
- var results = obj.$interface('test.aria.core.test.Interface1').search('a', 'b');
+ results = obj.$interface('test.aria.core.test.Interface1').search('a', 'b');
this.assertTrue(results == "return value intercepted");
obj.$removeInterceptors('test.aria.core.test.Interface1');
- var results = obj.search("a", "b");
+ results = obj.$interface('test.aria.core.test.Interface1').search('a', 'b');
this.assertTrue(results == "searchResult");
obj.$dispose();
+ },
+
+ testAddInterceptedMethods : function () {
+ var obj = Aria.getClassInstance('test.aria.core.test.ImplementInterface1');
+ var myInterceptor = Aria.getClassInstance('test.aria.core.test.MyFlow');
+ var interceptedMethodsCount = 0;
+
+ // adding an interceptor from a class object and not a callback object
+ obj.$addInterceptor('test.aria.core.test.Interface1', myInterceptor);
+
+ // test interceptor has been added for the correct method
+ this.assertTrue(obj.__$interceptors['test.aria.core.test.Interface1']['search'][0]['scope']['$classpath'] === myInterceptor.$classpath);
+
+ // test that only specific methods defined in the interceptor have been intercepted and not all the methods
+ // of the interface
+ interceptedMethodsCount = aria.utils.Object.keys(obj.__$interceptors['test.aria.core.test.Interface1']).length;
+ this.assertTrue(interceptedMethodsCount === 2);
+
+ obj.$removeInterceptors('test.aria.core.test.Interface1');
+ myInterceptor.$dispose();
+ obj.$dispose();
+ },
+
+ testRemoveInterceptedMethods : function () {
+ var obj = Aria.getClassInstance('test.aria.core.test.ImplementInterface1');
+ var myInterceptor = Aria.getClassInstance('test.aria.core.test.MyFlow');
+
+ // adding an interceptor from a class object and not a callback object
+ obj.$addInterceptor('test.aria.core.test.Interface1', myInterceptor);
+
+ // test interceptor has been added for the correct method
+ this.assertTrue(obj.__$interceptors['test.aria.core.test.Interface1']['search'][0]['scope']['$classpath'] === myInterceptor.$classpath);
+
+ // test interceptor has been removed
+ obj.$removeInterceptors('test.aria.core.test.Interface1');
+ this.assertTrue(aria.utils.Object.isEmpty(obj.__$interceptors['test.aria.core.test.Interface1']));
+ myInterceptor.$dispose();
+ obj.$dispose();
+ },
+
+ testCallInterceptedMethods : function () {
+ var obj = Aria.getClassInstance('test.aria.core.test.ImplementInterface1');
+ var myInterceptor = Aria.getClassInstance('test.aria.core.test.MyFlow');
+
+ // adding an interceptor from a class object and not a callback object
+ obj.$addInterceptor('test.aria.core.test.Interface1', myInterceptor);
+
+ var results = obj.$interface('test.aria.core.test.Interface1').search();
+ this.assertTrue(results == "intercepted by onSearchCallBegin");
+
+ results = obj.$interface('test.aria.core.test.Interface1').reset();
+ this.assertTrue(results == "intercepted by onResetCallEnd");
+
+ // test interceptor has been removed
+ obj.$removeInterceptors('test.aria.core.test.Interface1');
+ this.assertTrue(aria.utils.Object.isEmpty(obj.__$interceptors['test.aria.core.test.Interface1']));
+ myInterceptor.$dispose();
+ results = obj.$interface('test.aria.core.test.Interface1').reset();
+ this.assertTrue(results == null);
+ obj.$dispose();
+ },
+
+ testMultipleInterceptorsForSameMethod : function () {
+ var obj = Aria.getClassInstance('test.aria.core.test.ImplementInterface1');
+ var myInterceptor1 = function (param) {
+ param.returnValue = (!param.returnValue || typeof param.returnValue === "string") ? [] : param.returnValue;
+ param.returnValue.push("return value intercepted by myInterceptor1");
+ };
+
+ var myInterceptor2 = function (param) {
+ param.returnValue = (!param.returnValue || typeof param.returnValue === "string")
+ ? []
+ : param.returnValue;
+ param.returnValue.push("return value intercepted by myInterceptor2");
+ };
+
+ obj.$addInterceptor('test.aria.core.test.Interface1', myInterceptor1);
+ obj.$addInterceptor('test.aria.core.test.Interface1', myInterceptor2);
+ this.assertTrue(obj.__$interceptors['test.aria.core.test.Interface1']['search'].length === 2);
+
+ var results = obj.$interface('test.aria.core.test.Interface1').search();
+
+ /*
+ * The order in which the interceptor methods should be called is as follows:
+ * CallBegin: interceptor callbacks are called in the order in which they are registered with $addInterceptor
+ * CallEnd, Callback: they are called in the reverse order
+ * For this test interceptors are called in the following order:
+ * myInterceptor1
+ * myInterceptor2
+ * original interface method
+ * myInterceptor2
+ * myInterceptor1
+ */
+ // Note the original interface method changes the return value so we only detect for the CallEnd return
+ // values
+ this.assertTrue(results[0] == "return value intercepted by myInterceptor2");
+ this.assertTrue(results[1] == "return value intercepted by myInterceptor1");
+
+ obj.$removeInterceptors('test.aria.core.test.Interface1');
+ obj.$dispose();
}
}
});
19 test/aria/core/test/MyFlow.js
View
@@ -0,0 +1,19 @@
+Aria.classDefinition({
+ $classpath : "test.aria.core.test.MyFlow",
+ $extends : "aria.templates.FlowCtrl",
+ $constructor : function () {
+ this.$FlowCtrl.constructor.call(this);
+ },
+ $prototype : {
+ onSearchCallBegin : function (info) {
+ info.returnValue = 'intercepted by onSearchCallBegin';
+ info.cancelDefault = true;
+ return info;
+ },
+
+ onResetCallEnd : function (info) {
+ info.returnValue = 'intercepted by onResetCallEnd';
+ return info;
+ }
+ }
+});
290 test/aria/templates/FlowCtrlTest.js
View
@@ -17,149 +17,149 @@
* Test case for flow controllers.
*/
Aria.classDefinition({
- $classpath : 'test.aria.templates.FlowCtrlTest',
- $extends : 'aria.jsunit.TestCase',
- $dependencies : ['aria.templates.ModuleCtrlFactory'],
- $constructor : function () {
- this.$TestCase.constructor.call(this);
-
- // track calls of flow methods
- this.flowMethodsCalled = {};
-
- // this.defaultTestTimeout = 2000;
- },
- $prototype : {
- /**
- * Creates a module controller. A callback is provided to initArgs. This method will be stored in the flow and
- * called on each flow event.
- */
- testAsyncCreatingFlowCtrl : function () {
- // creates a module, does not call its init method
- aria.templates.ModuleCtrlFactory.createModuleCtrl({
- classpath : "test.aria.templates.test.SampleModuleCtrl"
- }, {
- fn : this._moduleCtrlCreated,
- scope : this
- }, true);
- },
-
- /**
- * Callback called on each flow event
- * @param {Object} res
- */
- _flowCtrlCb : function (res) {
- this.assertTrue(res.method == "on" + res.param.method + res.param.step);
- this.assertTrue(!this.flowMethodsCalled[res.method], "this method should not have been called twice.");
- this.flowMethodsCalled[res.method] = true;
- },
- /**
- * Callback called on each flow event
- * @param {Object} res
- */
- _flowCtrlSubmitCb : function (res) {
- var methodName = aria.utils.String.capitalize(res.param.method);
- this.assertTrue(!this.flowMethodsCalled[res.method], "this method should not have been called twice.");
- this.flowMethodsCalled[res.method] = true;
- },
-
- /**
- * Check the content of the callback when creating a module controller
- * @protected
- * @param {Object} args
- */
- _moduleCtrlCreated : function (args) {
- this.assertTrue(!args.error, "an error happened will creating the module controller");
-
- var moduleCtrl = args.moduleCtrl;
- var moduleCtrlPrivate = args.moduleCtrlPrivate;
-
- this.assertTrue(!!moduleCtrl, "Missing module controller");
- this.assertTrue(moduleCtrl === moduleCtrlPrivate.$publicInterface(), "public and private module controllers does not match");
-
- // call for the init : this should trigger the flow
- moduleCtrl.init({
- "flow:testCallback" : {
- scope : this,
- fn : this._flowCtrlCb
- },
- delay : 50
- }, {
- fn : this._initCallback,
- scope : this
- });
-
- this.assertTrue(this.flowMethodsCalled.oninitCallBegin, "oninitCallBegin was not called");
- this.assertTrue(this.flowMethodsCalled.oninitCallEnd, "oninitCallEnd was not called");
-
- aria.core.Timer.addCallback({
- fn : this._afterModuleInitCallback,
- scope : this,
- delay : 100,
- args : moduleCtrlPrivate
- });
-
- moduleCtrl.submit({
- "flow:testCallback" : {
- scope : this,
- fn : this._flowCtrlSubmitCb
- },
- delay : 50
- }, {
- fn : this._initCallback,
- scope : this
- });
-
- },
-
- /**
- * Init callback. Set a flag to be checked later
- * @private
- */
- _initCallback : function () {
- this.initCalled = true;
- },
-
- /**
- * Called after the init, to check that asynchronous callback flow event has been raised\
- * @param {Object} moduleCtrl
- * @protected
- */
- _afterModuleInitCallback : function (moduleCtrlPrivate) {
- this.assertTrue(this.initCalled, "init callback was not called");
- this.assertTrue(this.flowMethodsCalled.oninitCallback, "oninitCallback was not called");
- moduleCtrlPrivate.$dispose();
- this.notifyTestEnd("testAsyncCreatingFlowCtrl");
- },
-
- /**
- * Test module creation with a specific flow
- */
- testAsyncSpecificFlow : function () {
- // creates a module. The special flow is given to the contructor of the sample module
- aria.templates.ModuleCtrlFactory.createModuleCtrl({
- classpath : "test.aria.templates.test.SampleModuleCtrl",
- initArgs : {
- test : this
- },
- constructorArgs : {
- flowController : "test.aria.templates.test.SampleModuleSpecialCtrlFlow"
- }
- }, {
- fn : this._moduleCtrlSpecialFlowCreated,
- scope : this
- });
- },
-
- /**
- * Check that the special flag as been set to true on init
- * @protected
- * @param {Object} args
- */
- _moduleCtrlSpecialFlowCreated : function (args) {
- this.assertTrue(this.special, "Special flow is not used");
- args.moduleCtrlPrivate.$dispose();
- this.notifyTestEnd("testAsyncSpecificFlow");
- }
-
- }
+ $classpath : 'test.aria.templates.FlowCtrlTest',
+ $extends : 'aria.jsunit.TestCase',
+ $dependencies : ['aria.templates.ModuleCtrlFactory'],
+ $constructor : function () {
+ this.$TestCase.constructor.call(this);
+
+ // track calls of flow methods
+ this.flowMethodsCalled = {};
+
+ // this.defaultTestTimeout = 2000;
+ },
+ $prototype : {
+ /**
+ * Creates a module controller. A callback is provided to initArgs. This method will be stored in the flow and
+ * called on each flow event.
+ */
+ testAsyncCreatingFlowCtrl : function () {
+ // creates a module, does not call its init method
+ aria.templates.ModuleCtrlFactory.createModuleCtrl({
+ classpath : "test.aria.templates.test.SampleModuleCtrl"
+ }, {
+ fn : this._moduleCtrlCreated,
+ scope : this
+ }, true);
+ },
+
+ /**
+ * Callback called on each flow event
+ * @param {Object} res
+ */
+ _flowCtrlCb : function (res) {
+ this.assertTrue(res.method == "on" + res.param.method + res.param.step);
+ this.assertTrue(!this.flowMethodsCalled[res.method], "this method should not have been called twice.");
+ this.flowMethodsCalled[res.method] = true;
+ },
+ /**
+ * Callback called on each flow event
+ * @param {Object} res
+ */
+ _flowCtrlSubmitCb : function (res) {
+ var methodName = aria.utils.String.capitalize(res.param.method);
+ this.assertTrue(!this.flowMethodsCalled[res.method], "this method should not have been called twice.");
+ this.flowMethodsCalled[res.method] = true;
+ },
+
+ /**
+ * Check the content of the callback when creating a module controller
+ * @protected
+ * @param {Object} args
+ */
+ _moduleCtrlCreated : function (args) {
+ this.assertTrue(!args.error, "an error happened will creating the module controller");
+
+ var moduleCtrl = args.moduleCtrl;
+ var moduleCtrlPrivate = args.moduleCtrlPrivate;
+
+ this.assertTrue(!!moduleCtrl, "Missing module controller");
+ this.assertTrue(moduleCtrl === moduleCtrlPrivate.$publicInterface(), "public and private module controllers does not match");
+
+ // call for the init : this should trigger the flow
+ moduleCtrl.init({
+ "flow:testCallback" : {
+ scope : this,
+ fn : this._flowCtrlCb
+ },
+ delay : 50
+ }, {
+ fn : this._initCallback,
+ scope : this
+ });
+
+ this.assertTrue(this.flowMethodsCalled.oninitCallBegin, "oninitCallBegin was not called");
+ this.assertTrue(this.flowMethodsCalled.oninitCallEnd, "oninitCallEnd was not called");
+
+ aria.core.Timer.addCallback({
+ fn : this._afterModuleInitCallback,
+ scope : this,
+ delay : 100,
+ args : moduleCtrlPrivate
+ });
+
+ moduleCtrl.submit({
+ "flow:testCallback" : {
+ scope : this,
+ fn : this._flowCtrlSubmitCb
+ },
+ delay : 50
+ }, {
+ fn : this._initCallback,
+ scope : this
+ });
+
+ },
+
+ /**
+ * Init callback. Set a flag to be checked later
+ * @private
+ */
+ _initCallback : function () {
+ this.initCalled = true;
+ },
+
+ /**
+ * Called after the init, to check that asynchronous callback flow event has been raised\
+ * @param {Object} moduleCtrl
+ * @protected
+ */
+ _afterModuleInitCallback : function (moduleCtrlPrivate) {
+ this.assertTrue(this.initCalled, "init callback was not called");
+ this.assertTrue(this.flowMethodsCalled.oninitCallback, "oninitCallback was not called");
+ moduleCtrlPrivate.$dispose();
+ this.notifyTestEnd("testAsyncCreatingFlowCtrl");
+ },
+
+ /**
+ * Test module creation with a specific flow
+ */
+ testAsyncSpecificFlow : function () {
+ // creates a module. The special flow is given to the contructor of the sample module
+ aria.templates.ModuleCtrlFactory.createModuleCtrl({
+ classpath : "test.aria.templates.test.SampleModuleCtrl",
+ initArgs : {
+ test : this
+ },
+ constructorArgs : {
+ flowController : "test.aria.templates.test.SampleModuleSpecialCtrlFlow"
+ }
+ }, {
+ fn : this._moduleCtrlSpecialFlowCreated,
+ scope : this
+ });
+ },
+
+ /**
+ * Check that the special flag as been set to true on init
+ * @protected
+ * @param {Object} args
+ */
+ _moduleCtrlSpecialFlowCreated : function (args) {
+ this.assertTrue(this.special, "Special flow is not used");
+ args.moduleCtrlPrivate.$dispose();
+ this.notifyTestEnd("testAsyncSpecificFlow");
+ }
+
+ }
});
44 test/aria/utils/TypeTest.js
View
@@ -19,6 +19,7 @@
Aria.classDefinition({
$classpath : "test.aria.utils.TypeTest",
$extends : "aria.jsunit.TestCase",
+ $dependencies : ["aria.utils.Callback"],
$prototype : {
/**
@@ -125,6 +126,47 @@ Aria.classDefinition({
this.assertTrue(typeUtils.isHTMLElement(Aria.$window.document.body.firstChild));
// this.assertTrue(typeUtils.isHTMLElement(document.getElementsByTagName("*")));
- }
+ },
+
+ testIsCallback : function () {
+ var typeUtils = aria.utils.Type;
+
+ // Types of Callbacks:
+ this.assertTrue(typeUtils.isCallback({
+ fn : this._myTestMethod,
+ scope : this
+ }));
+
+ this.assertTrue(typeUtils.isCallback({
+ fn : "_myTestMethod",
+ scope : this
+ }));
+
+ this.assertTrue(typeUtils.isCallback(function () {}));
+
+ var myCallback = new aria.utils.Callback({
+ fn : this._myTestMethod,
+ scope : this
+ })
+
+ this.assertTrue(typeUtils.isCallback(myCallback));
+
+ myCallback.$dispose();
+
+ // NOT callbacks:
+ this.assertFalse(typeUtils.isCallback({
+ $classpath : "test.aria.utils.TypeTest",
+ fn : function () {},
+ scope : this
+ }));
+
+ this.assertFalse(typeUtils.isCallback({
+ $classpath : "test.aria.utils.TypeTest",
+ fn : "_myTestMethod",
+ scope : this
+ }));
+ },
+
+ _myTestMethod : function () {}
}
});
Something went wrong with that request. Please try again.