Added new functional tools.
authordsc <david.schoonover@gmail.com>
Sun, 31 Oct 2010 05:23:56 +0000 (22:23 -0700)
committerdsc <david.schoonover@gmail.com>
Sun, 31 Oct 2010 05:23:56 +0000 (22:23 -0700)
src/Y/modules/y.op.js
src/Y/y-collection.js
src/Y/y-function.js
src/Y/y-number.js
src/Y/y-op.js
src/portal/shape.js

index 4eed2b2..d8260a4 100644 (file)
@@ -97,4 +97,5 @@ Y.op = {
     }
 };
 
+
 })(this.Y);
index 4de7996..ee317ee 100644 (file)
@@ -15,11 +15,6 @@ YBase.subclass('YCollection', {
     'init' : function(o){
         if (!o) return;
         this._o = o;
-        // var proto = (o.constructor || {}).prototype || {};
-        // for (var k in proto) {
-        //     if (isFunction(proto[k]))
-        //         this[k] = bind.call(proto[k], o);
-        // }
     },
     
     'attr'   : function(k, v, def){
@@ -105,9 +100,10 @@ YBase.subclass('YCollection', {
     },
     
     'zip' : function(){
-        var sequences = new Y(arguments).map(Y).unshift(this);
+        var sequences = new Y(arguments).map( Y.limit(1) ).unshift(this);
         return this.map(function(_, k){
-            return sequences.invoke('attr', k);
+            var r = sequences.map( Y.op.get(k) );
+            return r;
         });
     },
     
index 91447cf..d73707d 100644 (file)
@@ -1,27 +1,34 @@
+var WR_P = "__wraps__";
+
+var _ = globals._ = YFunction._ = {};
+
 function YFunction(fn){
-    fn._o = fn;
+    if (!fn)
+        fn = function(){};
+    if (fn.__y__)
+        return fn;
+    
+    // fn._o = fn;
     fn.__y__ = true;
     return install(fn);
 }
 
-// YFunction = YCollection.subclass({
-//     init : YFunction,
-//     reduce : reduce,
-//     attr : attr,
-//     extend : extend,
-//     end : function(){ return this; }
-// })
-
 Y.YFunction = YFunction;
-YFunction.prototype.end    = function(){ return this; };
+Y.extend(YFunction.prototype, {
+    init   : YFunction,
+    reduce : methodize(Y.reduce),
+    extend : methodize(Y.extend),
+    end : function(){ return this; }
+});
 YFunction.prototype.attr   = methodize(Y.attr);
-YFunction.prototype.extend = methodize(Y.extend);
-YFunction.prototype.reduce = methodize(Y.reduce);
+// YFunction.prototype.extend = methodize(Y.extend);
+// YFunction.prototype.reduce = methodize(Y.reduce);
 
 YFunction.install = install;
 function install(target){
     target = target || Function.prototype;
     var proto = YFunction.prototype;
+    
     for (var k in proto) {
         if ( isFunction(proto[k]) && (k == 'bind' || !target[k]) )
             target[k] = proto[k];
@@ -31,6 +38,51 @@ function install(target){
 
 
 
+function unwrap(fn){
+    return ( fn && isFunction(fn) ) ? unwrap(fn[WR_P]) || fn : fn;
+}
+
+Y.curry = curry;
+YFunction.prototype.curry = methodize(curry);
+function curry(fn){
+    if (fn.__curried__)
+        return fn.apply(this, Y(arguments,1));
+    
+    var args = Y(arguments, 1)
+    ,   L = unwrap(fn).length;
+    
+    if ( args.length >= L )
+        return fn.apply(this, args);
+    
+    function curried(){
+        var _args = args.concat( Y(arguments) );
+        if ( _args.length >= L )
+            return fn.apply(this, _args);
+        else
+            return curry.apply(this, [fn].concat(_args));
+    }
+    
+    curried.__wraps__ = fn;
+    curried.__curried__ = args;
+    return curried;
+}
+
+
+Y.methodize = methodize;
+YFunction.prototype.methodize = methodize(methodize);
+function methodize(fn) {
+    if ( fn.__methodized__ )
+        return fn.__methodized__;
+    
+    var m = fn.__methodized__ =
+        function(){
+            return fn.apply(this, [this].concat( Y(arguments) ));
+        };
+    m[WR_P] = fn;
+    return m;
+}
+
+
 Y.compose = compose;
 YFunction.prototype.compose = methodize(compose);
 function _composer(x,fn){ return fn.call(this, x); }
@@ -60,56 +112,6 @@ function chain(f,g){
     return wrapper;
 }
 
-function splat(fn, x){
-    return fn[ isArray(x) ? "apply" : "call"](this, x);
-}
-
-function unwrap(fn){
-    return (fn && isFunction(fn)) ? unwrap(fn.__wraps__) || fn : fn;
-}
-
-YFunction.prototype.bind = function(context, args){
-    var bound = Y( _Function.prototype.bind.apply(this, arguments) );
-    bound.__wraps__ = this;
-    return bound;
-};
-
-
-// Remembers arguments but obeys current context
-YFunction.prototype.partial = partial;
-function partial(){
-    var fn = this
-    ,   args = Y(arguments)
-    ,   partially = Y(function(){
-            return fn.apply( this, args.concat(arguments) );
-        });
-    partially.__wraps__ = fn;
-    return partially;
-}
-
-// Collects arguments but ignores context: fn.curry( arg1, arg2, ... )
-YFunction.prototype.curry = methodize(curry);
-function curry(fn){
-    if (fn.__curried__)
-        return fn.apply(this, arguments);
-    
-    var args = Y(arguments, 1)
-    ,   L = unwrap(fn).length;
-    
-    function curried(){
-        var self = arguments.callee
-        ,   _args = self.__curried__ = args.concat(arguments);
-        self.__wraps__ = fn;
-        
-        if ( _args.length >= L )
-            return fn.apply(this, _args);
-        else
-            return curried;
-    }
-    
-    return curried();
-}
-
 // YFunction.prototype.lazy = methodize(lazy);
 // function lazy(fn){
 //     var args = Y(arguments, 1)
@@ -137,41 +139,96 @@ function curry(fn){
 // }
 
 
-Y.methodize = methodize;
-YFunction.prototype.methodize = methodize(methodize); // heh
-function methodize( fn ) {
-    if (fn.__methodized)
-        return fn.__methodized;
-    
-    var m = fn.__methodized =
-        Y(function(){
-            var target = (this instanceof YBase) ? this._o : this
-            ,   result = fn.apply(target, [target].concat(Y(arguments)));
-            if (result === target)
-                return this;
-            else
-                return result;
-            // return fn.apply(this, [this].concat(Y(arguments)));
-        });
-    m.__wraps__ = fn;
-    return m;
+function splat(fn, x){
+    return fn[ isArray(x) ? "apply" : "call"](this, x);
 }
 
+var _bind = _Function.prototype.bind;
+YFunction.prototype.bind = function(context, args){
+    var bound = _bind.apply(this, arguments);
+    bound.__wraps__ = this;
+    return Y(bound);
+};
+
+
+// Remembers arguments but obeys current context
+YFunction.prototype.partial = partial;
+function partial(){
+    var fn = this
+    ,   args = Y(arguments)
+    ,   partially = function(){
+            return fn.apply( this, args.concat(Y(arguments)) );
+        };
+    partially.__wraps__ = fn;
+    return Y(partially);
+}
+
+
 Y.genericize = genericize;
 YFunction.prototype.genericize = methodize(genericize); // heh
 function genericize( fn ) {
-    if (fn.__genericize)
-        return fn.__genericize;
+    if (fn.__genericized__)
+        return fn.__genericized__;
     
-    var g = fn.__genericize =
-        Y(function(){
+    var g = fn.__genericized__ =
+        function(){
             var args = Y(arguments), self = args.shift();
             return fn.apply(self, args);
-        });
+        };
     g.__wraps__ = fn;
-    return g;
+    return Y(g);
+}
+
+// Only works for arguments whose toString is unique and stateless (for example, primitives, but not closures).
+// XXX: hashCode()
+Y.memoize = memoize;
+YFunction.prototype.memoize = methodize(memoize);
+function memoize(fn){
+    var cache = {};
+    function memorizer(){
+        // I'd like to use toJSON here, but that won't work cross-browser.
+        var key = Y(arguments).join('\0');
+        if ( !(key in cache) )
+            cache[key] = fn.apply(this, arguments);
+        return cache[key];
+    }
+    
+    memorizer.__wraps__ = fn;
+    memorizer.__cache__ = cache;
+    return memorizer;
 }
 
+// Memorized to reduce eval costs
+var
+n = 4,
+_ofArityWrapper =
+YFunction._ofArityWrapper =
+    memoize(function(n, limit){
+        return eval('(function(fn){ '+
+            'return function('+Y.range(n).map( Y.op.add('$') ).join(',')+'){ '+
+                'return fn.apply(this,' + (limit ? 'Y(arguments).slice(0,'+n+')' : 'arguments')+ 
+            '); }; })');
+    });
+
+YFunction.prototype.aritize = function(n){
+    return _ofArityWrapper(n, false)(this);
+};
+
+YFunction.prototype.limit = function(n){
+    return _ofArityWrapper(n, true)(this);
+};
+
+
+/**
+ * Filter the arguments passed to the wrapper function
+ */
+YFunction.prototype.mask = mask;
+function mask(){
+    
+}
+
+
+
 /** Returns the declared name of a function. */
 YFunction.prototype.getname = Y.getname = getname;
 function getname( fn ){
@@ -183,7 +240,6 @@ function getname( fn ){
         return fn.className || fn.name || (fn+'').match( /function\s*([^\(]*)\(/ )[1] || '';
 }
 
-
 Y.mixinNames = mixinNames;
 function mixinNames(o, Donor, names, override, yWrap){
     var target = ( isFunction(o)     ? o.prototype     : o)
@@ -202,6 +258,10 @@ function mixinNames(o, Donor, names, override, yWrap){
 }
 
 
+YFunction(Y);
 Y(Y.reduce);
 Y(Y.attr);
 Y(Y.extend);
+Y.reduce(YFunction.prototype, function(_,fn,name){
+    YFunction(fn);
+});
index 724a8e6..c390bb5 100644 (file)
@@ -21,20 +21,37 @@ YCollection.subclass('YNumber', {
 
 
 Y.range = range;
-function range(start, end){
-    // range() --> []
-    if ( arguments.length === 0 ) return [];
-    // range(3) --> range(0,3)
-    else if ( arguments.length === 1 ) { end = start; start = 0; }
-    // range(5,2) --> range(1,6).reverse()
-    if (start > end) { 
-        var r = range(end-1, start+1);
-        r.reverse();
-        return r;
-    } else {
-        var i = end - start - 1, r = new Array(i);
-        while ( i >= 0 ) r[i] = start + i--;
-        return r;
+function range(start, end, step){
+    switch (arguments.length) {
+        // range() -> []
+        case 0 : return [];
+        
+        // range(3)  -> range( 0,3)
+        // range(-3) -> range(-3,0)
+        case 1 :
+            if (start > 0) {
+                end = start; 
+                start = 0;
+            } else
+                end = 0;
     }
+    
+    if (start === end) return [];
+    
+    // range(2,5) -> range(2,5, 1) -> [2,3,4]
+    // range(5,2) -> range(5,2,-1) -> [5,4,3]
+    if (start < end)
+        var v = start, L = end,   s =  1;
+    else
+        var v = end,   L = start, s = -1;
+    
+    step = step || s;
+    
+    var r = [];
+    while ( v < L ) {
+        r.push(v);
+        v += step;
+    }
+    return r;
 }
 
index 38d05b5..36394e3 100644 (file)
@@ -48,12 +48,21 @@ Y.op = {
     nop:    function(){},
     
     // accessors
-    isset:  function(o,def){   return o !== undefined ? o : def; },
-    has:    function(x,y){     return y in x; },
-    getkey: function(k,o){     return o[k] },
-    getdef: function(o,k,def){ return (k in o ? o[k] : def); },
-    set:    function(o,k,v){   if (o) o[k] = v; return o; }
+    isset:  function(def,o){   return o !== undefined ? o : def; },
+    has:    function(k,o){     return k in o; },
+    get: function(k,o){     return o[k] },
+    getdef: function(def,k,o){ return (k in o ? o[k] : def); },
+    set:    function(o,k,v){   if (o) o[k] = v; return o; },
+    method: function(name){
+        var args = Y(arguments,1);
+        return function(obj){ return obj[name].apply(obj, args); };
+    }
     
 };
 
+// Curry all operators
+Y.op = Y.reduce(Y.op, function(op, fn, k){
+    op[k] = Y(fn).curry();
+    return op;
+}, {});
 
index e0e3a63..a7b4c95 100644 (file)
@@ -57,41 +57,40 @@ Rect = new Y.Class('Rect', Shape, {
     
 });
 
-Triangle = new Y.Class('Triangle', Shape, {
-    x1: 0, y1: 0,
-    x2: 0, y2: 0,
+Polygon = new Y.Class('Polygon', Shape, {
+    x0: 0, y0:0,
     _offsetX : 0, // We need our triangle to be in the first quadrant
     _offsetY : 0, // so we'll have to offset any negative shapes at the position call
     
-    init : function(x1,y1, x2,y2){
+    /**
+     * Expects two arrays of coordinate-halfs, which could be zipped
+     * together to make the numbered coordinates.
+     * x0 and y0 will always be 0.
+     */
+    init : function(xs, ys){
         Layer.init.call(this);
         
-        var minX = Math.min(0, x1, x2);
-        if (minX < 0) {
-            var offX = this._offsetX = -minX;
-            x1 += offX; x2 += offX;
-        }
+        var xs = this._calcOffset('x', xs)
+        ,   ys = this._calcOffset('y', ys) ;
         
-        var minY = Math.min(0, y1, y2);
-        if (minY < 0) {
-            var offY = this._offsetY = -minY;
-            Y1 += offY; y2 += offY;
-        }
+        this.points = Y(xs).zip(ys);
         
-        this.x1 = x1; this.y1 = y1;
-        this.x2 = x2; this.y2 = y2;
-        this.width(  Math.max(0, x1, x2) );
-        this.height( Math.max(0, y1, y2) );
+        this.width(  Math.max.apply(Math, xs) );
+        this.height( Math.max.apply(Math, ys) );
     },
     
     _calcOffset : function(which, values){
-        var min = Math.min(0, Math.min.apply(Math, values));
+        values.unshift(0);
+        var self = this
+        ,   off = -1 * Math.min.apply(Math, values);
         
-        if (min < 0) {
-            var off = this['_offset'+which] = -min;
-            x1 += off; x2 += off;
-        }
-        return 
+        self['_offset'+which.toUpperCase()] = off;
+        self[which+'s'] = values = values.map(function(v, i){
+                v += (i === 0 ? 0 : off);
+                self[which+i] = v
+                return v;
+            });
+        return values;
     },
     
     position : function(left, top){
@@ -110,6 +109,23 @@ Triangle = new Y.Class('Triangle', Shape, {
         return this;
     },
     
+    drawShape : function(ctx){
+        var self = this;
+        
+    }
+});
+
+Triangle = new Y.Class('Triangle', Polygon, {
+    x1: 0, y1: 0,
+    x2: 0, y2: 0,
+    
+    init : function (x1,y1, x2,y2){
+        Polygon.init.call(this, [x1,x2], [y1,y2]);
+    },
+    
+    drawShape : function(ctx){
+        
+    }
 });
 
 Ellipse = new Y.Class('Ellipse', Shape, {