Adds init wrapper support to simplify mixin initialisation.
authordsc <david.schoonover@gmail.com>
Thu, 10 Feb 2011 09:04:59 +0000 (01:04 -0800)
committerdsc <david.schoonover@gmail.com>
Thu, 10 Feb 2011 09:04:59 +0000 (01:04 -0800)
src/evt.cjs
src/ezl/mixins/speciated.cjs
src/tanks/inventory/bag.cjs
src/tanks/inventory/bagbag.cjs
src/tanks/inventory/container.cjs
src/tanks/inventory/inventory.cjs
src/tanks/map/wall.cjs
src/tanks/mixins/inventoried.cjs
src/tanks/mixins/quantified.cjs
src/tanks/ui/inventory/containerui.cjs

index d8c1880..5ed4e9e 100644 (file)
@@ -43,7 +43,7 @@ var Y       = require('Y').Y
 
 ,   classStatics = [ 'instantiate', 'fabricate', 'subclass' ]
 ,   classMagic = [
-            '__bases__', '__initialise__', '__class__', 'constructor', 'className',
+            '__bases__', '__initialise__', '__inits__', '__class__', 'constructor', 'className',
             '__emitter__', '__static__', '__mixins__', '__id__'
         ] //.concat(classStatics)
 ,   mixinSkip = [
@@ -113,22 +113,26 @@ exports['createInitialise'] =
 function createInitialise(cls){
     function initialise(){
         var instance = this
-        ,   binds = cls.fn.__bind__ // list of names to bind
+        ,   proto = cls.fn
+        ,   binds = proto.__bind__ // list of names to bind
+        ,   init  = proto.init
+        ,   inits = proto.__inits__
+        ,   args  = Y(arguments)
         ;
         
         if (binds)
             Y.bindAll(instance, binds);
         
-        var init = cls.fn.init;
-        if ( typeof init == 'function' ) {
-            var result = init.apply(instance, arguments);
-            if (result) instance = result; // XXX: I think this needs to go away
-        }
+        if ( typeof init == 'function' && init !== arguments.callee )
+            init.apply(instance, args);
+        
+        if ( inits && inits.length )
+            inits.invoke('apply', instance, args);
         
         instance.emit('init', instance, {
             'instance' : instance,
             'cls'      : cls,
-            'args'     : Y(arguments)
+            'args'     : args
         }, instance);
         
         return instance;
@@ -136,9 +140,6 @@ function createInitialise(cls){
     return Y(initialise);
 };
 
-function notClassMagic(v, k){
-    return classMagic.indexOf(k) === -1;
-}
 
 
 
@@ -206,36 +207,39 @@ function Class(className, Parent, members){
     eval(constructor);
     
     // Copy parent methods, then add new instance methods
-    for (var k in parentMembers)
+    for (var k in parentMembers) {
         if ( hasOwn.call(parentMembers,k) )
             setDesc(prototype, k, getDesc(parentMembers,k));
         else
             prototype[k] = parentMembers[k];
+    }
     
-    if ( prototype.toString === objToString )
+    if ( prototype.toString === objToString ) // check SuperClass.fn.toString
         prototype.toString = classToString;
     
     NewClass.className = prototype.className = className;
     NewClass.prototype = NewClass.fn = prototype;
     
+    // Add class emitter
+    var ParentEmitter = (Parent.__emitter__ ? Parent : ClassFactory)
+    ,   ClassEmitter  = NewClass.__emitter__ = new Emitter(NewClass, ParentEmitter)
+    ,   mixins  = members.__mixins__ || []
+    ;
+    
     // Fix Constructors
     NewClass.__super__ = SuperClass; // don't override NewClass.constructor -- it should be Function
-    NewClass.__bases__ = NewClass.fn.__bases__ = Y([SuperClass]).concat( SuperClass.__bases__ || [ Class, Object ] );
+    NewClass.__bases__ = NewClass.fn.__bases__ = Y(mixins).concat( [SuperClass], SuperClass.__bases__ || [ Class, Object ] );
     prototype.constructor = prototype.__class__ = NewClass;
     
+    prototype.__inits__ = new Y.YArray();
     NewClass.init = prototype.__initialise__ = createInitialise(NewClass);
     
-    // Add class emitter
-    var ParentEmitter = (Parent.__emitter__ ? Parent : ClassFactory)
-    ,   ClassEmitter  = NewClass.__emitter__ = new Emitter(NewClass, ParentEmitter)
-    ;
     
     // Record for metaprogramming
     KNOWN_CLASSES[className] = NewClass;
     
     NewClass.__bind__ = prototype.__bind__;
-    var mixins   = NewClass.__mixins__ = Y([]).concat(members.__mixins__||[], SuperClass.__mixins__||[]).unique()
-    ,   statics  = NewClass.__static__ = {}
+    var statics  = NewClass.__static__ = {}
     ,   pstatics = SuperClass.__static__
     ,   mstatics = members.__static__
     ;
@@ -270,7 +274,7 @@ function Class(className, Parent, members){
     }
     
     NewClass.instantiate = instantiate.partial(NewClass);
-    NewClass.__bind__ = prototype.__bind__ = Y([]).concat(prototype.__bind__||[], SuperClass.__bind__||[]).unique();
+    NewClass.__bind__ = prototype.__bind__ = Y(prototype.__bind__||[]).concat(SuperClass.__bind__||[]).unique();
     
     // Notify mixins to let them finish up any customization
     if (mixins.length)
@@ -283,8 +287,8 @@ function Class(className, Parent, members){
     ParentEmitter.emit('subclass',
         NewClass, {
             'className' : className,
-            'parent'    : Parent,
-            'child'     : NewClass,
+            'super'     : Parent,
+            'cls'       : NewClass,
             'members'   : members,
             'prototype' : prototype
         }, NewClass);
@@ -299,8 +303,8 @@ Class.__emitter__ = new Emitter(Class);
 Class.fn = Class.prototype;
 Class.fn.__class__ = Class.fn.constructor = Class;
 Class.fn.__bases__ = Class.__bases__ = Y([ Object ]);
-Class.fn.__bind__ = Class.__bind__ = Y([]);
-Class.className = Class.fn.className = "Class";
+Class.fn.__bind__  = Class.__bind__ = Y([]);
+Class.fn.className = Class.className = "Class";
 
 /* Class Methods */
 
@@ -373,9 +377,10 @@ function mixinFilter(v, k){
  * Mixes a Mixin into another Class.
  */
 function mixin(cls, _mxn){
-    var proto   = cls.fn
-    ,   bases   = Y(cls.__bases__ || [])
-    ,   cbinds  = Y(cls.__bind__  || [])
+    var proto   = (typeof cls === "function") ? cls.prototype : cls
+    ,   bases   = cls.__bases__ = Y(cls.__bases__ || [])
+    ,   cbinds  = cls.__bind__  = proto.__bind__  = Y(cls.__bind__  || [])
+    ,   cinits  = cls.__inits__ = proto.__inits__ = Y(cls.__inits__ || [])
     ,   cstatic = cls.__static__
     ,   mxns    = (Y.isArray(_mxn) ? _mxn.slice(0) : Y(arguments, 1))
     ;
@@ -386,8 +391,9 @@ function mixin(cls, _mxn){
             throw new Error('Cannot mix in non-object! '+mxn);
         
         var mproto   = (typeof mxn === "function") ? mxn.fn : mxn
-        ,   statics  = mxn.__static__
+        ,   statics  = mxn.__static__ || {}
         ,   binds    = mxn.__bind__
+        ,   init     = mproto.init
         ,   onCreate = mproto.onCreate
         ,   firstMix = (bases && bases.indexOf(mxn) === -1)
         ;
@@ -395,14 +401,12 @@ function mixin(cls, _mxn){
         core.extend(proto, core.filter(mproto, mixinFilter, mproto));
         
         // Add mixin statics to class constructor
-        if (statics){
-            for (var k in statics)
-                if ( hasOwn.call(statics,k) && classMagic.indexOf(k) === -1 ) {
-                    var desc = getDesc(statics,k);
-                    setDesc(cls,     k, desc);
-                    setDesc(cstatic, k, desc);
-                }
-        }
+        for (var k in statics)
+            if ( hasOwn.call(statics,k) && classMagic.indexOf(k) === -1 ) {
+                var desc = getDesc(statics,k);
+                setDesc(cls,     k, desc);
+                setDesc(cstatic, k, desc);
+            }
         
         // Add/ensure the mixin is at the front of bases
         bases.remove(mxn).unshift(mxn);
@@ -411,6 +415,10 @@ function mixin(cls, _mxn){
         if (binds)
             cls.__bind__ = proto.__bind__ = cbinds.concat(binds).unique();
         
+        // Wrap init call
+        if ( typeof init == 'function' )
+            cinits.remove(init).unshift(init);
+        
         // Only perform these actions the first time we mix into this class
         if (!firstMix)
             return;
@@ -444,7 +452,7 @@ function aggregate(cls, key){
 Mixin.on('subclass',
     function onMixinSubclass(evt){
         var d       = evt.data
-        ,   mxn     = d.child
+        ,   mxn     = d.cls
         ,   members = d.members
         ,   onMixin = members.onMixin
         ;
@@ -464,4 +472,4 @@ exports['instantiate'] = instantiate;
 exports['fabricate']   = Y.fabricate;
 exports['lookupClass'] = lookupClass;
 exports['mixin']       = mixin;
-exports['aggregate']   = aggregate;
+exports['aggregate']   = aggregate;
\ No newline at end of file
index dad1630..70195f0 100644 (file)
@@ -126,6 +126,7 @@ Mixin.subclass('Speciated', {
     onMixin : function mixSpeciated(evt){
         var cls = evt.data.cls;
         cls.__known__ = {};
+        cls.on('subclass', arguments.callee);
     },
     
     toString : function(){
index bafd675..d535721 100644 (file)
@@ -15,15 +15,16 @@ Item.subclass('Bag', {
     
     /// Setup ///
     hasUI : true,
-    highlightIconOnOpen : true, // Whether to highlight the inventory icon when bag is open
+    uiOptions : null,
     reqs : null,
+    // highlightIconOnOpen : true, // Whether to highlight the inventory icon when bag is open
     
     /// Bookkeeping ///
     bagName : null,
     ui : null, // ContainerUI
     
     
-    init : function initBag(bagName, owner){
+    init : function initBag(owner, bagName){
         this.bagName = bagName;
         this.owner = owner;
         Item.init.call(this);
index 609b163..bec16a8 100644 (file)
@@ -15,8 +15,9 @@ Bag.subclass('BagBag', {
     
     /// Setup ///
     hasUI : true,
-    highlightIconOnOpen : true, // Whether to highlight the inventory icon when bag is open
-    reqs : 'bag',
+    uiOptions : null,
+    reqs : 'bag', // TODO: parse, enforce reqs
+    // highlightIconOnOpen : true, // Whether to highlight the inventory icon when bag is open
     
     /// Bookkeeping ///
     bagName : 'bagbag',
@@ -25,7 +26,7 @@ Bag.subclass('BagBag', {
     
     init : function initBagBag(inventory, player){
         this.inventory = inventory;
-        Bag.init.call(this, 'bagbag', player);
+        Bag.init.call(this, player, 'bagbag');
         this.showUI();
         if (this.ui) this.ui.layer.addClass('bagbag bag');
     }
index 775be14..25b005f 100644 (file)
@@ -25,15 +25,15 @@ Mixin.subclass('Container', {
     children : null,    // Nested containers: container id -> Container
     
     
-    onCreate : function initContainer(evt, self){
-        self.items = {};
-        self.children = {};
-        self.slots = new Array(self.max);
+    init : function initContainer(){
+        this.items = {};
+        this.children = {};
+        this.slots = new Array(this.max);
         
-        if ( typeof self.reqs == 'string' )
-            self.reqs = Y([ self.reqs ]);
+        if ( typeof this.reqs == 'string' )
+            this.reqs = Y([ this.reqs ]);
         else
-            self.reqs = Y(self.reqs);
+            this.reqs = Y(this.reqs);
     },
     
     setup : function setup(owner, items){
index 10cd7a1..bd9e8ff 100644 (file)
@@ -32,11 +32,11 @@ evt.subclass('Inventory', {
     belt : null,                // {Belt}               Size determined by beltSlots
     bagbag : null,              // {BagBag}             Size determined by bagSlots
     
-    items : {},                 // id -> {Item}         All items in all bags
-    equipment : {},             // name -> {Item}       All equipped items
-    bags : {},                  // id -> {Container}    All bags in all bags
+    items     : {},             // id -> {Item}         All items in all bags
+    equipment : {},             // slot -> {Item}       All equipped items
+    bags      : {},             // id -> {Container}    All bags in all bags
     namedBags : {},             // name -> {Container}  All named bags in all bags
-    equipBags : {},             // name -> {EquipSlot}  All EquipSlot containers
+    equipBags : {},             // slot -> {EquipSlot}  All EquipSlot containers
     
     // Y-wrapped
     _items : null,
index d55914c..fc35e99 100644 (file)
@@ -107,7 +107,7 @@ Thing.subclass('Wall', {
 Wall.register('wall', Wall);
 Wall.on('subclass',
     function(evt){
-        var subcls = evt.data.child;
+        var subcls = evt.data.cls;
         Wall.register(Y(subcls.className).camelToSnake(), subcls);
     });
 
index e027927..80f784c 100644 (file)
@@ -29,9 +29,9 @@ Mixin.subclass('Inventoried', {
     },
     
     
-    onCreate : function initInventoried(evt, self){
-        var clsInv = self.__class__.aggregate('inventory')
-        ,   inv    = self.inventory = deepcopy(clsInv)
+    init : function initInventoried(){
+        var clsInv = this.__class__.aggregate('inventory')
+        ,   inv    = this.inventory = deepcopy(clsInv)
         ;
         inv.items     = {};
         inv.backpack  = new Array(inv.max);
index b21ac8b..b65af5a 100644 (file)
@@ -17,12 +17,10 @@ Mixin.subclass('Quantified', {
     buffs     : [],
     
     
-    onCreate : function initQuantified(evt, self){
-        self.buffs = Y([]);
-        self.on('buff.conjure', self.onBuffAcquired);
-        self.on('buff.die',     self.onBuffLost);
-        // self.on('buff.conjure', self.onBuffAcquired.bind(self));
-        // self.on('buff.die',     self.onBuffLost.bind(self));
+    init : function initQuantified(){
+        this.buffs = Y([]);
+        this.on('buff.conjure', this.onBuffAcquired);
+        this.on('buff.die',     this.onBuffLost);
     },
     
     stat : function stat(k){
index 09cc579..39936ab 100644 (file)
@@ -9,6 +9,7 @@ var Y = require('Y').Y
 ContainerUI =
 exports['ContainerUI'] =
 HtmlLayer.subclass('ContainerUI', {
+    __mixins__ : [],
     __bind__ : [ 'onItemUpdated', 'onDrop' ],
     _layerClasses : 'item-container hud',