Revision: 3630 http://vexi.svn.sourceforge.net/vexi/?rev=3630&view=rev Author: clrg Date: 2009-08-28 10:06:12 +0000 (Fri, 28 Aug 2009)
Log Message: ----------- Better Cloning/Trap documentation Modified Paths: -------------- trunk/core/org.ibex.js/src/org/ibex/js/JS.jpp trunk/core/org.ibex.js/src/org/ibex/js/JSArray.jpp Modified: trunk/core/org.ibex.js/src/org/ibex/js/JS.jpp =================================================================== --- trunk/core/org.ibex.js/src/org/ibex/js/JS.jpp 2009-08-28 09:47:06 UTC (rev 3629) +++ trunk/core/org.ibex.js/src/org/ibex/js/JS.jpp 2009-08-28 10:06:12 UTC (rev 3630) @@ -41,19 +41,22 @@ * <code>cascade</code> keyword. <em>Note that reading the property directly will re-invoke the * read trap.</em></p> * - * <pre> var obj = { a:5 }; + * <pre> + * var obj = { a:5, b:4 }; * * // anonymous read trap - * obj.aSquared ++= function() { var a = cascade; return a*a; }; - * obj.aSquared == 25; // true + * obj.a ++= function() { var a = cascade; return a*a; }; + * obj.a == 25; // true * * // referenced read trap * var readCubed = function() { var a = cascade; return a*a*a; }; - * obj.aCubed ++= readCubed; - * obj.aCubed == 125; // true - * obj.aCubed --= readCubed; - * obj.aCubed == null; // true</pre> + * obj.b ++= readCubed; + * obj.b == 64; // true + * obj.b --= readCubed; + * obj.b == 4; // true</pre> * + * <p>You can not write to the <code>cascade</code> keyword in a read trap.</p> + * * <h3>Write Traps</h3> * * <p>A write trap is a js function with a single argument, which is the value being assigned to @@ -66,15 +69,38 @@ * * <p>To block a put - that is, cause the put to be ignored - simply return.</p> * + * <pre> + * <box id="a" enabled="true" focused="false" /> + * <box id="b" enabled="false" focused="false" /> + * + * var focusedWrite = function(v) { + * if (trapee.enabled) casade = v; + * else cascade = false; + * }; + * + * $a.focused ++= focusedWrite; + * $b.focused ++= focusedWrite; + * + * // $a accepts focus because it is enabled + * $a.focused = true; + * $a.focused == true; + * + * // $b declines focus because it is not enabled + * $b.focused = true; + * $b.focused == false;</pre> + * + * <p>You can not read from the <code>cascade</code> keyword in a write trap.</p> + * * <h3>Trap Chains</h3> * - * <p>Assigning multiple read or write traps to the same property on the same object are stacked - * in order of assignment to create a trap chain.</p> + * <p>When assigning multiple read or write traps to the same property on the same object, the + * traps are stacked in order of assignment to create a trap chain.</p> * * <p>There are two paths of execution in a trap chain, known as <em>pre-cascade</em> and * <em>post-cascade</em>. When a write or read occurs, the trap at the top of the stack enters its - * <em>pre-cascade</em> execution. When it cascades, it passes the execution to the next trap, - * and so on, until either a trap returns or the put/get reaches the object. Then the execution + * <em>pre-cascade</em> execution. When it <em>cascades</em> - either writing to cascade (write + * trap) or reading from cascade (read trap) - it passes the execution to the next trap, and so on, + * until either a trap returns or the put/get reaches the object. Then the execution * enters the <em>post-cascade</em> of the next trap up in the stack fro the return point, and * when a trap finishes, it passes the execution back up again in the stack.</p> * @@ -82,86 +108,106 @@ * * <p>Consider:</p> * - * <pre> var obj = {}; - * var block_at_B = false; + * <pre> + * var obj = { a:true }; * - * var trap_A = function(v) { - * vexi.log.info("A: pre-cascade"); + * var trap_1 = function(v) { + * vexi.log.info("1: pre-cascade"); * cascade = v; - * vexi.log.info("A: post-cascade"); + * vexi.log.info("1: post-cascade"); * }; - * var trap_B = function(v) { - * vexi.log.info("B: pre-cascade"); - * if (block_at_B) return; + * var trap_2 = function(v) { + * vexi.log.info("2: pre-cascade"); + * if (v==false) return; * cascade = v; - * vexi.log.info("B: post-cascade"); + * vexi.log.info("2: post-cascade"); * }; - * var trap_C = function(v) { - * vexi.log.info("B: pre-cascade"); + * var trap_3 = function(v) { + * vexi.log.info("3: pre-cascade"); * cascade = v; - * vexi.log.info("B: post-cascade"); + * vexi.log.info("3: post-cascade"); * }; * - * obj.a ++= trap_A; - * obj.a ++= trap_B; - * obj.a ++= trap_C; + * obj.a ++= trap_1; + * obj.a ++= trap_2; + * obj.a ++= trap_3; * * obj.a = true; * // outputs: - * // C: pre-cascade - * // B: pre-cascade - * // A: pre-cascade - * // A: post-cascade - * // B: post-cascade - * // C: post-cascade + * // 3: pre-cascade + * // 2: pre-cascade + * // 1: pre-cascade + * // 1: post-cascade + * // 2: post-cascade + * // 3: post-cascade * - * block_at_B = true; - * obj.a = true; + * obj.a = false; * // outputs: - * // C: pre-cascade - * // B: pre-cascade - * // C: post-cascade</pre> + * // 3: pre-cascade + * // 2: pre-cascade + * // 3: post-cascade</pre> + * + * <p>For encapsulation reasons, traps are always stacked in order of assignment, and this order + * can not be altered except by removing, by reference, any traps in the chain.</p> */ /*...@page(concept=Cloning) * - * <p>A clone of an object is identical to the object it has cloned, the clonee, except that - * traps placed on it are not placed on the clonee. That is, puts and reads will act upon the - * clonee unless otherwise intercepted by traps on the clone.</p> + * <p>A clone is an object that shares the properties of the object from which it was cloned, but + * can be modified using traps that do not impact upon the original object.</p> * - * <p>Clones can be created using the <code>vexi.js.clone()</code> function:</p> + * <p>Clones can be created using the <code>vexi.js.clone()</code> function.</p> * - * <pre> var clonee = {}; + * <p>You may get the original object using <code>vexi.js.unclone()</code> function. It will + * always get the original object and never return a clone.</p> + * + * <h3>Clone Behaviour</h3> + * + * <p>A clone of an object is initially identical to the object it has cloned, the clonee, and puts + * and reads on the clone will act upon the clonee, but they are not the same object. Traps placed + * on the clone are not placed on the clonee. That is, puts and reads on the clone will act upon + * the clonee unless otherwise intercepted by non-cascading traps on the clone.</p> + * + * <p>Consider:</p> + * + * <pre> var clonee = { a:3, b:5 }; * var clone = vexi.js.clone(clonee); - * var tmp; + * var z; * - * // these puts are equivalent - * clone.foo = 1; - * clonee.foo = 1; + * // true + * 3 == clonee.a == clone.a; * + * // still true after put to clone + * clone.a = 2; + * 2 == clonee.a == clone.a; + * + * // still true after put to clonee + * clonee.a = 1; + * 1 == clonee.a == clone.a; + * * // these reads are equivalent - * tmp = clone.foo; - * tmp = clonee.foo; + * z = clone.a; + * z = clonee.a; * - * clone.bar ++= function(v) { return; } - * clone.bar ++= function() { return null; } + * // non-cascading traps + * clone.b ++= function(v) { return; } + * clone.b ++= function() { return 0; } * * // these puts are not equivalent - * clone.bar = 2; - * clonee.bar = 2; + * clone.b = 2; // clone.b == 0, clonee.b == 5 + * clonee.b = 2; // clone.b == 0, clonee.b == 2 * * // these reads are not equivalent - * tmp = clone.bar; // tmp==null - * tmp = clonee.bar; // tmp==2</pre> + * z = clone.b; // z==0 + * z = clonee.b; // z==2</pre> * - * <p>You may created multiple clones of an object. You may clones of clones. Clones can be - * created and discarded without affecting the original object directly.</p> + * <p>You may created multiple clones of an object. You may create clones of clones. Clones can + * be created and discarded without affecting the original object directly.</p> * * <p>A clone is a different object to its clonee, so the following is always true:</p> * - * <pre> vexi.js.clone(clonee) != clonee</pre> - * - * <p>You may get the original object using <code>vexi.js.unclone()</code> function.</p> + * <pre> + * vexi.js.clone(clonee) != clonee</pre> */ /** The minimum set of functionality required for objects which are manipulated by JavaScript */ @@ -230,7 +276,28 @@ public JS unclone() { return this; } public JS type() { return SC_immutable; } public Keys keys() throws JSExn { throw new JSExn(type()+" has no key set"); } - public JS get(JS key) throws JSExn { return null; } + public JS get(JS key) throws JSExn { + //#noswitch - leave, needed for jsdoc + /*...@page(varname=Immutable,humanname=Immutable JS Object) + * + * <p>An immutable js object.</p> + * + * <p>Immutable objects may not have any properties or traps placed upon them.</p> + * + * <p>They may be useful in conjuction with Cloning to create objects with a strict + * set of static or scoped properties.</p> + * + * <pre> + * var immutable = new vexi.js.Immutable(); + * var type = vexi.js.clone(immutable); + * var scopedprop = "foo"; + * type.prop ++= function() { return scopedprop; }; + * type.prop ++= function(v) { scopedprop = v; };</pre> + * + * */ + //#end + throw new JSExn("'"+key+"' is not a valid property on "+type()); + } public void put(JS key, JS val) throws JSExn { throw new JSExn("'" + key + "' is read only on " + type()); } @@ -272,7 +339,7 @@ public class Constructor extends JS.Immutable { final String name; - public Constructor(String name){ this.name = name; } + public Constructor(String name) { this.name = name; } public JS apply(JS this_, JS[] args) throws JSExn { throw new JSExn("Basic type constructor '"+ name + "' can only used with new"); } @@ -283,8 +350,9 @@ public static class Clone extends JS.Obj { protected final Cloneable clonee; public Clone(JS clonee) throws JSExn { - if (!(clonee instanceof Cloneable)) + if (!(clonee instanceof Cloneable)) { throw new JSExn(clonee.getClass().getName() + " does not implement cloneable"); + } this.clonee = (Cloneable)clonee; } // Non-Trap methods forward to the clonee @@ -337,12 +405,16 @@ } public Obj(ConstructorList constructor) { - if (Instr.memory!=null) Instr.memory.register(this); + if (Instr.memory!=null) { + Instr.memory.register(this); + } constructors = constructor; } protected void finalize() throws Throwable { - if (Instr.memory!=null) Instr.memory.unregister(this); + if (Instr.memory!=null) { + Instr.memory.unregister(this); + } } // HACK - neat, but still a hack. At least until the semantics are clear @@ -430,11 +502,13 @@ * * <p>The standard js object.</p> * - * <p>Objects can be created as literals in javascript using <code>{}</code></p> + * <p>Objects can be created as literals in vexiscript using <code>{}</code>.</p> * - * <p>Unlike in browser javascript, in vexiscript (Vexi javascript) - * Objects do not have any standard properties (and so have a - * completely free keyspace). </p> + * <p>Objects can be initialized with content using <code>{ key1:val1, key2:val2,... + * keyn:valn }.</code></p> + * + * <p>Unlike in browser javascript, in vexiscript Objects do not have any standard + * properties, and so have a completely free keyspace.</p> * * */ //#end @@ -568,9 +642,10 @@ * <p>Placing a trap on this allows the interception of all read and writes to this * proxy object</p> * - * <pre> - * proxy.Properties ++= function(){} // a (range) read trap - * proxy.Properties ++= function(v){} // a (range) write trap</pre> + * <pre> // a (range) read trap + * proxy.Properties ++= function() { }; + * // a (range) write trap + * proxy.Properties ++= function(v) { };</pre> * * @initial_value(N/A,code=false) * @type(<i>N/A</i>) @@ -689,19 +764,18 @@ //#switch(JSU.toString(key)) /*...@page(varname=ProxyList,humanname=ProxyList Object) * - * <p>The proxy list object is an alternative list object to the - * standard js array, which supports a 'range trap' 'Elements' to - * trap on the accessingadding/removing of elements</p> + * <p>The proxy list object is an alternative list object to the standard js array, + * which supports a 'range trap' 'Elements' to trap on the + * accessing/adding/removing of elements</p> * * <p>Whereas the Proxy is very similar to the standard Object the ProxyList is not * similar to an array and so cannot be used as a drop in replacement. Notably * it does not support most of the methods that arrays have, and it is not sparse * and cannot contain nulls. Putting null to a proxy list will remove the object - * at the index. </p> - * + * at the index.</p> * */ - /* The length of the ProxyList @type(Number) */ + /* The length of the ProxyList @type(Number) @initial_value(varies,code=false) */ case "length": return JSU.N(bt.treeSize()); /* <p>The index of an element in the proxylist, or null if the element @@ -720,10 +794,10 @@ * <p>Placing a trap on this allows the interception of all read and writes to this * proxylist object</p> * - * <pre> - * proxylist.Elements ++= function(){} // a (range) read trap - * proxylist.Elements ++= function(v){} // a (range) write trap - * </pre> + * <pre> // a (range) read trap + * proxylist.Elements ++= function() { }; + * // a (range) write trap + * proxylist.Elements ++= function(v) { };</pre> * * @initial_value(N/A,code=false) * @type(<i>N/A</i>) Modified: trunk/core/org.ibex.js/src/org/ibex/js/JSArray.jpp =================================================================== --- trunk/core/org.ibex.js/src/org/ibex/js/JSArray.jpp 2009-08-28 09:47:06 UTC (rev 3629) +++ trunk/core/org.ibex.js/src/org/ibex/js/JSArray.jpp 2009-08-28 10:06:12 UTC (rev 3630) @@ -32,41 +32,49 @@ * * <p>The standard js array.</p> * - * <p>Arrays can be created as literals in javascript using <code>[]</code></p> + * <p>Arrays can be created as literals in vexiscript using <code>[]</code> which + * creates a new empty array.</p> + * + * <p>Arrays can be initialized with contents in vexiscript using <code>[i1, i2,... in]</code>. * */ - /* Returns a new array containing the elements from the array - * object followed by the elements from each of the arguments. + + /* Returns a new array containing the elements from the array object followed by the + * elements from each of the arguments. * * @param(name=a,varargs=true) * @return(Array) * */ case "concat": return METHOD; + /* Returns a shallow copy of the array. * * @return(Array) * */ case "copy": return METHOD; - /* <p>Returns the array's values concatenated into a single string, - * with each value separated by the separator string.</p> + + /* <p>Returns the array's values concatenated into a single string, with each value + * separated by the separator string.</p> * - * <p>If separator is omitted, then it defaults to "," as the - * separator string.<p> + * <p>If separator is omitted, then it defaults to "," as the separator string.</p> * * @param(name=separator,optional=true) * @return(String) * */ case "join": return METHOD; - /* The length of an array. - + + /* The length of an array. * * @type(Number) * */ case "length": return JSU.N(size()); + /* Removes the last element of the array and returns it. * If the array is currently empty, then it returns null. * * @return(<i>varies</i>) * */ case "pop": return METHOD; + /* Adds the specified values to the end of the current array * and returns the new size of the array. * @@ -74,17 +82,20 @@ * @return(Number) * */ case "push": return METHOD; + /* Reverses the order of the elements in the current array and returns the array. * * @return(Array) * */ case "reverse": return METHOD; + /* Removes the first element of the array and returns it. If the array is currently * empty, then it returns null. * * @return(<i>varies</i>) * */ case "shift": return METHOD; + /* <p>Returns a new array which contains a copy of the section of the current array * between start and end - 1, inclusive.</p> * @@ -98,6 +109,7 @@ * @return(Array) * */ case "slice": return METHOD; + /* <p>Sorts the contents of the current array and returns it.</p> * * <p>If compareFunction is specified, then the given comparison function (which must @@ -108,6 +120,7 @@ * @return(Array) * */ case "sort": return METHOD; + /* <p>Removes the array elements from start to start + deleteCount from the array, * and replaces them with the specified values. Returns a new array containing the * deleted values.<p> @@ -123,11 +136,13 @@ * @return(Number) */ case "splice": return METHOD; + /* Returns array.join(). * * @return(String) * */ case "toString": return METHOD; + /* Inserts the specified values at the beginning of the array. Returns the new size * of the array. * @@ -135,26 +150,39 @@ * @return(Number) * */ case "unshift": return METHOD; + //#end // MAYbe better to return null // return null; throw new JSExn("Attempt to get unrecognized string key '"+JSU.toString(key)+"' from an array"); } int i = JSU.toInt(key); - if (i < 0) throw new JSExn("Attempt to get negative key '"+i+"' from an array"); + if (i < 0) { + throw new JSExn("Attempt to get negative key '"+i+"' from an array"); + } try { return (JS)get(i); - } catch (IndexOutOfBoundsException e) { return null; } + } catch (IndexOutOfBoundsException e) { + return null; + } } public void put(JS key, JS val) throws JSExn { // special array property put for length - if (JSU.isString(key) && JSU.toString(key).equals("length")) { size(JSU.toInt(val)); return; } + if (JSU.isString(key) && JSU.toString(key).equals("length")) { + size(JSU.toInt(val)); + return; + } // normal array[i] put - if (key == null || !(JSU.isInt(key))) + if (key == null || !(JSU.isInt(key))) { throw new JSExn("Arrays only support positive integer keys, can not use: "+JSU.toString(key)); + } int i = JSU.toInt(key); - if (i < 0) throw new JSExn("Attempt to put to negative key '"+i+" on an array"); - if (size() < i+1) size(i + 1); + if (i < 0) { + throw new JSExn("Attempt to put to negative key '"+i+" on an array"); + } + if (size() < i+1) { + size(i + 1); + } set(i, val); } @@ -182,7 +210,9 @@ case "splice": return splice(args); case "toString": return join(","); case "unshift": - for (int i=0; i < args.length; i++) add(i, args[i]); + for (int i=0; i < args.length; i++) { + add(i, args[i]); + } return JSU.N(size()); //#end throw new JSExn("Arrays have no function: "+JSU.toString(method)); @@ -204,7 +234,7 @@ } private void concat_fill(JSArrayLike arr) throws JSExn { - for(int i=0; i<arr.length(); i++) { + for (int i=0; i<arr.length(); i++) { add(arr.getElement(i)); } } @@ -229,14 +259,16 @@ private JS concat(JS[] args) throws JSExn { int l = size(); // size & check - for(int i=0; i<args.length; i++) { - if(!(args[i] instanceof JSArrayLike)) throw new JSExn("Arg "+i+" not an []"); + for (int i=0; i<args.length; i++) { + if (!(args[i] instanceof JSArrayLike)) { + throw new JSExn("Arg "+i+" not an []"); + } JSArrayLike a = ((JSArrayLike)args[i]); l += a.length(); } JSArray r = new JSArray(l); r.concat_fill(this); - for(int i=0; i<args.length; i++) { + for (int i=0; i<args.length; i++) { r.concat_fill((JSArrayLike)args[i]); } return r; @@ -304,8 +336,12 @@ try { sortargs[0] = (JS)a; sortargs[1] = (JS)b; return JSU.toInt(sort.apply(null, sortargs)); - } catch (JSExn e) { throw new JSExn.Wrapper(e); - } finally { sortargs[0] = null; sortargs[1] = null; } + } catch (JSExn e) { + throw new JSExn.Wrapper(e); + } finally { + sortargs[0] = null; + sortargs[1] = null; + } } private JSArray copy() { @@ -319,8 +355,9 @@ JSArray r = new JSArray(0); r.size = size; r.o = new Object[size]; - for(int i=0; i<size(); i++) + for (int i=0; i<size(); i++) { r.o[i] = JSU.deepcopy((JS)o[i]); + } return r; } @@ -328,8 +365,9 @@ public int length() { return size(); } public JS[] toArray() { JS[] r = new JS[size()]; - for(int i=0; i<size(); i++) + for (int i=0; i<size(); i++) { r[i] = (JS)o[i]; + } return r; } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Vexi-svn mailing list Vexi-svn@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/vexi-svn