UNPKG

dojox

Version:

Dojo eXtensions, a rollup of many useful sub-projects and varying states of maturity – from very stable and robust, to alpha and experimental. See individual projects contain README files for details.

479 lines (448 loc) 16.8 kB
<html> <head> <title>aspects</title> <style type="text/css"> @import "../../../dojo/resources/dojo.css"; </style> <script type="text/javascript" src="../../../dojo/dojo.js" data-dojo-config="isDebug:true"></script> <script type="text/javascript" src="../aspect.js"></script> <script type="text/javascript" src="../aspect/cflow.js"></script> <script type="text/javascript" src="../aspect/tracer.js"></script> <script type="text/javascript" src="../aspect/timer.js"></script> <script type="text/javascript" src="../aspect/profiler.js"></script> <script type="text/javascript" src="../aspect/counter.js"></script> <script type="text/javascript" src="../aspect/memoizer.js"></script> <script type="text/javascript" src="../aspect/memoizerGuard.js"></script> <script type="text/javascript"> dojo.require("dojox.lang.aspect"); dojo.require("dojox.lang.aspect.cflow"); dojo.require("dojox.lang.aspect.tracer"); dojo.require("dojox.lang.aspect.timer"); dojo.require("dojox.lang.aspect.profiler"); dojo.require("dojox.lang.aspect.counter"); dojo.require("dojox.lang.aspect.memoizer"); dojo.require("dojox.lang.aspect.memoizerGuard"); dojo.require("dojo.string"); dojo.require("dojox.lang.functional.listcomp"); var test = function(){ // This is a test class, don't program like this! var Rect = function(){ this.x = this.y = this.width = this.height = 0; }; dojo.extend(Rect, { // getters getX: function(){ return this.x; }, getY: function(){ return this.y; }, getWidth: function(){ return this.width; }, getHeight: function(){ return this.height; }, // setters setX: function(val){ this.x = val; }, setY: function(val){ this.y = val; }, setWidth: function(val){ this.width = val; }, setHeight: function(val){ this.height = val; }, // special methods getPerimeter: function(){ return 2 * (this.width + this.height); }, getArea: function(){ return this.width * this.height; }, getCorner: function(){ return {x: this.x + this.width, y: this.y + this.height}; }, move: function(x, y){ this.x = x; this.y = y; }, makeSquare: function(l){ this.width = this.height = l; }, scale: function(s){ this.width *= s; this.height *= s; }, pointInside: function(x, y){ return this.x <= x && x < (this.x + this.width) && this.y <= y && y < (this.y + this.height); }, assertSquare: function(){ if(this.getHeight() != this.getWidth()){ throw new Error("NOT A SQUARE!"); } } }); var aop = dojox.lang.aspect, df = dojox.lang.functional; // our simple advices var TraceArguments = { before: function(/*arguments*/){ var joinPoint = aop.getContext().joinPoint, args = Array.prototype.join.call(arguments, ", "); console.log("=> " + joinPoint.targetName + "(" + args + ")"); } }; var TraceReturns = { afterReturning: function(retVal){ var joinPoint = aop.getContext().joinPoint; console.log("<= " + joinPoint.targetName + " returns " + retVal); }, afterThrowing: function(excp){ var joinPoint = aop.getContext().joinPoint; console.log("<= " + joinPoint.targetName + " throws: " + excp); } }; console.log("create rect1 and call its methods without aspects."); var rect1 = new Rect; rect1.move(100, 100); rect1.makeSquare(200); rect1.pointInside(150, 250); console.log("perimeter: " + rect1.getPerimeter()); console.log("area: " + rect1.getArea()); console.log("================================="); console.log("create rect2, attach advices to the instance, and repeat..."); var rect2 = new Rect; aop.advise(rect2, /^get/, TraceReturns); aop.advise(rect2, [/^set/, "move", "makeSquare"], TraceArguments); aop.advise(rect2, "pointInside", [TraceReturns, TraceArguments]); rect2.move(100, 100); rect2.makeSquare(200); rect2.pointInside(150, 250); console.log("perimeter: " + rect2.getPerimeter()); console.log("area: " + rect2.getArea()); console.log("================================="); console.log("attach advices to the Rect class, and repeat with rect1..."); var h1 = aop.advise(Rect, /^get/, TraceReturns); var h2 = aop.advise(Rect, [/^set/, "move", "makeSquare"], TraceArguments); var h3 = aop.advise(Rect, "pointInside", [TraceReturns, TraceArguments]); rect1.move(100, 100); rect1.makeSquare(200); rect1.pointInside(150, 250); console.log("perimeter: " + rect1.getPerimeter()); console.log("area: " + rect1.getArea()); console.log("================================="); console.log("remove advices for getters and setters from the class, and repeat with rect1..."); aop.unadvise(h1); aop.unadvise(h2); rect1.move(100, 100); rect1.makeSquare(200); rect1.pointInside(150, 250); console.log("perimeter: " + rect1.getPerimeter()); console.log("area: " + rect1.getArea()); console.log("================================="); console.log("repeat with rect2..."); rect2.move(100, 100); rect2.makeSquare(200); rect2.pointInside(150, 250); console.log("perimeter: " + rect2.getPerimeter()); console.log("area: " + rect2.getArea()); console.log("================================="); console.log("test rect2 with throwing an exception..."); aop.advise(rect2, /^assert/, TraceReturns); try{ rect2.assertSquare(); rect2.width = 300; // triggering exception rect2.assertSquare(); }catch(e){ // squelch } console.log("================================="); // more complex dynamic tracing advice var Trace = function(context){ this.name = context.joinPoint.targetName; }; dojo.extend(Trace, { before: function(/*arguments*/){ this.args = Array.prototype.join.call(arguments, ", "); }, afterReturning: function(retVal){ var buf = "-- " + this.name + "(" + this.args + ")"; if(typeof retVal == "undefined"){ // procedure without a return value console.log(buf); }else{ // function with returned value console.log(buf + " returns: " + retVal); } }, afterThrowing: function(excp){ console.log("-- " + this.name + "(" + this.args + ") throws: " + excp); } }); // remove tracing for pointInside aop.unadvise(h3); console.log("create rect3, and trace all its methods..."); var rect3 = new Rect; aop.advise(rect3, /^\S/, Trace); rect3.move(100, 100); rect3.makeSquare(200); rect3.pointInside(150, 250); console.log("perimeter: " + rect3.getPerimeter()); console.log("area: " + rect3.getArea()); rect3.assertSquare(); console.log("================================="); var TraceAll = function(context, id){ this.name = context.joinPoint.targetName; this.prefix = dojo.string.pad("", context.depth * 2, "--", true) + "-- #" + (id || 1); }; dojo.extend(TraceAll, { before: function(/*arguments*/){ var args = Array.prototype.join.call(arguments, ", "); console.log(this.prefix + " => before " + this.name + "(" + args + ")"); }, around: function(/*arguments*/){ var args = Array.prototype.join.call(arguments, ", "); console.log(this.prefix + " => around " + this.name + "(" + args + ")"); var retVal = aop.proceed.apply(null, arguments); console.log(this.prefix + " <= around " + this.name + " returns " + retVal); return retVal; // should return a value, if the target returns a value }, afterReturning: function(retVal){ console.log(this.prefix + " <= afterR " + this.name + " returns " + retVal); }, afterThrowing: function(excp){ console.log(this.prefix + " <= afterT " + this.name + " throws: " + excp); }, after: function(){ console.log(this.prefix + " <= after " + this.name); } }); console.log("create rect4, and attach two tracer to all its methods..."); var rect4 = new Rect; aop.advise(rect4, /^\S/, [ function(context){ return new TraceAll(context, 1); }, function(context){ return new TraceAll(context, 2); } ]); rect4.move(100, 100); rect4.makeSquare(200); rect4.pointInside(150, 250); console.log("perimeter: " + rect4.getPerimeter()); console.log("area: " + rect4.getArea()); try{ rect4.assertSquare(); rect4.width = 300; // triggering exception rect4.assertSquare(); }catch(e){ // squelch } console.log("================================="); var TraceTopLevel = function(context){ this.name = context.joinPoint.targetName; }; dojo.extend(TraceTopLevel, { before: function(/*arguments*/){ var args = Array.prototype.join.call(arguments, ", "); console.log("=> " + this.name + "(" + args + ")"); }, afterReturning: function(retVal){ console.log("<= " + this.name + " returns: " + retVal); }, afterThrowing: function(excp){ console.log("<= " + this.name + " throws: " + excp); } }); console.log("create rect5, and track only top-level calls..."); var rect5 = new Rect; aop.advise(rect5, /^\S/, function(context){ return aop.cflow(context.instance) ? // the advised object {} : // do nothing new TraceTopLevel(context); // log top level } ); rect5.move(100, 100); rect5.makeSquare(200); rect5.pointInside(150, 250); console.log("perimeter: " + rect5.getPerimeter()); console.log("area: " + rect5.getArea()); try{ rect5.assertSquare(); rect5.width = 300; // triggering exception rect5.assertSquare(); }catch(e){ // squelch } console.log("================================="); var log = function(){ // log the rect1pointInside state var dispatcher = "native"; if(rect1.pointInside.target){ if(rect1.pointInside.advices){ dispatcher = "dojox.lang.aspect"; }else if(rect1.pointInside._listeners){ dispatcher = "dojo.connect"; } } console.log("Dispatcher: " + dispatcher); }; console.log("use dojo.connect() on rect1 to trace..."); console.log("Running native method."); log(); rect1.pointInside(150, 250); console.log("Connecting an event processor."); h1 = dojo.connect(rect1, "pointInside", function(){ var args = Array.prototype.join.call(arguments, ", "); console.log("from dojo.connect(): " + args); }); log(); rect1.pointInside(150, 250); console.log("Connecting the TraceAll advice."); h2 = aop.advise(rect1, "pointInside", TraceAll); log(); rect1.pointInside(150, 250); console.log("Disconnecting the event processor."); dojo.disconnect(h1); log(); rect1.pointInside(150, 250); console.log("Disconnecting the advise."); aop.unadvise(h2); log(); rect1.pointInside(150, 250); console.log("Connecting the TraceAll advice."); h2 = aop.advise(rect1, "pointInside", TraceAll); log(); rect1.pointInside(150, 250); console.log("Connecting an event processor."); h1 = dojo.connect(rect1, "pointInside", function(){ var args = Array.prototype.join.call(arguments, ", "); console.log("from dojo.connect(): " + args); }); log(); rect1.pointInside(150, 250); console.log("Disconnecting the advise."); aop.unadvise(h2); log(); rect1.pointInside(150, 250); console.log("Disconnecting the event processor."); dojo.disconnect(h1); log(); rect1.pointInside(150, 250); console.log("================================="); console.log("trace all methods of rect1..."); h1 = aop.advise(rect1, /^\S/, aop.tracer(true)); rect1.move(100, 100); rect1.makeSquare(200); rect1.pointInside(150, 250); console.log("perimeter: " + rect1.getPerimeter()); console.log("area: " + rect1.getArea()); try{ rect1.assertSquare(); rect1.width = 300; // triggering exception rect1.assertSquare(); }catch(e){ // squelch } aop.unadvise(h1); console.log("================================="); console.log("count all get* methods of rect1..."); var counter = aop.counter(); h1 = aop.advise(rect1, /^get/, counter); rect1.move(100, 100); rect1.makeSquare(200); rect1.pointInside(150, 250); console.log("perimeter: " + rect1.getPerimeter()); console.log("area: " + rect1.getArea()); try{ rect1.assertSquare(); rect1.width = 300; // triggering exception rect1.assertSquare(); }catch(e){ // squelch } aop.unadvise(h1); console.log("get* methods were called", counter.calls, "times, with", counter.errors, "errors."); console.log("================================="); console.log("time all methods of rect1..."); h1 = aop.advise(rect1, /^\S/, aop.timer()); rect1.move(100, 100); rect1.makeSquare(200); rect1.pointInside(150, 250); console.log("perimeter: " + rect1.getPerimeter()); console.log("area: " + rect1.getArea()); try{ rect1.assertSquare(); rect1.width = 300; // triggering exception rect1.assertSquare(); }catch(e){ // squelch } aop.unadvise(h1); console.log("================================="); /* console.log("profile all methods of rect1..."); h1 = aop.advise(rect1, /^\S/, aop.profiler("Profile1")); rect1.move(100, 100); rect1.makeSquare(200); rect1.pointInside(150, 250); console.log("perimeter: " + rect1.getPerimeter()); console.log("area: " + rect1.getArea()); try{ rect1.assertSquare(); rect1.width = 300; // triggering exception rect1.assertSquare(); }catch(e){ // squelch } aop.unadvise(h1); console.log("================================="); */ var Fibonacci = function(order){ if(arguments.length == 1){ this.setOrder(order); }else{ this.offset = 2; } } dojo.extend(Fibonacci, { setOrder: function(order){ this.offset = order + 1; }, getOrder: function(){ return this.offset - 1; }, calculate: function(n){ if(n < 0){ return 0; } if(n == 0){ return 1; } return this.calculate(n - 1) + this.calculate(n - this.offset); }, calculateN: function(n, o){ if(n < 0){ return 0; } if(n == 0){ return 1; } return this.calculateN(n - 1, o) + this.calculateN(n - 1 - o, o); } }); var args = df.listcomp("i for(i = 0; i < 15; ++i)"); console.log("calculate Fibonacci numbers..."); var fib = new Fibonacci; h1 = aop.advise(fib, /^calculate/, aop.timer("fib")); console.log("before memoization"); fib.setOrder(0); console.log("0-order:", dojo.map(args, dojo.hitch(fib, "calculate"))); fib.setOrder(1); console.log("1-order:", dojo.map(args, dojo.hitch(fib, "calculate"))); fib.setOrder(2); console.log("2-order:", dojo.map(args, dojo.hitch(fib, "calculate"))); fib.setOrder(3); console.log("3-order:", dojo.map(args, dojo.hitch(fib, "calculate"))); console.log("after memoization"); h2 = aop.advise(fib, "calculate", aop.memoizer()); h3 = aop.advise(fib, /^set/, aop.memoizerGuard("calculate")); fib.setOrder(0); console.log("0-order:", dojo.map(args, dojo.hitch(fib, "calculate"))); fib.setOrder(1); console.log("1-order:", dojo.map(args, dojo.hitch(fib, "calculate"))); fib.setOrder(2); console.log("2-order:", dojo.map(args, dojo.hitch(fib, "calculate"))); fib.setOrder(3); console.log("3-order:", dojo.map(args, dojo.hitch(fib, "calculate"))); aop.unadvise(h3); aop.unadvise(h2); console.log("before memoization"); console.log(fib.calculateN(15, 0)); console.log(fib.calculateN(15, 1)); console.log(fib.calculateN(15, 2)); console.log(fib.calculateN(15, 3)); console.log("after memoization"); h2 = aop.advise(fib, "calculateN", aop.memoizer(function(a, b){ return a + "/" + b; })); h3 = aop.advise(fib, /^set/, aop.memoizerGuard("calculate")); console.log(fib.calculateN(15, 0)); console.log(fib.calculateN(15, 1)); console.log(fib.calculateN(15, 2)); console.log(fib.calculateN(15, 3)); aop.unadvise(h3); aop.unadvise(h2); aop.unadvise(h1); console.log("================================="); }; //dojo.addOnLoad(test); </script> </head> <body> <p>This test is meant to run with Firebug. Open the console to see the output.</p> <p><button onclick="test()">Start</button></p> </body> </html>