From 34b2f689ed8b30f2ebc1daae924787320ea9908e Mon Sep 17 00:00:00 2001 From: dsc Date: Sat, 27 Nov 2010 15:03:53 -0800 Subject: [PATCH] Checkpoint on module refactor. --- src/Y/_intro.js | 4 - src/Y/_outro.js | 2 - src/Y/alias.cjs | 13 + src/Y/alias.js | 13 - src/Y/class.cjs | 229 +++++++++++++ src/Y/core.cjs | 118 +++++++ src/Y/core.js | 102 ------ src/Y/index.cjs | 71 ++++ src/Y/op.cjs | 78 +++++ src/Y/to-function.js | 221 ------------- src/Y/tofunction.cjs | 221 +++++++++++++ src/Y/type.cjs | 115 +++++++ src/Y/type.js | 80 ----- src/Y/types/array.cjs | 102 ++++++ src/Y/types/collection.cjs | 134 ++++++++ src/Y/types/function.cjs | 308 ++++++++++++++++++ src/Y/types/number.cjs | 59 ++++ src/Y/types/object.cjs | 74 +++++ src/Y/types/string.cjs | 155 +++++++++ src/Y/y-array.js | 98 ------ src/Y/y-class.js | 229 ------------- src/Y/y-collection.js | 133 -------- src/Y/y-core.js | 88 ----- src/Y/y-function.js | 301 ------------------ src/Y/y-number.js | 57 ---- src/Y/y-object.js | 72 ----- src/Y/y-op.js | 78 ----- src/Y/y-string.js | 153 --------- src/Y/y.cjs | 89 ++++++ src/easel/layer.js | 513 ------------------------------ src/easel/loop/cooldown.js | 41 --- src/easel/loop/eventloop.js | 122 ------- src/easel/loop/fps.js | 101 ------ src/easel/math/line.js | 141 -------- src/easel/math/math.js | 19 -- src/easel/math/vec.js | 133 -------- src/easel/shape/circle.js | 23 -- src/easel/shape/line.js | 130 -------- src/easel/shape/polygon.js | 63 ---- src/easel/shape/rect.js | 28 -- src/easel/shape/shape.js | 23 -- src/easel/util/astar.js | 140 -------- src/easel/util/binaryheap.js | 146 --------- src/easel/util/graph.js | 16 - src/easel/util/tree/pointquadtree.js | 580 ---------------------------------- src/easel/util/tree/quadtree.js | 241 -------------- src/easel/util/tree/rbtree.js | 467 --------------------------- src/ezl/layer.js | 513 ++++++++++++++++++++++++++++++ src/ezl/loop/cooldown.js | 41 +++ src/ezl/loop/eventloop.js | 122 +++++++ src/ezl/loop/fps.js | 101 ++++++ src/ezl/math/line.js | 141 ++++++++ src/ezl/math/math.js | 19 ++ src/ezl/math/vec.js | 133 ++++++++ src/ezl/shape/circle.js | 23 ++ src/ezl/shape/line.js | 130 ++++++++ src/ezl/shape/polygon.js | 63 ++++ src/ezl/shape/rect.js | 28 ++ src/ezl/shape/shape.js | 23 ++ src/ezl/util/astar.js | 140 ++++++++ src/ezl/util/binaryheap.js | 146 +++++++++ src/ezl/util/graph.js | 16 + src/ezl/util/tree/pointquadtree.js | 580 ++++++++++++++++++++++++++++++++++ src/ezl/util/tree/quadtree.js | 241 ++++++++++++++ src/ezl/util/tree/rbtree.js | 467 +++++++++++++++++++++++++++ src/tanks/calc.cjs | 5 + src/tanks/calc.js | 5 - src/tanks/config.cjs | 14 + src/tanks/config.js | 16 - src/tanks/game.cjs | 193 +++++++++++ src/tanks/game.js | 183 ----------- src/tanks/globals.cjs | 52 +++ src/tanks/globals.js | 52 --- src/tanks/index.cjs | 2 + src/tanks/map/level.cjs | 104 ++++++ src/tanks/map/level.js | 104 ------ src/tanks/map/loc.js | 260 --------------- src/tanks/map/loc/loc.cjs | 260 +++++++++++++++ src/tanks/map/pathmap.cjs | 378 ++++++++++++++++++++++ src/tanks/map/pathmap.js | 378 ---------------------- src/tanks/map/trajectory.cjs | 227 +++++++++++++ src/tanks/map/trajectory.js | 227 ------------- src/tanks/tanks.js | 1 - src/tanks/thing/bullet.cjs | 118 +++++++ src/tanks/thing/bullet.js | 118 ------- src/tanks/thing/custom-tank.cjs | 8 + src/tanks/thing/custom-tank.js | 8 - src/tanks/thing/index.cjs | 5 + src/tanks/thing/player.cjs | 199 ++++++++++++ src/tanks/thing/player.js | 200 ------------ src/tanks/thing/tank.cjs | 424 +++++++++++++++++++++++++ src/tanks/thing/tank.js | 424 ------------------------- src/tanks/thing/thing.cjs | 196 ++++++++++++ src/tanks/thing/thing.js | 189 ----------- src/tanks/ui/grid.cjs | 66 ++++ src/tanks/ui/grid.js | 66 ---- src/tanks/ui/main.cjs | 250 +++++++++++++++ src/tanks/ui/main.js | 250 --------------- src/tanks/ui/ui-config.cjs | 90 ++++++ src/tanks/ui/ui-config.js | 90 ------ src/tanks/ui/ui.cjs | 1 + src/tanks/ui/ui.js | 1 - src/tanks/util/config.cjs | 93 ++++++ src/tanks/util/config.js | 93 ------ src/tanks/util/utils.cjs | 15 + src/tanks/util/utils.js | 15 - tanks.php | 40 ++-- 107 files changed, 7413 insertions(+), 7258 deletions(-) delete mode 100644 src/Y/_intro.js delete mode 100644 src/Y/_outro.js create mode 100644 src/Y/alias.cjs delete mode 100644 src/Y/alias.js create mode 100644 src/Y/class.cjs create mode 100644 src/Y/core.cjs delete mode 100644 src/Y/core.js create mode 100644 src/Y/index.cjs create mode 100644 src/Y/op.cjs delete mode 100644 src/Y/to-function.js create mode 100644 src/Y/tofunction.cjs create mode 100644 src/Y/type.cjs delete mode 100644 src/Y/type.js create mode 100644 src/Y/types/array.cjs create mode 100644 src/Y/types/collection.cjs create mode 100644 src/Y/types/function.cjs create mode 100644 src/Y/types/number.cjs create mode 100644 src/Y/types/object.cjs create mode 100644 src/Y/types/string.cjs delete mode 100644 src/Y/y-array.js delete mode 100644 src/Y/y-class.js delete mode 100644 src/Y/y-collection.js delete mode 100644 src/Y/y-core.js delete mode 100644 src/Y/y-function.js delete mode 100644 src/Y/y-number.js delete mode 100644 src/Y/y-object.js delete mode 100644 src/Y/y-op.js delete mode 100644 src/Y/y-string.js create mode 100644 src/Y/y.cjs delete mode 100644 src/easel/layer.js delete mode 100644 src/easel/loop/cooldown.js delete mode 100644 src/easel/loop/eventloop.js delete mode 100644 src/easel/loop/fps.js delete mode 100644 src/easel/math/line.js delete mode 100644 src/easel/math/math.js delete mode 100644 src/easel/math/vec.js delete mode 100644 src/easel/shape/circle.js delete mode 100644 src/easel/shape/line.js delete mode 100644 src/easel/shape/polygon.js delete mode 100644 src/easel/shape/rect.js delete mode 100644 src/easel/shape/shape.js delete mode 100644 src/easel/util/astar.js delete mode 100644 src/easel/util/binaryheap.js delete mode 100644 src/easel/util/graph.js delete mode 100644 src/easel/util/tree/pointquadtree.js delete mode 100644 src/easel/util/tree/quadtree.js delete mode 100644 src/easel/util/tree/rbtree.js create mode 100644 src/ezl/layer.js create mode 100644 src/ezl/loop/cooldown.js create mode 100644 src/ezl/loop/eventloop.js create mode 100644 src/ezl/loop/fps.js create mode 100644 src/ezl/math/line.js create mode 100644 src/ezl/math/math.js create mode 100644 src/ezl/math/rect.cjs create mode 100644 src/ezl/math/vec.js create mode 100644 src/ezl/shape/circle.js create mode 100644 src/ezl/shape/line.js create mode 100644 src/ezl/shape/polygon.js create mode 100644 src/ezl/shape/rect.js create mode 100644 src/ezl/shape/shape.js create mode 100644 src/ezl/util/astar.js create mode 100644 src/ezl/util/binaryheap.js create mode 100644 src/ezl/util/graph.js create mode 100644 src/ezl/util/tree/pointquadtree.js create mode 100644 src/ezl/util/tree/quadtree.js create mode 100644 src/ezl/util/tree/rbtree.js create mode 100644 src/tanks/calc.cjs delete mode 100644 src/tanks/calc.js create mode 100644 src/tanks/config.cjs delete mode 100644 src/tanks/config.js create mode 100644 src/tanks/game.cjs delete mode 100644 src/tanks/game.js create mode 100644 src/tanks/globals.cjs delete mode 100644 src/tanks/globals.js create mode 100644 src/tanks/index.cjs create mode 100644 src/tanks/map/index.cjs create mode 100644 src/tanks/map/level.cjs delete mode 100644 src/tanks/map/level.js delete mode 100644 src/tanks/map/loc.js create mode 100644 src/tanks/map/loc/bbox.cjs create mode 100644 src/tanks/map/loc/index.cjs create mode 100644 src/tanks/map/loc/loc.cjs create mode 100644 src/tanks/map/loc/rect.cjs create mode 100644 src/tanks/map/pathmap.cjs delete mode 100644 src/tanks/map/pathmap.js create mode 100644 src/tanks/map/trajectory.cjs delete mode 100644 src/tanks/map/trajectory.js delete mode 100644 src/tanks/tanks.js create mode 100644 src/tanks/thing/bullet.cjs delete mode 100644 src/tanks/thing/bullet.js create mode 100644 src/tanks/thing/custom-tank.cjs delete mode 100644 src/tanks/thing/custom-tank.js create mode 100644 src/tanks/thing/index.cjs create mode 100644 src/tanks/thing/player.cjs delete mode 100644 src/tanks/thing/player.js create mode 100644 src/tanks/thing/tank.cjs delete mode 100644 src/tanks/thing/tank.js create mode 100644 src/tanks/thing/thing.cjs delete mode 100644 src/tanks/thing/thing.js create mode 100644 src/tanks/ui/grid.cjs delete mode 100644 src/tanks/ui/grid.js create mode 100644 src/tanks/ui/index.cjs create mode 100644 src/tanks/ui/main.cjs delete mode 100644 src/tanks/ui/main.js create mode 100644 src/tanks/ui/ui-config.cjs delete mode 100644 src/tanks/ui/ui-config.js create mode 100644 src/tanks/ui/ui.cjs delete mode 100644 src/tanks/ui/ui.js create mode 100644 src/tanks/util/config.cjs delete mode 100644 src/tanks/util/config.js create mode 100644 src/tanks/util/utils.cjs delete mode 100644 src/tanks/util/utils.js diff --git a/src/Y/_intro.js b/src/Y/_intro.js deleted file mode 100644 index 1fb369f..0000000 --- a/src/Y/_intro.js +++ /dev/null @@ -1,4 +0,0 @@ -(function(){ - -this.Y = Y; - diff --git a/src/Y/_outro.js b/src/Y/_outro.js deleted file mode 100644 index 22a7560..0000000 --- a/src/Y/_outro.js +++ /dev/null @@ -1,2 +0,0 @@ - -})(); diff --git a/src/Y/alias.cjs b/src/Y/alias.cjs new file mode 100644 index 0000000..6898c30 --- /dev/null +++ b/src/Y/alias.cjs @@ -0,0 +1,13 @@ +var undefined +, globals = (function(){ return this; })() +, _Object = globals.Object +, _Function = globals.Function +, _Array = globals.Array +, _String = globals.String +, _Number = globals.Number + +, slice = _Array.prototype.slice +, hasOwn = _Object.prototype.hasOwnProperty +, getProto = _Object.getPrototypeOf +; + diff --git a/src/Y/alias.js b/src/Y/alias.js deleted file mode 100644 index 01249a8..0000000 --- a/src/Y/alias.js +++ /dev/null @@ -1,13 +0,0 @@ -var globals = this -, _Object = globals.Object -, _Function = globals.Function -, _Array = globals.Array -, _String = globals.String -, _Number = globals.Number - -, slice = _Array.prototype.slice -, toString = _Object.prototype.toString -, hasOwn = _Object.prototype.hasOwnProperty -, getProto = _Object.getPrototypeOf -; - diff --git a/src/Y/class.cjs b/src/Y/class.cjs new file mode 100644 index 0000000..9ca59ab --- /dev/null +++ b/src/Y/class.cjs @@ -0,0 +1,229 @@ +// Inspired by John Resig's "Simple Class Inheritence" -- http://ejohn.org/blog/simple-javascript-inheritance/ + +var Y = require('Y').Y +, type = require('Y/type') +, KNOWN_CLASSES = type.type.KNOWN_CLASSES +, classToString = function toString(){ return this.className+"()"; } +; + +// Private delegating constructor -- must be defined for every +// new class to prevent shared state. All construction is +// actually done in the init method. +function _Class() { + var cls = arguments.callee + , instance = this; + + // Not subclassing + if ( cls.caller !== Class.fabricate ) { + if ( instance.init ){ + var result = instance.init.apply(instance, arguments); + if (result) instance = result; + } + } + + return instance; +} + + +/** + * Creates a new class. All classes inherit from Y.Class, and therefore support + * metaprogramming hooks and mixins. + * + * @param {String} className Name of the Class. + * + * @param {Type} [Parent] Parent class for subclassing. If Parent is a subclass of Y.Class + * itself, the new class will inherit directly from Parent. Otherwise, members will be + * copied off the prototype of Parent before applying any new instance members, but the + * new class will not respond to instanceof from Parent. + * + * @param {Object} [members] Instance members to add to the new class's prototype; a class + * constructor can be supplied as `init`. + * + * @returns {Class} A new Class. + */ +function Class(className, Parent, members) { + var ClassFactory = arguments.callee + , SuperClass = ClassFactory + , prototype = this + , parentMembers = {} + ; + + if ( !members && !isFunction(Parent) ) { + members = Parent; + Parent = null; + } + members = members || {}; + Parent = Parent || getProto(members).constructor || ClassFactory; + + if (Parent == ClassFactory) + Parent = Object; + + // Parent is the prototype + if ( !isFunction(Parent) ) { + SuperClass = getProto(Parent).constructor || Object; + prototype = Parent; + + // Parent is a constructor: check ClassFactory + } else if (Parent.prototype instanceof ClassFactory) { + SuperClass = Parent; + prototype = Parent.fabricate(); + + // Recurse so `this` is an instance of ClassFactory + } else if ( !(prototype instanceof ClassFactory) ) { + return new ClassFactory(className, Parent, members); + + } else { + parentMembers = Parent.prototype || {}; + } + + // Creates a new function with the appropriate name + // based on the className. + var NewClass, + constructor = [ + 'var '+className, + (''+_Class).replace(_Class.name, className), + 'NewClass = '+className, '' + ].join(';\n'); + eval(constructor); + + // Copy Class statics + for (var k in ClassFactory) + NewClass[k] = ClassFactory[k]; + + // Copy parent methods, then add new instance methods + for (var k in parentMembers) + prototype[k] = parentMembers[k]; + + if ( prototype.toString === toString ) + prototype.toString = classToString; + + // Fix Constructors, prototypes + NewClass.prototype = NewClass.fn = prototype; + prototype.constructor = prototype.__class__ = NewClass; + NewClass.__super__ = SuperClass; // don't override NewClass.constructor -- it should be Function + NewClass.className = prototype.className = className; + + // Either invoke body constructor... + if ( isFunction(members) ) { + members.call(prototype, NewClass); + + // Or add new instance methods + } else for (var k in members) { + if ( hasOwn.call(members, k) ) + prototype[k] = members[k]; + } + + if (prototype.init) NewClass.init = Y(prototype.init); + + KNOWN_CLASSES[className] = NewClass; + + return NewClass; +} + +// Add metaprogramming data to Class object +Class.__super__ = Object; +Class.fn = Class.prototype; +Class.fn.__class__ = Class; +Class.className = Class.fn.className = "Class"; + + +/* Class Methods */ + +/** + * Create a new instance and run delegate constructor if it exists. + * Unlike the keyword `new`, instantiate can be applied. + */ +Class.instantiate = + function instantiate(){ + var instance = this.fabricate(); + if ( instance.init ) { + var r = instance.init.apply(instance, arguments); + return (r !== undefined ? r : instance); + } else + return instance; + }; + +/** + * Create new instance, but do not run the delegate constructor. + */ +Class.fabricate = + function fabricate(){ + return new this(); + }; + +/** + * Class method of Classes, not to be confused with Y.subclass, which is a static method. + */ +Class.subclass = +Class.fn.subclass = + function subclass(className, members){ + return new Class(className, this, members); + }; + + + +/** + * Root-class for all Y-objects. + */ +var YBase = new Class("YBase", { + __y__ : true +}); + + + + +/// Other Class Utilities /// + +function bindName(v, k){ + if ( isFunction(v) ) + this[k] = Y(v).bind(this); +} +// bindName = Y(bindName).curry(); + +function bindAll(o, names){ + var names = new Y(arguments, 1); + Y(names.size() ? names.generate(Y.op.get(o)) : o).forEach( bindName, o ); + return o; +} + +// Y.chainDelegates = chainDelegates; +function chainDelegates(type, name){ + var names = Y(arguments, 1), + proto = type.prototype; + names.forEach(function(name){ + proto[name] = function(){ + var o = this._o || this; + o[name].apply(o, Y(arguments)); + return this; + }; + }); + return type; +} + +// Y.mixinNames = mixinNames; +function mixinNames(o, Donor, names, override, yWrap){ + var target = ( isFunction(o) ? o.prototype : o) + , proto = ( isFunction(Donor) ? Donor.prototype : Donor); + + // Need a closure to capture the name + names.forEach(function(name){ + if ( isFunction(proto[name]) && (override || !target[name]) ) + target[name] = function(){ + var r = proto[name].apply(this._o || target, arguments); + return (yWrap ? Y(r) : r); + }; + }); + + return o; +} + +exports['Class'] = +exports['subclass'] = Class; +exports['instantiate'] = Class.instantiate.bind(Class); +exports['fabricate'] = Class.fabricate.bind(Class); + +exports['YBase'] = YBase; +exports['bindAll'] = bindAll; +exports['chainDelegates'] = chainDelegates; +exports['mixinNames'] = mixinNames; + diff --git a/src/Y/core.cjs b/src/Y/core.cjs new file mode 100644 index 0000000..83f1594 --- /dev/null +++ b/src/Y/core.cjs @@ -0,0 +1,118 @@ +// Generic Collection Functions + +function notWrapped(fn){ + var self = arguments.callee.caller; + return fn && fn !== self && fn.__wraps__ !== self; +} + +function reduce(o, fn, acc){ + if ( !o ) + return acc; + + fn = Function.toFunction(fn); + var cxt = arguments[3] || o; + if ( notWrapped(o.reduce) ) + return o.reduce.apply(o, [fn, acc, cxt]); + + for ( var name in o ) + acc = fn.call(cxt, acc, o[name], name, o); + + return acc; +} + +function map(o, fn){ + if ( !o ) + return o; + + fn = Function.toFunction(fn); + var acc = {}, cxt = arguments[2] || o; + if ( notWrapped(o.map) ) + return o.map.apply(o, [fn, cxt]); + + for ( var name in o ) + acc[name] = fn.call(cxt, o[name], name, o); + + return acc; +} + +function forEach(o, fn){ + map(o, fn, cxt); + return o; +} + +function filter(o, fn){ + if ( !o ) + return o; + + fn = Function.toFunction(fn); + var acc = {}, cxt = arguments[2] || o; + if ( notWrapped(o.filter) ) + return o.filter.apply(o, [fn, cxt]); + + for ( var name in o ) + if ( fn.call(cxt, o[name], name, o) ) + acc[name] = o[name]; + + return acc; +} + +function set(o, key, value, def){ + if ( o && key !== undefined ){ + if (def === undefined) + def = o[key]; + o[key] = (value !== undefined ? value : def); + } + return o; +} + +function dset(o, key, value, def){ + if ( o && notWrapped(o.set) ) + return o.set.apply(o, slice.call(arguments,1)); + else + return set(o, key, value, def); +} + +function attr(o, key, value, def){ + if ( !o || key === undefined ) return o; + + if ( Y.isPlainObject(key) ) + return extend(o, key); + + if ( value !== undefined || def !== undefined ){ + return dset(o, key, value, def); + } else + return o[key]; +} + +function dattr(o, key, value, def){ + if ( o && notWrapped(o.attr) ) + return o.attr.apply(o, slice.call(arguments,1)); + else + return attr(o, key, value, def); +} + +function extend( A, B ){ + return slice.call(arguments,1).reduce(extendall, A); +} +function extendall(A, donor){ return reduce(donor, attrvk, A); } +function attrvk(o, v, k){ return attr(o, k, v, o[k]); } + +function dextend( A, B ){ + return slice.call(arguments,1).reduce(dextendall, A); +} +function dextendall(A, donor){ return reduce(donor, dattrvk, A); } +function dattrvk(o, v, k){ return dattr(o, k, v, o[k]); } + + +exports['reduce'] = reduce; +exports['map'] = map; +exports['forEach'] = forEach; +exports['filter'] = filter; + +exports['set'] = set; +exports['attr'] = attr; +exports['extend'] = extend; + +exports['dset'] = dset; +exports['dattr'] = dattr; +exports['dextend'] = dextend; diff --git a/src/Y/core.js b/src/Y/core.js deleted file mode 100644 index 9f70f78..0000000 --- a/src/Y/core.js +++ /dev/null @@ -1,102 +0,0 @@ -// Generic Collection Functions - -function notWrapped(fn){ - var self = arguments.callee.caller; - return fn && fn !== self && fn.__wraps__ !== self; -} - -function reduce(o, fn, acc){ - if ( !o ) - return acc; - - fn = Function.toFunction(fn); - var cxt = arguments[3] || o; - if ( notWrapped(o.reduce) ) - return o.reduce.apply(o, [fn, acc, cxt]); - - for ( var name in o ) - acc = fn.call(cxt, acc, o[name], name, o); - - return acc; -} - -function map(o, fn){ - if ( !o ) - return o; - - fn = Function.toFunction(fn); - var acc = {}, cxt = arguments[2] || o; - if ( notWrapped(o.map) ) - return o.map.apply(o, [fn, cxt]); - - for ( var name in o ) - acc[name] = fn.call(cxt, o[name], name, o); - - return acc; -} - -function forEach(o, fn){ - map(o, fn, cxt); -} - -function filter(o, fn){ - if ( !o ) - return o; - - fn = Function.toFunction(fn); - var acc = {}, cxt = arguments[2] || o; - if ( notWrapped(o.filter) ) - return o.filter.apply(o, [fn, cxt]); - - for ( var name in o ) - if ( fn.call(cxt, o[name], name, o) ) - acc[name] = o[name]; - - return acc; -} - -function set(o, key, value, def){ - if ( o && key !== undefined ){ - if (def === undefined) - def = o[key]; - o[key] = (value !== undefined ? value : def); - } - return o; -} - -function dset(o, key, value, def){ - if ( o && notWrapped(o.set) ) - return o.set.apply(o, slice.call(arguments,1)); - else - return set(o, key, value, def); -} - -function attr(o, key, value, def){ - if ( !o || key === undefined ) return o; - - if ( Y.isPlainObject(key) ) - return extend(o, key); - - if ( value !== undefined || def !== undefined ){ - return dset(o, key, value, def); - } else - return o[key]; -} - -function dattr(o, key, value, def){ - if ( o && notWrapped(o.attr) ) - return o.attr.apply(o, slice.call(arguments,1)); - else - return attr(o, key, value, def); -} - -function extend( A, B ){ - return slice.call(arguments,1).reduce(extend._extendall, A); -} -extend._extendall = function _extendall(A, donor){ - return reduce(donor, extend._set, A); -}; -extend._set = function _set(o, v, k){ - return dattr(o, k, v, o[k]); -}; - diff --git a/src/Y/index.cjs b/src/Y/index.cjs new file mode 100644 index 0000000..4b3e16b --- /dev/null +++ b/src/Y/index.cjs @@ -0,0 +1,71 @@ + +/// Import our external deps first /// +require('lessly/future'); +require('functional/to-function'); + +/// Set up core and utilities /// +var core = require('Y/core') +, type = require('Y/type') +, Y = require('Y/y').Y +; + +exports['Y'] = Y; + +// Copy all our type utils onto the type function, as it has the +// same name as its namespace +core.extend(type.type, type); + +// Attach core & type to Y +core.extend(Y, core, type); + +// Make top-level setters refer to the delegating versions +Y['core'] = core; +Y['set'] = core.dset; +Y['attr'] = core.dattr; +Y['extend'] = core.dextend; + + +/// Patch modules that weren't available earlier /// + +// Attach YFunction methods to library functions +var yfn = require('Y/types/function') +, YFunction = Y['YFunction'] = yfn.YFunction ; + +YFunction(Y); +core.forEach(core, YFunction); +YFunction(Y.type); +Y['is'] = YFunction(Y.is).curry(); + +addNames('curry methodize genericize compose chain memoize', yfn); + +// Curry all operators +var op = require('Y/op'); +core.forEach(op, YFunction); +Y['op'] = op.extend({}, core.map(yfn.curry, op)); +// Y['op'] = core.reduce(op, function(Yop, fn, k){ +// Yop[k] = yfn.curry(fn); +// return Yop; +// }, {}); + +// var yclass = require('Y/types/class'); +addNames('Class subclass instantiate fabricate YBase', + require('Y/class')); + + +/// Now start assembling the normal sub-modules /// +addNames('YCollection', require('Y/types/collection')); +addNames('YArray', require('Y/types/array')); +addNames('YObject', require('Y/types/object')); +addNames('YString', require('Y/types/string')); +addNames('YNumber range', require('Y/types/number')); + +// var ycollection = require('Y/types/collection') +// , yarray = require('Y/types/array') +// , yobject = require('Y/types/object') +// , ystring = require('Y/types/string') +// , ynumber = require('Y/types/number') +// ; + + +function addName(name){ Y[name] = this[name]; } +function addNames(names, ns){ names.split(' ').forEach(addName, ns); } diff --git a/src/Y/op.cjs b/src/Y/op.cjs new file mode 100644 index 0000000..97ef023 --- /dev/null +++ b/src/Y/op.cjs @@ -0,0 +1,78 @@ +/* A subset of the functional operators, used in Y's core */ + +var Y = require('Y').Y +, core = require('Y/core') +, op = { // XXX: Make these function statements? + + // comparison + cmp: function(x,y){ return x == y ? 0 : (x > y ? 1 : -1); }, + eq: function(x,y){ return x == y; }, + ne: function(x,y){ return x != y; }, + gt: function(x,y){ return x > y; }, + ge: function(x,y){ return x >= y; }, + lt: function(x,y){ return x < y; }, + le: function(x,y){ return x <= y; }, + + // math + add: function(x,y){ return x + y; }, + sub: function(x,y){ return x - y; }, + mul: function(x,y){ return x * y; }, + div: function(x,y){ return x / y; }, + flrdiv: function(x,y){ return Math.floor(x / y); }, + mod: function(x,y){ return x % y; }, + + // logic + and: function(x,y){ return x && y; }, + or: function(x,y){ return x || y; }, + xor: function(x,y){ return x != y; }, + not: function(x){ return !x; }, + neg: function(x){ return -x; }, + + // bitwise + bitnot: function(x){ return ~x; }, + bitand: function(x,y){ return x & y; }, + bitor: function(x,y){ return x | y; }, + bitxor: function(x,y){ return x ^ y; }, + lshift: function(x,y){ return x << y; }, + rshift: function(x,y){ return x >> y; }, + zrshift: function(x,y){ return x >>> y; }, + + // values + nop: function(x){}, + I: function(x){ return x; }, + K: function(k){ return function(){ return k; }; }, + val: function(def,o){ return o !== undefined ? o : def; }, + ok: function(o){ return o !== undefined && o !== null; }, + + // reduce-ordered values & accessors + khas: function(k,o){ return k in o; }, + kget: function(k,o){ return o[k] }, + defkget: function(def,k,o){ return (k in o ? o[k] : def); }, + vkset: function(o,v,k){ if (o && k !== undefined) o[k] = v; return o; }, + + // curry-ordered values & accessors + has: function(o,k){ return k in o; }, + get: function(o,k){ return o[k] }, + getdef: function(o,k,def){ return (k in o ? o[k] : def); }, + set: core.set, // set( o, key, value, def ) + attr: core.attr, // attr( o, key, value, def ) + method: function(name){ + var args = Y(arguments,1); + return function(obj){ + if (obj && obj[name]) + return obj[name].apply( obj, args.concat(Y(arguments)) ); + else + return obj; + }; + }, + extend : function extend(A,B){ + return slice.call(arguments,1).reduce(extender, A); + } + +}; + +function extender(target, donor){ + return core.reduce(donor, op.vkset, target); +} + +core.extend(exports, op); diff --git a/src/Y/to-function.js b/src/Y/to-function.js deleted file mode 100644 index 936376b..0000000 --- a/src/Y/to-function.js +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Author: Oliver Steele - * Copyright: Copyright 2007 by Oliver Steele. All rights reserved. - * License: MIT License - * Homepage: http://osteele.com/javascripts/functional - * Created: 2007-07-11 - * Version: 1.0.2 - * - * - * This defines "string lambdas", that allow strings such as `x+1` and - * `x -> x+1` to be used in some contexts as functions. - */ - - -/// ^ String lambdas - -/** - * Turns a string that contains a JavaScript expression into a - * `Function` that returns the value of that expression. - * - * If the string contains a `->`, this separates the parameters from the body: - * >> 'x -> x + 1'.lambda()(1) -> 2 - * >> 'x y -> x + 2*y'.lambda()(1, 2) -> 5 - * >> 'x, y -> x + 2*y'.lambda()(1, 2) -> 5 - * - * Otherwise, if the string contains a `_`, this is the parameter: - * >> '_ + 1'.lambda()(1) -> 2 - * - * Otherwise if the string begins or ends with an operator or relation, - * prepend or append a parameter. (The documentation refers to this type - * of string as a "section".) - * >> '/2'.lambda()(4) -> 2 - * >> '2/'.lambda()(4) -> 0.5 - * >> '/'.lambda()(2,4) -> 0.5 - * Sections can end, but not begin with, `-`. (This is to avoid interpreting - * e.g. `-2*x` as a section). On the other hand, a string that either begins - * or ends with `/` is a section, so an expression that begins or ends with a - * regular expression literal needs an explicit parameter. - * - * Otherwise, each variable name is an implicit parameter: - * >> 'x + 1'.lambda()(1) -> 2 - * >> 'x + 2*y'.lambda()(1, 2) -> 5 - * >> 'y + 2*x'.lambda()(1, 2) -> 5 - * - * Implicit parameter detection ignores strings literals, variable names that - * start with capitals, and identifiers that precede `:` or follow `.`: - * >> map('"im"+root', ["probable", "possible"]) -> ["improbable", "impossible"] - * >> 'Math.cos(angle)'.lambda()(Math.PI) -> -1 - * >> 'point.x'.lambda()({x:1, y:2}) -> 1 - * >> '({x:1, y:2})[key]'.lambda()('x') -> 1 - * - * Implicit parameter detection mistakenly looks inside regular expression - * literals for variable names. It also doesn't know to ignore JavaScript - * keywords and bound variables. (The only way you can get these last two is - * with a function literal inside the string. This is outside the intended use - * case for string lambdas.) - * - * Use `_` (to define a unary function) or `->`, if the string contains anything - * that looks like a free variable but shouldn't be used as a parameter, or - * to specify parameters that are ordered differently from their first - * occurrence in the string. - * - * Chain `->`s to create a function in uncurried form: - * >> 'x -> y -> x + 2*y'.lambda()(1)(2) -> 5 - * >> 'x -> y -> z -> x + 2*y+3*z'.lambda()(1)(2)(3) -> 14 - * - * `this` and `arguments` are special: - * >> 'this'.call(1) -> 1 - * >> '[].slice.call(arguments, 0)'.call(null,1,2) -> [1, 2] - */ -String.prototype.lambda = function() { - var params = [], - expr = this, - sections = expr.ECMAsplit(/\s*->\s*/m); - if (sections.length > 1) { - while (sections.length) { - expr = sections.pop(); - params = sections.pop().split(/\s*,\s*|\s+/m); - sections.length && sections.push('(function('+params+'){return ('+expr+')})'); - } - } else if (expr.match(/\b_\b/)) { - params = '_'; - } else { - // test whether an operator appears on the left (or right), respectively - var leftSection = expr.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m), - rightSection = expr.match(/[+\-*\/%&|\^\.=<>!]\s*$/m); - if (leftSection || rightSection) { - if (leftSection) { - params.push('$1'); - expr = '$1' + expr; - } - if (rightSection) { - params.push('$2'); - expr = expr + '$2'; - } - } else { - // `replace` removes symbols that are capitalized, follow '.', - // precede ':', are 'this' or 'arguments'; and also the insides of - // strings (by a crude test). `match` extracts the remaining - // symbols. - var vars = this.replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*\s*:|this|arguments|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, '').match(/([a-z_$][a-z_$\d]*)/gi) || []; // ' - for (var i = 0, v; v = vars[i++]; ) - params.indexOf(v) >= 0 || params.push(v); - } - } - return new Function(params, 'return (' + expr + ')'); - // return eval('(function('+params+'){return ('+expr+'); })'); -} - -/// Turn on caching for `string` -> `Function` conversion. -String.prototype.lambda.cache = function() { - var proto = String.prototype, - cache = {}, - uncached = proto.lambda, - cached = function() { - var key = '#' + this; // avoid hidden properties on Object.prototype - return cache[key] || (cache[key] = uncached.call(this)); - }; - cached.cached = function(){}; - cached.uncache = function(){proto.lambda = uncached}; - proto.lambda = cached; -} - -/** - * ^^ Duck-Typing - * - * Strings support `call` and `apply`. This duck-types them as - * functions, to some callers. - */ - -/** - * Coerce the string to a function and then apply it. - * >> 'x+1'.apply(null, [2]) -> 3 - * >> '/'.apply(null, [2, 4]) -> 0.5 - */ -String.prototype.apply = function(thisArg, args) { - return this.toFunction().apply(thisArg, args); -} - -/** - * Coerce the string to a function and then call it. - * >> 'x+1'.call(null, 2) -> 3 - * >> '/'.call(null, 2, 4) -> 0.5 - */ -String.prototype.call = function() { - return this.toFunction().apply(arguments[0], - Array.prototype.slice.call(arguments, 1)); -} - -/// ^^ Coercion - -/** - * Returns a `Function` that perfoms the action described by this - * string. If the string contains a `return`, applies - * `new Function` to it. Otherwise, this function returns - * the result of `this.lambda()`. - * >> '+1'.toFunction()(2) -> 3 - * >> 'return 1'.toFunction()(1) -> 1 - */ -String.prototype.toFunction = function() { - var body = this; - if (body.match(/\breturn\b/)) - return new Function(this); - return this.lambda(); -} - -/** - * Returns this function. `Function.toFunction` calls this. - * >> '+1'.lambda().toFunction()(2) -> 3 - */ -Function.prototype.toFunction = function() { - return this; -} - -/** - * Coerces `fn` into a function if it is not already one, - * by calling its `toFunction` method. - * >> Function.toFunction(function() {return 1})() -> 1 - * >> Function.toFunction('+1')(2) -> 3 - * - * `Function.toFunction` requires an argument that can be - * coerced to a function. A nullary version can be - * constructed via `guard`: - * >> Function.toFunction.guard()('1+') -> function() - * >> Function.toFunction.guard()(null) -> null - * - * `Function.toFunction` doesn't coerce arbitrary values to functions. - * It might seem convenient to treat - * `Function.toFunction(value)` as though it were the - * constant function that returned `value`, but it's rarely - * useful and it hides errors. Use `Functional.K(value)` instead, - * or a lambda string when the value is a compile-time literal: - * >> Functional.K('a string')() -> "a string" - * >> Function.toFunction('"a string"')() -> "a string" - */ -Function.toFunction = function(value) { - return value.toFunction(); -} - -// Utilities - -// IE6 split is not ECMAScript-compliant. This breaks '->1'.lambda(). -// ECMAsplit is an ECMAScript-compliant `split`, although only for -// one argument. -String.prototype.ECMAsplit = - // The test is from the ECMAScript reference. - ('ab'.split(/a*/).length > 1 - ? String.prototype.split - : function(separator, limit) { - if (typeof limit != 'undefined') - throw "ECMAsplit: limit is unimplemented"; - var result = this.split.apply(this, arguments), - re = RegExp(separator), - savedIndex = re.lastIndex, - match = re.exec(this); - if (match && match.index == 0) - result.unshift(''); - // in case `separator` was already a RegExp: - re.lastIndex = savedIndex; - return result; - }); diff --git a/src/Y/tofunction.cjs b/src/Y/tofunction.cjs new file mode 100644 index 0000000..936376b --- /dev/null +++ b/src/Y/tofunction.cjs @@ -0,0 +1,221 @@ +/* + * Author: Oliver Steele + * Copyright: Copyright 2007 by Oliver Steele. All rights reserved. + * License: MIT License + * Homepage: http://osteele.com/javascripts/functional + * Created: 2007-07-11 + * Version: 1.0.2 + * + * + * This defines "string lambdas", that allow strings such as `x+1` and + * `x -> x+1` to be used in some contexts as functions. + */ + + +/// ^ String lambdas + +/** + * Turns a string that contains a JavaScript expression into a + * `Function` that returns the value of that expression. + * + * If the string contains a `->`, this separates the parameters from the body: + * >> 'x -> x + 1'.lambda()(1) -> 2 + * >> 'x y -> x + 2*y'.lambda()(1, 2) -> 5 + * >> 'x, y -> x + 2*y'.lambda()(1, 2) -> 5 + * + * Otherwise, if the string contains a `_`, this is the parameter: + * >> '_ + 1'.lambda()(1) -> 2 + * + * Otherwise if the string begins or ends with an operator or relation, + * prepend or append a parameter. (The documentation refers to this type + * of string as a "section".) + * >> '/2'.lambda()(4) -> 2 + * >> '2/'.lambda()(4) -> 0.5 + * >> '/'.lambda()(2,4) -> 0.5 + * Sections can end, but not begin with, `-`. (This is to avoid interpreting + * e.g. `-2*x` as a section). On the other hand, a string that either begins + * or ends with `/` is a section, so an expression that begins or ends with a + * regular expression literal needs an explicit parameter. + * + * Otherwise, each variable name is an implicit parameter: + * >> 'x + 1'.lambda()(1) -> 2 + * >> 'x + 2*y'.lambda()(1, 2) -> 5 + * >> 'y + 2*x'.lambda()(1, 2) -> 5 + * + * Implicit parameter detection ignores strings literals, variable names that + * start with capitals, and identifiers that precede `:` or follow `.`: + * >> map('"im"+root', ["probable", "possible"]) -> ["improbable", "impossible"] + * >> 'Math.cos(angle)'.lambda()(Math.PI) -> -1 + * >> 'point.x'.lambda()({x:1, y:2}) -> 1 + * >> '({x:1, y:2})[key]'.lambda()('x') -> 1 + * + * Implicit parameter detection mistakenly looks inside regular expression + * literals for variable names. It also doesn't know to ignore JavaScript + * keywords and bound variables. (The only way you can get these last two is + * with a function literal inside the string. This is outside the intended use + * case for string lambdas.) + * + * Use `_` (to define a unary function) or `->`, if the string contains anything + * that looks like a free variable but shouldn't be used as a parameter, or + * to specify parameters that are ordered differently from their first + * occurrence in the string. + * + * Chain `->`s to create a function in uncurried form: + * >> 'x -> y -> x + 2*y'.lambda()(1)(2) -> 5 + * >> 'x -> y -> z -> x + 2*y+3*z'.lambda()(1)(2)(3) -> 14 + * + * `this` and `arguments` are special: + * >> 'this'.call(1) -> 1 + * >> '[].slice.call(arguments, 0)'.call(null,1,2) -> [1, 2] + */ +String.prototype.lambda = function() { + var params = [], + expr = this, + sections = expr.ECMAsplit(/\s*->\s*/m); + if (sections.length > 1) { + while (sections.length) { + expr = sections.pop(); + params = sections.pop().split(/\s*,\s*|\s+/m); + sections.length && sections.push('(function('+params+'){return ('+expr+')})'); + } + } else if (expr.match(/\b_\b/)) { + params = '_'; + } else { + // test whether an operator appears on the left (or right), respectively + var leftSection = expr.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m), + rightSection = expr.match(/[+\-*\/%&|\^\.=<>!]\s*$/m); + if (leftSection || rightSection) { + if (leftSection) { + params.push('$1'); + expr = '$1' + expr; + } + if (rightSection) { + params.push('$2'); + expr = expr + '$2'; + } + } else { + // `replace` removes symbols that are capitalized, follow '.', + // precede ':', are 'this' or 'arguments'; and also the insides of + // strings (by a crude test). `match` extracts the remaining + // symbols. + var vars = this.replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*\s*:|this|arguments|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, '').match(/([a-z_$][a-z_$\d]*)/gi) || []; // ' + for (var i = 0, v; v = vars[i++]; ) + params.indexOf(v) >= 0 || params.push(v); + } + } + return new Function(params, 'return (' + expr + ')'); + // return eval('(function('+params+'){return ('+expr+'); })'); +} + +/// Turn on caching for `string` -> `Function` conversion. +String.prototype.lambda.cache = function() { + var proto = String.prototype, + cache = {}, + uncached = proto.lambda, + cached = function() { + var key = '#' + this; // avoid hidden properties on Object.prototype + return cache[key] || (cache[key] = uncached.call(this)); + }; + cached.cached = function(){}; + cached.uncache = function(){proto.lambda = uncached}; + proto.lambda = cached; +} + +/** + * ^^ Duck-Typing + * + * Strings support `call` and `apply`. This duck-types them as + * functions, to some callers. + */ + +/** + * Coerce the string to a function and then apply it. + * >> 'x+1'.apply(null, [2]) -> 3 + * >> '/'.apply(null, [2, 4]) -> 0.5 + */ +String.prototype.apply = function(thisArg, args) { + return this.toFunction().apply(thisArg, args); +} + +/** + * Coerce the string to a function and then call it. + * >> 'x+1'.call(null, 2) -> 3 + * >> '/'.call(null, 2, 4) -> 0.5 + */ +String.prototype.call = function() { + return this.toFunction().apply(arguments[0], + Array.prototype.slice.call(arguments, 1)); +} + +/// ^^ Coercion + +/** + * Returns a `Function` that perfoms the action described by this + * string. If the string contains a `return`, applies + * `new Function` to it. Otherwise, this function returns + * the result of `this.lambda()`. + * >> '+1'.toFunction()(2) -> 3 + * >> 'return 1'.toFunction()(1) -> 1 + */ +String.prototype.toFunction = function() { + var body = this; + if (body.match(/\breturn\b/)) + return new Function(this); + return this.lambda(); +} + +/** + * Returns this function. `Function.toFunction` calls this. + * >> '+1'.lambda().toFunction()(2) -> 3 + */ +Function.prototype.toFunction = function() { + return this; +} + +/** + * Coerces `fn` into a function if it is not already one, + * by calling its `toFunction` method. + * >> Function.toFunction(function() {return 1})() -> 1 + * >> Function.toFunction('+1')(2) -> 3 + * + * `Function.toFunction` requires an argument that can be + * coerced to a function. A nullary version can be + * constructed via `guard`: + * >> Function.toFunction.guard()('1+') -> function() + * >> Function.toFunction.guard()(null) -> null + * + * `Function.toFunction` doesn't coerce arbitrary values to functions. + * It might seem convenient to treat + * `Function.toFunction(value)` as though it were the + * constant function that returned `value`, but it's rarely + * useful and it hides errors. Use `Functional.K(value)` instead, + * or a lambda string when the value is a compile-time literal: + * >> Functional.K('a string')() -> "a string" + * >> Function.toFunction('"a string"')() -> "a string" + */ +Function.toFunction = function(value) { + return value.toFunction(); +} + +// Utilities + +// IE6 split is not ECMAScript-compliant. This breaks '->1'.lambda(). +// ECMAsplit is an ECMAScript-compliant `split`, although only for +// one argument. +String.prototype.ECMAsplit = + // The test is from the ECMAScript reference. + ('ab'.split(/a*/).length > 1 + ? String.prototype.split + : function(separator, limit) { + if (typeof limit != 'undefined') + throw "ECMAsplit: limit is unimplemented"; + var result = this.split.apply(this, arguments), + re = RegExp(separator), + savedIndex = re.lastIndex, + match = re.exec(this); + if (match && match.index == 0) + result.unshift(''); + // in case `separator` was already a RegExp: + re.lastIndex = savedIndex; + return result; + }); diff --git a/src/Y/type.cjs b/src/Y/type.cjs new file mode 100644 index 0000000..0063683 --- /dev/null +++ b/src/Y/type.cjs @@ -0,0 +1,115 @@ +// Type Utilities // +// Much borrowed from jQuery + +var undefined +, globals = (function(){ return this; })() +, _Object = globals.Object +, _Function = globals.Function +, _Array = globals.Array +, _String = globals.String +, _Number = globals.Number + +, FN = "constructor" +, PT = "prototype" +, OP = _Object[PT] + +, slice = _Array[PT].slice +, getProto = _Object.getPrototypeOf +, hasOwn = OP.hasOwnProperty +, toString = OP.toString +, hasOwn = OP.hasOwnProperty + +, KNOWN_CLASSES = {} +; + +var class2name = + "Boolean Number String Function Array Date RegExp Object" + .split(" ") + .reduce(function(class2name, name) { + class2name[ "[object "+name+"]" ] = name.toLowerCase(); + return class2name; + }, {}); + +function type_of(obj){ + return obj == null ? + String( obj ) : + class2name[ toString.call(obj) ] || "object"; +} + +isArray.types = []; +function isArray(obj) { return type_of(obj) === "array" || obj instanceof Y.YArray; } +function isFunction(obj) { return type_of(obj) === "function"; } +function isString(obj) { return type_of(obj) === "string"; } +function isNumber(obj) { return type_of(obj) === "number"; } +function isWindow(obj) { return obj && typeof obj === "object" && "setInterval" in obj; } + +function isPlainObject( obj ){ + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || type_of(obj) !== "object" || obj.nodeType || isWindow(obj) ) + return false; + + // Not own constructor property must be Object + if ( obj[FN] && + !hasOwn.call(obj, FN) && + !hasOwn.call(obj[FN][PT], "isPrototypeOf") ) + return false; + + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); +} + +function type( o ) { + switch ( typeof(o) ) { + case "undefined" : return undefined; + case "string" : return _String; + case "number" : return _Number; // Note: NaN and Infinity are Number literals + case "boolean" : return _Boolean; + + case "function" : + // If the function has a user-specified prototype, we can probably assume + // it's meant to be a class constructor (and therefore, a type) + if ( o[PT] && o[PT] !== _Function[PT] ) + return o; + else + return _Function; + + case "object" : + default : + // Null is an object, obv + if ( o === null ) + return null; + + return KNOWN_CLASSES[o.className] || o.__class__ + || (o[FN] && o[FN] !== _Object) ? o[FN] : _Object; + } +} + +function is( A, B ){ + if ( isArray(B) ) + return B.map( Y.is(A) ).any(); + else { + var AT = type(A), BT = type(B); + return (A instanceof BT || B instanceof AT || AT === BT); + } +} + +exports['is'] = is; +exports['type'] = type; +exports['type_of'] = type_of; + +exports['isArray'] = isArray; +exports['isFunction'] = isFunction; +exports['isString'] = isString; +exports['isNumber'] = isNumber; +exports['isWindow'] = isWindow; +exports['isPlainObject'] = isPlainObject; + +type['KNOWN_CLASSES'] = KNOWN_CLASSES; + diff --git a/src/Y/type.js b/src/Y/type.js deleted file mode 100644 index a4be9df..0000000 --- a/src/Y/type.js +++ /dev/null @@ -1,80 +0,0 @@ -// Type Utilities // -// Much borrowed from jQuery - -var class2name = - "Boolean Number String Function Array Date RegExp Object" - .split(" ") - .reduce(function(class2name, name) { - class2name[ "[object "+name+"]" ] = name.toLowerCase(); - return class2name; - }, {}) -; - -function type_of(obj){ - return obj == null ? - String( obj ) : - class2name[ toString.call(obj) ] || "object"; -} - -function isArray(obj) { return type_of(obj) === "array" || obj instanceof Y.YArray; } -function isFunction(obj) { return type_of(obj) === "function"; } -function isString(obj) { return type_of(obj) === "string"; } -function isNumber(obj) { return type_of(obj) === "number"; } -function isWindow(obj) { return obj && typeof obj === "object" && "setInterval" in obj; } - -function isPlainObject( obj ){ - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || type_of(obj) !== "object" || obj.nodeType || isWindow(obj) ) - return false; - - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) - return false; - - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - var key; - for ( key in obj ) {} - - return key === undefined || hasOwn.call( obj, key ); -} - -function type( o ) { - switch ( typeof(o) ) { - case "undefined" : return undefined; - case "string" : return String; - case "number" : return Number; // Note: NaN and Infinity are Number literals - case "boolean" : return Boolean; - - case "function" : - // If the function has a user-specified prototype, we can probably assume - // it's meant to be a class constructor (and therefore, a type) - if ( o.prototype && o.prototype !== Function.prototype ) - return o; - else - return Function; - - case "object" : - default : - // Null is an object, obv - if ( o === null ) - return null; - - return KNOWN_CLASSES[o.className] || o.__class__ - || (o.constructor && o.constructor !== Object) ? o.constructor : Object; - } -} - -function is( A, B ){ - if ( isArray(B) ) - return B.map( Y.is(A) ).any(); - else { - var AT = type(A), BT = type(B); - return (A instanceof BT || B instanceof AT || AT === BT); - } -} diff --git a/src/Y/types/array.cjs b/src/Y/types/array.cjs new file mode 100644 index 0000000..18b50e3 --- /dev/null +++ b/src/Y/types/array.cjs @@ -0,0 +1,102 @@ +var Y = require('Y').Y; + +exports['YArray'] = +Y.YCollection.subclass('YArray', function(YArray){ + var yclass = require('Y/class'); + + yclass.chainDelegates(YArray, 'push', 'unshift', 'sort', 'splice', 'reverse'); + yclass.mixinNames(YArray, Array, ['reduce', 'map', 'forEach', 'filter', 'slice', 'some', 'every'], true, true); + yclass.mixinNames(YArray, Array, ['indexOf', 'lastIndexOf', 'shift', 'pop', 'join'], true, false); + + + + + this.init = function(o){ + // YCollection.init.call(this, o || []); + this._o = o || []; + }; + + this.merge = + this.concat = + function concat( donor ){ + var A = this._o; + new Y(arguments).forEach(function( donor ){ + A = A.concat(donor instanceof YArray ? donor.end() : donor); + }); + return Y(A); + }; + + this.remove = + function remove(v){ + if (arguments.length > 1) + Y(arguments).forEach(this.remove, this); + else { + var idx = this.indexOf(v); + if ( idx != -1 ) + this.splice(idx, 1); + } + return this; + }; + + this.last = + function last(){ + var A = this._o; + return A[ A.length-1 ]; + }; + + this.unique = + function unique(){ + return this.reduce( + function(acc, v, i){ + if (acc.indexOf(v) === -1) + acc.push(v); + return acc; + + }, new YArray() ); + + // return this.filter(function(v, i){ + // // Executes in the context of the new array, so + // // `this.indexOf` is checking what we've already + // // collected. + // return (this.indexOf(v) === -1); + // }); + }; + + // Like map, but produces a dict + // Y(["Foo?", "R&D"]).generate(encodeURIComponent) + // -> Y({"Foo?":"Foo%3F", "R&D":"R%26D"}) + this.generate = + function generate(fn, acc){ + var args = Y(arguments), + fn = args.shift(), + acc = args.shift(); + return this.reduce(function(acc, v, i){ + return acc.attr(v, fn.apply( this, [v].concat(args) )); + }, Y(acc || {})); + }; + + // Y([ ["foo", 1], ["bar", 2] ]).toDict() + // -> Y({foo:1, bar:2}) + this.toDict = + function toDict(){ + + }; + + this.clone = + function clone(){ + return Y(this._o.slice(0)); + }; + + this.size = + function size(){ + return this._o.length; + }; + + this.toString = + function toString(){ + return "Y[" + (this._o || "") + "]"; + }; + + return this; +}); + diff --git a/src/Y/types/collection.cjs b/src/Y/types/collection.cjs new file mode 100644 index 0000000..669f942 --- /dev/null +++ b/src/Y/types/collection.cjs @@ -0,0 +1,134 @@ +/** YCollection is the core of Y. */ + +var Y = require('Y').Y +, isFunction = require('Y/type').isFunction +, extend = require('Y/core').extend +, bool = require('Y/op').bool +; + + +function extendY(){ + extend.apply(this, [this._o].concat(Y(arguments))); + return this; +} + +exports['YCollection'] = +Y.YBase.subclass('YCollection', { + 'init' : function(o){ + this._o = o || {}; + }, + + 'attr' : function attr(k, v, def){ + var r = Y.attr(this._o, k, v, def); + if (r === this._o) + return this; + else + return r; + }, + 'extend' : extendY, + 'merge' : extendY, + 'concat' : extendY, + + 'end' : function end(){ return this._o; }, + + 'reduce' : function reduce( fn, acc, context ){ + var o = this._o || this, + acc = acc || new o.constructor(); + for ( var name in o ) + acc = fn.call( context || this, acc, o[name], name, o ); + return acc; + }, + + 'map' : function map( fn, context ){ + var o = this._o, acc = new o.constructor(); + for ( var name in o ) + acc[name] = fn.call( context || this, o[name], name, o ); + return acc; + }, + + 'forEach' : function forEach( fn, context ){ + var o = this._o; + for ( var name in o ) + fn.call( context || this, o[name], name, o ); + }, + + 'filter' : function filter( fn, context ){ + var o = this._o, acc = new o.constructor(); + for ( var name in o ) + if ( fn.call( context || this, o[name], name, o ) ) + acc[name] = o[name]; + return acc; + }, + + 'indexOf' : function indexOf( value ){ + var o = this._o; + for ( var name in o ) + if ( o[name] === value ) + return name; + return -1; + }, + + 'has' : function has( value ){ + return ( this.indexOf(value) !== -1 ); + }, + + 'clone' : function clone(){ + return Y({}).extend(this); + }, + + 'remove' : function remove(v){ + var o = this._o + , toRemove = new Y(arguments); + + for (var k in o) { + var v = o[k]; + if ( toRemove.has(v) ) { + delete o[k]; + toRemove.remove(v); + } + } + return this; + }, + + 'every' : function every( fn ){ + var self = this, fn = fn || bool; + return this.reduce(function(acc, v, k, o){ + return acc && fn.call(self, v, k, o); + }, true); + }, + + 'any' : function any( fn ){ + var self = this, fn = fn || bool; + return this.reduce(function(acc, v, k, o){ + return acc || fn.call(self, v, k, o); + }, false); + }, + + 'zip' : function zip(){ + var sequences = new Y(arguments).map( Y.limit(1) ).unshift(this); + return this.map(function(_, k){ + return sequences.invoke('attr', k); + }).invoke('end'); + }, + + 'pluck' : function pluck(key){ + return this.map(function(v){ + return v && (isFunction(v.attr) ? v.attr(key) : v[key]); + }); + }, + + 'invoke' : function invoke(name){ + var args = Y(arguments), + name = args.shift(); + return this.map(function(o){ + return o && o[name].apply(o, args); + }); + }, + + 'apply' : function apply(name, args){ + return this[name].apply(this, args); + } + +}); + + diff --git a/src/Y/types/function.cjs b/src/Y/types/function.cjs new file mode 100644 index 0000000..f354cb3 --- /dev/null +++ b/src/Y/types/function.cjs @@ -0,0 +1,308 @@ +var undefined +, WRAPS = "__wraps__" +, globals = (function(){ return this; })() + +, Y = require('Y').Y +, core = require('Y/core') +, type = require('Y/type') + +, isNumber = type.isNumber +, isFunction = type.isFunction +, isArray = type.isArray +, isPlainObject = type.isPlainObject + +, _ = exports._ = YFunction._ = {} +, YFP = YFunction.prototype +; + +function YFunction(fn){ + fn = fn || function(){}; + + if (fn.__y__) + return fn; + + fn.__y__ = true; + + for (var k in YFP) { + var v = YFP[k]; + if ( isFunction(v) && (k == 'bind' || !fn[k]) ) + fn[k] = v; + } + return fn; +} + +core.extend( YFP, { + init : YFunction, + attr : methodize(core.attr), + reduce : methodize(core.reduce), + extend : methodize(core.extend), + end : function end(){ return this; } +}); + + + + +function unwrap(fn){ + return ( fn && isFunction(fn) ) ? unwrap(fn[WRAPS]) || fn : fn; +} + +function curry(fn){ + if (fn.__curried__) + return fn.apply(this, Y(arguments,1)); + + fn = Function.toFunction(fn); + 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; +} + + +function methodize(fn) { + fn = fn.toFunction(); + var g = fn.__genericized__ + , m = fn.__methodized__ ; + if (m) return m; + if (g && g[WRAPS]) return g[WRAPS]; + + m = fn.__methodized__ = + function methodized(){ + return fn.apply(this, [this].concat( Y(arguments) )); + }; + m[WRAPS] = fn; + return m; +} + +function genericize( fn ) { + fn = fn.toFunction(); + var g = fn.__genericized__ + , m = fn.__methodized__ ; + if (g) return g; + if (m && m[WRAPS]) return m[WRAPS]; + + g = fn.__genericized__ = + function genericized(){ + var args = Y(arguments); + return fn.apply(args.shift(), args); + }; + g[WRAPS] = fn; + return g; +}; + + + +function _composer(x,fn){ return fn.call(this, x); } +function compose(f,g){ + var fns = Y(arguments).map(Function.toFunction); + return function(){ + return fns.reduce(_composer, Y(arguments), this); + }; +} + +function chain(f,g){ + var fns = Y(arguments).map(Function.toFunction); + + if ( g.__sequence__ ) + fns = g.__sequence__.concat( fns.slice(1) ); + + function chained(){ + var args = Y(arguments) + , i = fns.length; + while (i-- > 0) args = fns[i].call(this, x); + return args; + } + + chained.__sequence__ = fns; + return chained; +} + +// YFunction.prototype.lazy = methodize(lazy); +// function lazy(fn){ +// var args = Y(arguments, 1) +// , L = unwrap(fn).length +// , lazied = function(){ +// var _args = Y(arguments) +// , f = _args[0]; +// +// if ( isFunction(f) ) { +// var lazied = arguments.callee.compose(_args.shift()); +// if (_args.length !== 0) +// return lazied.lazy.apply(lazied, _args); +// } +// +// args.splice.apply(args, [args.length, 0].concat(_args)); +// if ( args.length >= L ) +// return fn.apply(this, args); +// else +// return arguments.callee; +// } +// ; +// lazied[WRAPS] = fn; +// lazied.__args = args; +// return lazied(); +// } + + +var _bind = _Function.prototype.bind; +function bind(fn, context, args){ + var bound = _bind.apply(fn, Y(arguments,1)); + bound[WRAPS] = fn; + return YFunction(bound); +} + + +// Remembers arguments but obeys current context +function partial(fn){ + var args = Y(arguments,1) + , partially = + function partially(){ + return fn.apply( this, args.concat(Y(arguments)) ); + }; + partially[WRAPS] = fn; + return YFunction(partially); +} + + +// Only works for arguments whose toString is unique and stateless (for example, primitives, but not closures). +// XXX: hashCode() + +/** + * @param {Function} fn Function to memorize. + * @param {Array -> String} [keyfn] Serializes an array of arguments to a string. By default, joins with three nulls. + * @param {Object} [cacher] Object on which to store the memorization cache for lookups. Useful for meta-caches. Defaults to the memorized function. + * @param {String} [cacheName="cache"] Property this cache will be stored under. + */ +function memoize(fn){ + if (fn.__memoized__) return fn.__memoized__; + + var m = + fn.__memoized__ = + function memorizer(){ + // toJSON would be a better alternative, but that won't work cross-browser + var key = Y(arguments).join('\0\0\0') + , cache = arguments.callee.cache; + if ( !(key in cache) ) + cache[key] = fn.apply(this, arguments); + return cache[key]; + }; + + m[WRAPS] = fn; + m.purge = function purge(){ + var cache = this.cache; + this.cache = {}; + return cache; + }; + + m.purge(); + return m; +} + +// Memorized to reduce eval costs +var +_ofArityWrapper = +YFunction._ofArityWrapper = + memoize(function(n, limit){ + return eval('(function '+(limit ? 'limited' : 'artized')+'(fn){ '+ + 'return function('+Y.range(n).map( Y.op.add('$') ).join(',')+'){ '+ + 'return fn.apply(this,' + (limit ? 'Y(arguments).slice(0,'+n+')' : 'arguments')+ + '); }; })'); + }); + +function aritize(fn, n){ + var cache = fn.__aritized__ ; + + if (fn.length === n) + return fn; + + if ( !cache ) + cache = fn.__aritized__ = {}; + else if ( cache[n] ) + return cache[n]; + + return ( cache[n] = _ofArityWrapper(n, false)(fn) ); +} + +function limit(fn, n){ + var cache = fn.__limited__ ; + + if ( !cache ) + cache = fn.__limited__ = {}; + else if ( cache[n] ) + return cache[n]; + + return ( cache[n] = _ofArityWrapper(n, true)(fn) ); +} + + +/** + * Filter the arguments passed to the wrapper function + */ +// YFunction.prototype.mask = mask; +// function mask(){ +// +// } + + + +/** Returns the declared name of a function. */ +function getName( fn ){ + if ( !isFunction(fn) ) + return fn; + else + return fn.className || fn.name || (fn+'').match( /function\s*([^\(]*)\(/ )[1] || ''; +} + +function splat(fn, x){ + return fn[ isArray(x) ? "apply" : "call"](this, x); +} + + + + +exports['unwrap'] = unwrap; +exports['curry'] = curry; +exports['methodize'] = methodize; +exports['genericize'] = genericize; +exports['compose'] = compose; +exports['chain'] = chain; +exports['bind'] = bind; +exports['partial'] = partial; +exports['memoize'] = memoize; +exports['aritize'] = aritize; +exports['limit'] = limit; +exports['getName'] = getName; +// exports['splat'] = splat; + +// Methodize and then attach to YFunction's prototype +YFP.extend(core.map(exports, methodize)); +// YFP['unwrap'] = methodize(unwrap); +// YFP['curry'] = methodize(curry); +// YFP['methodize'] = methodize(methodize); +// YFP['genericize'] = methodize(genericize); // heh +// YFP['compose'] = methodize(compose); +// YFP['chain'] = methodize(chain); +// YFP['bind'] = methodize(bind); +// YFP['partial'] = methodize(partial); +// YFP['memoize'] = methodize(memoize); +// YFP['aritize'] = methodize(aritize); +// YFP['limit'] = methodize(limit); +// YFP['getName'] = methodize(getName); + +// Export these last to avoid methodizing them +exports['YFunction'] = YFunction; + +// Attach our methods to our exports! +core.forEach(exports, YFunction); diff --git a/src/Y/types/number.cjs b/src/Y/types/number.cjs new file mode 100644 index 0000000..875a641 --- /dev/null +++ b/src/Y/types/number.cjs @@ -0,0 +1,59 @@ +var Y = require('Y').Y +, op = require('Y/op') +; + +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; +} + + +exports['YNumber'] = +Y.YCollection.subclass('YNumber', { + init: function(o){ + this._o = o || 0; + }, + + compare : function compare(n){ + return op.cmp(this._o, n); + }, + + range : function range(end, step){ + return range(this._o, end, step); + }, + + toString : function toString(){ + return this.end()+''; + } +}); + +exports['range'] = range; diff --git a/src/Y/types/object.cjs b/src/Y/types/object.cjs new file mode 100644 index 0000000..3aeec15 --- /dev/null +++ b/src/Y/types/object.cjs @@ -0,0 +1,74 @@ +var Y = require('Y').Y +, isArray = Y.isArray +; + + +exports['YObject'] = +Y.YCollection.subclass('YObject', { + + 'init': function initYObject(o){ + this._o = o || {}; + }, + + /** + * Ensures an object has the given property or nested property chain. Each missing link in a chain is filled with a new, empty object. + * @param {String} chain Property name or nested property chain starting at `base`. Property chains are specified in dotted lookup syntax. + * @return {this} + */ + ensure : function ensure(chain){ + if (chain) chain + .split('.') + .reduce(function(o,link) { + if( o && link && o[link] === undefined ) + o[link] = {}; + return o[link]; + }, this._o ); + return this; + }, + + /** + * Searches a heirarchical object for a given subkey specified in dotted-property syntax. + * @param {Array|String} chain The property-chain to lookup. + * @param {Any} [def] Default value should the key be `undefined`. + * @param {Boolean} [meta] If supplied return an object of the form + * `{ key: Qualified key name, obj: Parent object of key, value: Value at obj[key] }` + * if chain is found (and `undefined` otherwise). + * @return {Any} The value at the path, or `def` if `undefined`, otherwise `undefined`. + */ + getNested : function getNested(chain, def, meta){ + if ( !isArray(chain) ) + chain = chain.toString().split('.'); + + var lastIdx = chain.length-1 + , ret = chain.reduce(function(current, key){ + if ( current === undefined || current.value[key] === undefined ) + return undefined; + else + return { + key : key, + value : current.value[key], + obj : current.value + }; + }, { value:this._o }); + + if (ret !== undefined) + return (meta ? ret : ret.value); + else + return (meta ? { value:def } : def); + }, + + /** + * Searches a heirarchical object for a given subkey specified in dotted-property + * syntax, setting it wiht the provided value if found. + * @param {Array|String} chain The property-chain to lookup. + * @param {Any} value The value to set. + * @return {this} + */ + setNested : function setNested(chain, value){ + var prop = this.ensure(chain).getNested(chain); + prop.obj[prop.key] = value; + return this; + } + +}); + diff --git a/src/Y/types/string.cjs b/src/Y/types/string.cjs new file mode 100644 index 0000000..cff211f --- /dev/null +++ b/src/Y/types/string.cjs @@ -0,0 +1,155 @@ +var Y = require('Y').Y +, mixinNames = require('Y/class').mixinNames +, op = require('Y/op') +; + +exports['YString'] = +Y.YCollection.subclass('YString', function(YString){ + + mixinNames(YString, String, [ + 'slice', 'split', + 'substr', 'substring', + 'concat', 'replace', + 'toLowerCase', 'toUpperCase' + ], true, true); + mixinNames(YString, String, [ 'indexOf', 'lastIndexOf', 'charAt', 'charCodeAt' ], true, false); + + function trim(val){ + var s = this._o+''; + val = val+''; + if (s.length < val.length) + return s; + else if ( s.indexOf(val) === 0 ) + return s.slice(val.length); + else + return s; + } + + op.extend(this, { + init : function init(o){ + if (!o) o = ""; + this._o = o; + }, + + /** + * As Array.slice -- replaces `howMany` elements starting at `idx` + * with the concatenation of the rest of the arguments. + * + * A negative value `idx` is offset from the end. + * + * Invalid values for `howMany` will be replaced with 0. + */ + splice : function splice(idx, howMany){ + var s = this._o; + + idx = (idx < 0 ? s.length+idx : idx); + howMany = Number(howMany > 0 ? howMany : 0); + + var prefix = s.slice(0, idx) + , insert = Y(arguments, 2).join('') + , suffix = s.slice(idx+howMany) + ; + this._o = prefix + insert + suffix; + return this; + }, + + /** + * Replaces the portion of the string defined by s.slice(start, end) + * with the concatenation of the rest of the arguments. + * + * Negative values for start and/or end are allowed. + */ + mutate : function mutate(start, end){ + return this.splice.apply(this, [start, end-start].concat(Y(arguments, 2)) ); + // var s = this._o, len = s.length ; + // + // if (start < 0) start += len; + // if (end < 0) end += len; + // + // var prefix = s.slice(0, start) + // , insert = Y(arguments, 2).join('') + // , suffix = s.slice(end) + // ; + // this._o = prefix + insert + suffix; + // return this; + }, + + strip: function strip(){ + return this._o.replace(/(^\s+|\s+$)/g, ''); + }, + + trim: trim, + ltrim: trim, + + rtrim: function rtrim(val){ + var s = this._o+''; + val = val+''; + + var idx = (s.length - val.length); + if (idx < 0) + return s; + else if ( s.lastIndexOf(val) === idx ) + return s.slice(0, idx); + else + return s; + }, + + startsWith: function startsWith(val){ + return this._o.indexOf(val) === 0; + }, + endsWith: function endsWith(val){ + var s = this._o; + return s.lastIndexOf(val) === (s.length - val.length); + }, + + compare : function compare(n){ + var m = this._o; + return (m > n ? 1 : + (m < n ? -1 : 0 )); + }, + + toString: function(){ + return this._o; + } + }); + + this.set = function set(key, value, def){ + var s = this._o, _val = (value !== undefined ? value : def); + + if ( Y.isNumber(key) ) + return this.splice(key, 1, _val); + if ( Y.isArray(key) ) + return this.splice.apply(this, key.slice(0,2).concat([_val]) ); + + // TODO: Should cache the new properties and re-applied them whenever we mutate _o, + // as strings are immutable and they'll be lost otherwise. + op.set(s, key, _val); + return this; + }; + + this.attr = function attr(key, value, def){ + var s = this._o; + // set + if ( value !== undefined || def !== undefined ) + return Y.attr(this, key, value, def); + + // get + else { + if ( Y.isNumber(key) ) + return s.charAt(key); + if ( Y.isArray(key) ) + return s.slice.apply(s, key); + + return s[key]; + } + }; + this.attr.__wraps__ = Y.attr; + + this.reduce = function reduce(fn, acc){ + fn = Function.toFunction(fn); + for ( var s = this._o, cxt = arguments[2]||this, i = 0, L = s.length; i < L; ++i ) + acc = fn.call(cxt, acc, s.charAt(i), i, s); + return acc; + }; + +}); diff --git a/src/Y/y-array.js b/src/Y/y-array.js deleted file mode 100644 index 8b72596..0000000 --- a/src/Y/y-array.js +++ /dev/null @@ -1,98 +0,0 @@ -var -YArray = -Y.YArray = -YCollection.subclass('YArray', function(YArray){ - this.init = function(o){ - // YCollection.init.call(this, o || []); - this._o = o || []; - }; - - this.merge = - this.concat = - function concat( donor ){ - var A = this._o; - new Y(arguments).forEach(function( donor ){ - A = A.concat(donor instanceof Y.YArray ? donor.end() : donor); - }); - return Y(A); - }; - - this.remove = - function remove(v){ - if (arguments.length > 1) - Y(arguments).forEach(this.remove, this); - else { - var idx = this.indexOf(v); - if ( idx != -1 ) - this.splice(idx, 1); - } - return this; - }; - - this.last = - function last(){ - var A = this._o; - return A[ A.length-1 ]; - }; - - this.unique = - function unique(){ - return this.reduce( - function(acc, v, i){ - if (acc.indexOf(v) === -1) - acc.push(v); - return acc; - - }, new Y.YArray() ); - - // return this.filter(function(v, i){ - // // Executes in the context of the new array, so - // // `this.indexOf` is checking what we've already - // // collected. - // return (this.indexOf(v) === -1); - // }); - }; - - // Like map, but produces a dict - // Y(["Foo?", "R&D"]).generate(encodeURIComponent) - // -> Y({"Foo?":"Foo%3F", "R&D":"R%26D"}) - this.generate = - function generate(fn, acc){ - var args = Y(arguments), - fn = args.shift(), - acc = args.shift(); - return this.reduce(function(acc, v, i){ - return acc.attr(v, fn.apply( this, [v].concat(args) )); - }, Y(acc || {})); - }; - - // Y([ ["foo", 1], ["bar", 2] ]).toDict() - // -> Y({foo:1, bar:2}) - this.toDict = - function toDict(){ - - }; - - this.clone = - function clone(){ - return Y(this._o.slice(0)); - }; - - this.size = - function size(){ - return this._o.length; - }; - - this.toString = - function toString(){ - return "Y[" + (this._o || "") + "]"; - }; - - - chainDelegates(YArray, 'push', 'unshift', 'sort', 'splice', 'reverse'); - mixinNames(YArray, Array, ['reduce', 'map', 'forEach', 'filter', 'slice', 'some', 'every'], true, true); - mixinNames(YArray, Array, ['indexOf', 'lastIndexOf', 'shift', 'pop', 'join'], true, false); - - return this; -}); - diff --git a/src/Y/y-class.js b/src/Y/y-class.js deleted file mode 100644 index 5c7aea0..0000000 --- a/src/Y/y-class.js +++ /dev/null @@ -1,229 +0,0 @@ -// Inspired by John Resig's "Simple Class Inheritence" -- http://ejohn.org/blog/simple-javascript-inheritance/ - -var KNOWN_CLASSES = {} -, classToString = function toString(){ return this.className+"()"; } -; - -// Private delegating constructor -- must be defined for every -// new class to prevent shared state. All construction is -// actually done in the init method. -function _Class() { - var cls = arguments.callee - , instance = this; - - // Not subclassing - if ( cls.caller !== Y.Class.fabricate ) { - if ( instance.init ){ - var result = instance.init.apply(instance, arguments); - if (result) instance = result; - } - } - - return instance; -} - - -/** - * Creates a new class. All classes inherit from Y.Class, and therefore support - * metaprogramming hooks and mixins. - * - * @param {String} className Name of the Class. - * - * @param {Type} [Parent] Parent class for subclassing. If Parent is a subclass of Y.Class - * itself, the new class will inherit directly from Parent. Otherwise, members will be - * copied off the prototype of Parent before applying any new instance members, but the - * new class will not respond to instanceof from Parent. - * - * @param {Object} [members] Instance members to add to the new class's prototype; a class - * constructor can be supplied as `init`. - * - * @returns {Class} A new Class. - */ -function Class(className, Parent, members) { - var ClassFactory = arguments.callee - , SuperClass = ClassFactory - , prototype = this - , parentMembers = {} - ; - - if ( !members && !isFunction(Parent) ) { - members = Parent; - Parent = null; - } - members = members || {}; - Parent = Parent || getProto(members).constructor || ClassFactory; - - if (Parent == ClassFactory) - Parent = Object; - - // Parent is the prototype - if ( !isFunction(Parent) ) { - SuperClass = getProto(Parent).constructor || Object; - prototype = Parent; - - // Parent is a constructor: check ClassFactory - } else if (Parent.prototype instanceof ClassFactory) { - SuperClass = Parent; - prototype = Parent.fabricate(); - - // Recurse so `this` is an instance of ClassFactory - } else if ( !(prototype instanceof ClassFactory) ) { - return new ClassFactory(className, Parent, members); - - } else { - parentMembers = Parent.prototype || {}; - } - - // Creates a new function with the appropriate name - // based on the className. - var NewClass, - constructor = [ - 'var '+className, - (''+_Class).replace(_Class.name, className), - 'NewClass = '+className, '' - ].join(';\n'); - eval(constructor); - - // Copy Class statics - for (var k in ClassFactory) - NewClass[k] = ClassFactory[k]; - - // Copy parent methods, then add new instance methods - for (var k in parentMembers) - prototype[k] = parentMembers[k]; - - if ( prototype.toString === toString ) - prototype.toString = classToString; - - // Fix Constructors, prototypes - NewClass.prototype = NewClass.fn = prototype; - prototype.constructor = prototype.__class__ = NewClass; - NewClass.__super__ = SuperClass; // don't override NewClass.constructor -- it should be Function - NewClass.className = prototype.className = className; - - // Either invoke body constructor... - if ( isFunction(members) ) { - members.call(prototype, NewClass); - - // Or add new instance methods - } else for (var k in members) { - if ( hasOwn.call(members, k) ) - prototype[k] = members[k]; - } - - if (prototype.init) NewClass.init = prototype.init; - - KNOWN_CLASSES[className] = NewClass; - - return NewClass; -} - -// Add metaprogramming data to Class object -Class.__super__ = Object; -Class.fn = Class.prototype; -Class.fn.__class__ = Class; -Class.className = Class.fn.className = "Class"; - - -Y.Class = -Y.subclass = Class; - -/* Class Methods */ - -/** - * Create a new instance and run delegate constructor if it exists. - * Unlike the keyword `new`, instantiate can be applied. - */ -Class.instantiate = - function instantiate(){ - var instance = this.fabricate(); - if ( instance.init ) { - var r = instance.init.apply(instance, arguments); - return (r !== undefined ? r : instance); - } else - return instance; - }; - -/** - * Create new instance, but do not run the delegate constructor. - */ -Class.fabricate = - function fabricate(){ - return new this(); - }; - -/** - * Class method of Classes, not to be confused with Y.subclass, which is a static method. - */ -Class.subclass = -Class.fn.subclass = - function subclass(className, members){ - return new Class(className, this, members); - }; - - - -/** - * Root-class for all Y-objects. - */ -function YBase(){} -YBase = Y.YBase = new Class("YBase", { - __y__ : true -}); - - - - -/// Other Class Utilities /// - -function bindName(v, k){ - if ( isFunction(v) ) - this[k] = Y(this[k]).bind(this); -} -// bindName = Y(bindName).curry(); - -Y.bindAll = bindAll; -function bindAll(o, names){ - var names = new Y(arguments, 1); - Y(names.size() ? names.generate(Y.op.get(o)) : o).forEach( bindName, o ); - - // if ( names.size() ){ - // names.forEach(binder); - // } else - // for (var k in o) binder(k); - - return o; -} - -// Y.chainDelegates = chainDelegates; -function chainDelegates(type, name){ - var names = Y(arguments, 1), - proto = type.prototype; - names.forEach(function(name){ - proto[name] = function(){ - var o = this._o || this; - o[name].apply(o, Y(arguments)); - return this; - }; - }); - return type; -} - -// Y.mixinNames = mixinNames; -function mixinNames(o, Donor, names, override, yWrap){ - var target = ( isFunction(o) ? o.prototype : o) - , proto = ( isFunction(Donor) ? Donor.prototype : Donor); - - // Need a closure to capture the name - names.forEach(function(name){ - if ( isFunction(proto[name]) && (override || !target[name]) ) - target[name] = function(){ - var r = proto[name].apply(this._o || target, arguments); - return (yWrap ? Y(r) : r); - }; - }); - - return o; -} - - diff --git a/src/Y/y-collection.js b/src/Y/y-collection.js deleted file mode 100644 index f027877..0000000 --- a/src/Y/y-collection.js +++ /dev/null @@ -1,133 +0,0 @@ - -/** YCollection is the core of Y. */ - -function bool(v){ return !!(v); } - -function extendY(){ - extend.apply(this, [this._o].concat(Y(arguments)) ); - return this; -} - -var -YCollection = -Y.YCollection = -YBase.subclass('YCollection', { - 'init' : function(o){ - if (!o) return; - this._o = o; - }, - - 'attr' : function attr(k, v, def){ - var r = Y.attr(this._o, k, v, def); - if (r === this._o) - return this; - else - return r; - }, - 'extend' : extendY, - 'merge' : extendY, - 'concat' : extendY, - - 'end' : function end(){ return this._o; }, - - 'reduce' : function reduce( fn, acc, context ){ - var o = this._o || this, - acc = acc || new o.constructor(); - for ( var name in o ) - acc = fn.call( context || this, acc, o[name], name, o ); - return acc; - }, - - 'map' : function map( fn, context ){ - var o = this._o, acc = new o.constructor(); - for ( var name in o ) - acc[name] = fn.call( context || this, o[name], name, o ); - return acc; - }, - - 'forEach' : function forEach( fn, context ){ - var o = this._o; - for ( var name in o ) - fn.call( context || this, o[name], name, o ); - }, - - 'filter' : function filter( fn, context ){ - var o = this._o, acc = new o.constructor(); - for ( var name in o ) - if ( fn.call( context || this, o[name], name, o ) ) - acc[name] = o[name]; - return acc; - }, - - 'indexOf' : function indexOf( value ){ - var o = this._o; - for ( var name in o ) - if ( o[name] === value ) - return name; - return -1; - }, - - 'has' : function has( value ){ - return ( this.indexOf(value) !== -1 ); - }, - - 'clone' : function clone(){ - return Y({}).extend(this); - }, - - 'remove' : function remove(v){ - var o = this._o - , toRemove = new Y(arguments); - - for (var k in o) { - var v = o[k]; - if ( toRemove.has(v) ) { - delete o[k]; - toRemove.remove(v); - } - } - return this; - }, - - 'every' : function every( fn ){ - var self = this, fn = fn || bool; - return this.reduce(function(acc, v, k, o){ - return acc && fn.call(self, v, k, o); - }, true); - }, - - 'any' : function any( fn ){ - var self = this, fn = fn || bool; - return this.reduce(function(acc, v, k, o){ - return acc || fn.call(self, v, k, o); - }, false); - }, - - 'zip' : function zip(){ - var sequences = new Y(arguments).map( Y.limit(1) ).unshift(this); - return this.map(function(_, k){ - return sequences.invoke('attr', k); - }).invoke('end'); - }, - - 'pluck' : function pluck(key){ - return this.map(function(v){ - return v && (isFunction(v.attr) ? v.attr(key) : v[key]); - }); - }, - - 'invoke' : function invoke(name){ - var args = Y(arguments), - name = args.shift(); - return this.map(function(o){ - return o && o[name].apply(o, args); - }); - }, - - 'apply' : function apply(name, args){ - return this[name].apply(this, args); - } - -}); - - diff --git a/src/Y/y-core.js b/src/Y/y-core.js deleted file mode 100644 index 2abb48b..0000000 --- a/src/Y/y-core.js +++ /dev/null @@ -1,88 +0,0 @@ - -Y.reduce = reduce; -Y.map = map; -Y.forEach = forEach; -Y.filter = filter; -Y.set = dset; -Y.attr = dattr; -Y.extend = extend; - -Y.type = type; -Y.is = is; -Y.isString = isString; -Y.isNumber = isNumber; -Y.isFunction = isFunction; -Y.isArray = isArray; -Y.isPlainObject = isPlainObject; - - - - -/** - * Creates a Y wrapper around its input. - */ -function Y(o){ - var A = arguments - , newY = (this instanceof Y) - , r, args - ; - - // Passthrough nulls - if (o === undefined || o === null) - return newY ? this : o; - - // Don't re-wrap Y-objects - if ( o.__y__ ) - return newY ? Y(o.end()) : o; - - // Y( arguments, start=0, stop=arguments.length ) - // Cast `arguments` object to a real Array, optionally slicing at specified delimiters - if ( o.prototype === undefined - && isNumber(o.length) - && !_Array.isArray(o) - && o.constructor === _Object ) - { - r = slice.call( o, A[1]||0, A[2]||o.length ); - return (newY ? new Y.YArray(r) : r); - } - - // Convenience calls for non-object conversions to collections - args = slice.call(A, 0); - if ( A.length > 1 ) { - - // Merge Arrays or Objects - // Y([0,1], [2,3], [4,5]) -> [0,1,2,3,4,5] - // Y({foo:1}, {bar:2}) -> { foo:1, bar:2 } - if ( args.every(isArray) || args.every(isPlainObject) ) { - r = extend.apply(this, args); - - // Convenience of Y(Y.range()) - } else if ( args.every(isNumber) ) { - r = Y.range.apply(this, A); - - // We got random stuff: wrap an Array of it - } else - return new Y.YArray( args ); - - return (newY ? Y(r) : r); - } - - // Do we have a type-specific wrapper? - var name = type_of(o) - , yname = 'Y' + name.charAt(0).toUpperCase() + name.slice(1) - , YType = Y[yname] - ; - - // if ( YType && YType !== Y.YObject || YType !== Y.YBase ) - // return new YType(o); - if ( YType ) - return new YType(o); - - // Add YFunction methods, since we can't subclass function - // if ( isFunction(o) ) - // return new Y.YFunction(o); - - // Finally, Generic object wrapper - return new Y.YObject(o); -} - diff --git a/src/Y/y-function.js b/src/Y/y-function.js deleted file mode 100644 index 6f1e873..0000000 --- a/src/Y/y-function.js +++ /dev/null @@ -1,301 +0,0 @@ -var _ = globals._ = Y._ = YFunction._ = {} -, WRAPS = "__wraps__" -; - -function YFunction(fn){ - if (!fn) - fn = function(){}; - - if (fn.__y__) - return fn; - - fn.__y__ = true; - return Y.YFunction.install(fn); -} - -Y.YFunction = YFunction; -Y.extend(YFunction.prototype, { - init : YFunction, - reduce : methodize(Y.reduce), - extend : methodize(Y.extend), - end : function end(){ return this; } -}); -YFunction.prototype.attr = methodize(Y.attr); - -YFunction.install = -function install(target){ - target = target || Function.prototype; - var proto = Y.YFunction.prototype; - - for (var k in proto) { - if ( Y.isFunction(proto[k]) && (k == 'bind' || !target[k]) ) - target[k] = proto[k]; - } - return target; -}; - - - -function unwrap(fn){ - return ( fn && isFunction(fn) ) ? unwrap(fn[WRAPS]) || fn : fn; -} - -Y.curry = curry; -YFunction.prototype.curry = methodize(curry); -function curry(fn){ - if (fn.__curried__) - return fn.apply(this, Y(arguments,1)); - - fn = Function.toFunction(fn); - 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) { - fn = fn.toFunction(); - var g = fn.__genericized__ - , m = fn.__methodized__ ; - if (m) return m; - if (g && g[WRAPS]) return g[WRAPS]; - - m = fn.__methodized__ = - function methodized(){ - return fn.apply(this, [this].concat( Y(arguments) )); - }; - m[WRAPS] = fn; - return m; -} - -Y.genericize = genericize; -YFunction.prototype.genericize = methodize(genericize); // heh -function genericize( fn ) { - fn = fn.toFunction(); - var g = fn.__genericized__ - , m = fn.__methodized__ ; - if (g) return g; - if (m && m[WRAPS]) return m[WRAPS]; - - g = fn.__genericized__ = - function genericized(){ - var args = Y(arguments); - return fn.apply(args.shift(), args); - }; - g[WRAPS] = fn; - return g; -}; - - - -Y.compose = compose; -YFunction.prototype.compose = methodize(compose); -function _composer(x,fn){ return fn.call(this, x); } -function compose(f,g){ - var fns = Y(arguments).map(Function.toFunction); - return function(){ - return fns.reduce(_composer, Y(arguments), this); - }; -} - -Y.chain = chain; -YFunction.prototype.chain = methodize(chain); -function chain(f,g){ - var fns = Y(arguments).map(Function.toFunction); - - if ( g.__sequence__ ) - fns = g.__sequence__.concat( fns.slice(1) ); - - function chained(){ - var args = Y(arguments) - , i = fns.length; - while (i-- > 0) args = fns[i].call(this, x); - return args; - } - - chained.__sequence__ = fns; - return chained; -} - -// YFunction.prototype.lazy = methodize(lazy); -// function lazy(fn){ -// var args = Y(arguments, 1) -// , L = unwrap(fn).length -// , lazied = function(){ -// var _args = Y(arguments) -// , f = _args[0]; -// -// if ( isFunction(f) ) { -// var lazied = arguments.callee.compose(_args.shift()); -// if (_args.length !== 0) -// return lazied.lazy.apply(lazied, _args); -// } -// -// args.splice.apply(args, [args.length, 0].concat(_args)); -// if ( args.length >= L ) -// return fn.apply(this, args); -// else -// return arguments.callee; -// } -// ; -// lazied[WRAPS] = fn; -// lazied.__args = args; -// return lazied(); -// } - - -function splat(fn, x){ - return fn[ isArray(x) ? "apply" : "call"](this, x); -} - -var _bind = _Function.prototype.bind; -YFunction.prototype.bind = - function bind(context, args){ - var bound = _bind.apply(this, arguments); - bound[WRAPS] = this; - return Y(bound); - }; - - -// Remembers arguments but obeys current context -YFunction.prototype.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); - }; - - -// 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); - -/** - * @param {Function} fn Function to memorize. - * @param {Array -> String} [keyfn] Serializes an array of arguments to a string. By default, joins with three nulls. - * @param {Object} [cacher] Object on which to store the memorization cache for lookups. Useful for meta-caches. Defaults to the memorized function. - * @param {String} [cacheName="cache"] Property this cache will be stored under. - */ -function memoize(fn){ - if (fn.__memoized__) return fn.__memoized__; - - var m = - fn.__memoized__ = - function memorizer(){ - // toJSON would be a better alternative, but that won't work cross-browser - var key = Y(arguments).join('\0\0\0') - , cache = arguments.callee.cache; - if ( !(key in cache) ) - cache[key] = fn.apply(this, arguments); - return cache[key]; - }; - - m[WRAPS] = fn; - m.purge = function purge(){ - var cache = this.cache; - this.cache = {}; - return cache; - }; - - m.purge(); - return m; -} - -// Memorized to reduce eval costs -var -_ofArityWrapper = -YFunction._ofArityWrapper = - memoize(function(n, limit){ - return eval('(function '+(limit ? 'limited' : 'artized')+'(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 aritize(n){ - var fn = this - , cache = fn.__aritized__ ; - - if (fn.length === n) - return fn; - - if ( !cache ) - cache = fn.__aritized__ = {}; - else if ( cache[n] ) - return cache[n]; - - return ( cache[n] = _ofArityWrapper(n, false)(fn) ); -}; - -YFunction.prototype.limit = -function limit(n){ - var fn = this - , cache = fn.__limited__ ; - - if ( !cache ) - cache = fn.__limited__ = {}; - else if ( cache[n] ) - return cache[n]; - - return ( cache[n] = _ofArityWrapper(n, true)(fn) ); -}; - - -/** - * 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 - function getName( fn ){ - if ( !fn && isFunction(this) ) - fn = this; - if ( !isFunction(fn) ) - return fn; - else - return fn.className || fn.name || (fn+'').match( /function\s*([^\(]*)\(/ )[1] || ''; - } - - -YFunction(Y); -Y(Y.reduce); -Y(Y.map); -Y(Y.forEach); -Y(Y.filter); -Y(Y.set); -Y(Y.attr); -Y(Y.extend); -Y(Y.type); -Y.is = Y(Y.is).curry(); - -Y.reduce(YFunction.prototype, function(_,fn,name){ - YFunction(fn); -}); diff --git a/src/Y/y-number.js b/src/Y/y-number.js deleted file mode 100644 index dba6137..0000000 --- a/src/Y/y-number.js +++ /dev/null @@ -1,57 +0,0 @@ - -var -YNumber = -Y.YNumber = -YCollection.subclass('YNumber', { - init: function(o){ - if (!o) o = 0; - YCollection.init.call(this, o); - }, - - compare : function compare(n){ - var m = this._o; - return (m > n ? 1 : - (m < n ? -1 : 0 )); - }, - -