Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #4060: base.js.diff

File base.js.diff, 8.0 kB (added by newmanb@stanford.edu, 2 years ago)

An update. More than just an iteration, too. See my upcoming comments for a summary.

  • src/base.js

    old new  
    1 var Class = { 
    2   create: function() { 
    3     return function() {  
    4       this.initialize.apply(this, arguments); 
     1var Class = new (function() { 
     2 
     3  // You'll definitely want to check out 
     4  // http://groupspace.org/devben/proto-svn/demo/ 
     5  // to get a mile-high understanding of why I 
     6  // bothered with all of this. 
     7 
     8  this.NAME = "Class"; 
     9  this.VERSION = Prototype.Version || 2.0; 
     10  // put your name here if you've helped in any way! 
     11  this.AUTHORS = "Ben Newman (of groupspace.org), et al."; 
     12   
     13  this.__repr__ = function() { 
     14    return "[" + this.NAME + " " + this.VERSION + "]"; 
     15  }; 
     16 
     17  this.toString = function() { 
     18    return this.__repr__(); 
     19  }; 
     20 
     21  var __doNotInit = {}; 
     22 
     23  this.create = function(declarations) { 
     24 
     25    var ctor = function() { 
     26      if (arguments[0] !== __doNotInit && this.initialize) { 
     27        this._runTimeDeclarations = {}; 
     28        this.initialize.apply(this, arguments); 
     29      } 
     30    }; 
     31 
     32    if (declarations) { 
     33      // runs when we call __inherit(ctor, ownPrototype) below 
     34      var ownPrototype = function() { 
     35        for (var i in declarations) 
     36          __attachClassProperty(i, declarations[i], this); 
     37        __ensureDefaults(this, declarations); 
     38      }; 
     39 
     40      if (declarations.extending) { 
     41        var baseInstance = // a constant-time operation: 
     42          __inherit(ownPrototype, declarations.extending); 
     43        declarations['getBaseInstance'] = Class.encap(baseInstance); 
     44        declarations['sup'] = __makeSup(); 
     45      } 
     46       
     47      __markCriticalFunctions(declarations); 
     48      __setupAttachDelete(declarations); 
     49      __inherit(ctor, ownPrototype); 
    550    } 
    6   } 
    7 } 
    851 
     52    return ctor; 
     53  }; 
     54 
     55  // superclass can be constructor function or existing object 
     56  var __inherit = function(subclass, superclass) { 
     57    if (typeof(superclass) == 'function') { 
     58      superclass.getInstance = superclass.getInstance || 
     59        Class.encap(new superclass(__doNotInit)); 
     60      subclass.prototype = superclass.getInstance(); 
     61    } else if (typeof(superclass) == 'object') 
     62      subclass.prototype = superclass; 
     63    return subclass.prototype; 
     64  }; 
     65   
     66  // Functions marked here will be denied this.sup and privacy benefits, 
     67  // but will be faster because they will be called directly. 
     68  var __markCriticalFunctions = function(declarations) { 
     69    var critical = declarations.critical; 
     70    if (typeof(critical) == 'object') { 
     71      for (var i in critical) { 
     72        critical[i]._critical = true; 
     73        declarations[i] = critical[i]; 
     74      } 
     75    } 
     76  }; 
     77 
     78  var __setupAttachDelete = function(declarations) { 
     79    // these two methods allow runtime method attachment and deletion, 
     80    // with all the benefits of this.sup and privacy restrictions 
     81    declarations['attachMethod'] = function(fnName, func, 
     82                                            /*optional*/ critical) { 
     83      // can't replace existing methods 
     84      if (!this.ownPrototypeHas(fnName)) { 
     85        func._critical = !!critical; 
     86        this._runTimeDeclarations[fnName] = true; 
     87        __attachClassProperty(fnName, func, this); 
     88      } 
     89    }; 
     90    declarations['deleteMethod'] = function(fnName) { 
     91      // can only delete non-runtime additions 
     92      if (this._runTimeDeclarations[fnName]) { 
     93        __attachClassProperty(fnName, null, this, true); 
     94        this._runTimeDeclarations[fnName] = false; 
     95      } 
     96    }; 
     97  }; 
     98   
     99  var __attachClassProperty = function(propName, prop, obj, 
     100                                       /*optional*/ removeInstead) { 
     101    if (removeInstead) { 
     102      if (obj.ownPrototypeHas(propName)) delete obj[propName]; 
     103    } else { 
     104      obj[propName] = prop; 
     105      if (!prop._critical && typeof(prop) == 'function') 
     106        __addStackLogic(obj, propName); 
     107    } 
     108  }; 
     109 
     110  // special-purpose array object (slightly faster in tests) 
     111  var __callStack = new (function() { 
     112    var stack = []; var index = 0; 
     113    this.push  = function(what) { stack[index++] = what; } 
     114    this.pop   = function()     { return stack[--index]; } 
     115    this.empty = function()     { return index == 0; } 
     116    this.peek  = function()     { return stack[index - 1]; } 
     117  })(); 
     118   
     119  var __lastOnCallStack = function() { 
     120    if (__callStack.empty()) return ['', null]; 
     121    else return __callStack.peek(); 
     122  }; 
     123     
     124  var __addStackLogic = function(obj, fnName) { 
     125    switch (fnName) { 
     126      case 'sup': case 'toString': case 'valueOf': 
     127      case 'attachMethod': case 'deleteMethod': 
     128      case 'getBaseInstance': return; 
     129      default: { 
     130        var __func = obj[fnName]; 
     131        obj[fnName] = function() { 
     132          // this privacy check can be omitted for slight performance 
     133          // gains in production code (privacy is a development tool) 
     134          var lastRef = __refOfLastCallingObject(); 
     135          if (Class.followsPrivateNamingConvention(fnName) && 
     136              (lastRef || {}).constructor !== this.constructor) { 
     137            Class.privateCallError(fnName); 
     138          } else { 
     139            __callStack.push([fnName, this]); 
     140            var result = __func.apply(this, arguments); 
     141            __callStack.pop(); 
     142            return result; 
     143          } 
     144        }; 
     145      } 
     146      obj[fnName].core = __func; // preserve original 
     147      // e.g. obj[fnName].core.call(obj, arg1, ...) 
     148    } 
     149  }; 
     150     
     151  Function.prototype.grant = function(obj) { 
     152    var __func = this; 
     153    var __callStackMemory = __lastOnCallStack(); 
     154    return function() { 
     155      __callStack.push(__callStackMemory); 
     156      var result = __func.apply(obj || this, arguments); 
     157      __callStack.pop(); 
     158      return result; 
     159    } 
     160  }; 
     161 
     162  // consider exposing these (they expose nothing but useful info) 
     163  var __nameOfLastCalledMethod = function() { 
     164    return __lastOnCallStack()[0]; 
     165  }; 
     166 
     167  var __refOfLastCallingObject = function() { 
     168    return __lastOnCallStack()[1]; 
     169  }; 
     170 
     171  // change this at will 
     172  this.followsPrivateNamingConvention = function(propName) { 
     173    return propName.charAt(0) == '_'; 
     174  }; 
     175   
     176  this.privateCallError = function(fnName) { 
     177    alert("Error: Tried to access private member " + fnName + 
     178          " from from non-member method " + 
     179          __nameOfLastCalledMethod()); 
     180  }; 
     181 
     182  var __ensureDefaults = function(ownPrototype, declarations) { 
     183    ['toString', 
     184     'toLocaleString', 
     185     'valueOf'].each(function(prop) { 
     186       if (declarations[prop]) { 
     187         __attachClassProperty(prop, declarations[prop], ownPrototype); 
     188       } 
     189     }); 
     190    ownPrototype.ownPrototypeHas = function(property) { 
     191      return (typeof(declarations[property]) != 'undefined' || 
     192              (this._runTimeDeclarations && // present if instantiated 
     193               this._runTimeDeclarations[property])); 
     194    } 
     195  }; 
     196 
     197  var __makeSup = function(parentPrototype) { 
     198    var __platform = false; // where to start lookup 
     199     
     200    return function() { 
     201      var origin = __nameOfLastCalledMethod(); 
     202      var curObj = __platform || this; 
     203 
     204      // walk up inheritance chain until we've found the first class that 
     205      // actually implements the method from which this.sup was called 
     206      while (!curObj.ownPrototypeHas(origin) 
     207             && curObj.getBaseInstance) 
     208        curObj = curObj.getBaseInstance(); 
     209      curObj = curObj.getBaseInstance 
     210        ? curObj.getBaseInstance() 
     211        : {}; // origin won't be found here! 
     212 
     213      var prevBase = __platform; 
     214      __platform = curObj; 
     215      var result = curObj[origin].apply(this, arguments); 
     216      __platform = prevBase; 
     217      return result; 
     218    }; 
     219  }; 
     220 
     221  // convenient mechanism for creating accessor functions 
     222  this.encap = function(__val, mutable) { 
     223    if (!mutable) return function() { return __val; } 
     224    else return function(/* optional new value */) { 
     225      if (arguments.length > 0) __val = arguments[0]; 
     226      return __val; 
     227    } 
     228  }; 
     229 
     230})(); // construct the Class object 
     231 
     232var createClass = Class.create; 
     233 
    9234var Abstract = new Object(); 
    10235 
    11236Object.extend = function(destination, source) {