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

Ticket #4060: base.js.4.diff

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

Yet further progress. Since I'm no longer trying to support method privacy, it turns out the call stack isn't needed at all. This insight came to me while reading Dean Edwards' Base.js. Unit tests of the slimmer framework here: http://groupspace.org/devben/proto-minimal/test/unit/class.html

  • src/base.js

    old new  
    1 var Class = { 
    2   create: function() { 
    3     return function() {  
    4       this.initialize.apply(this, arguments); 
     1var Class = new (function(vocab) { 
     2   
     3  this.AUTHOR = "Ben Newman (newmanb@stanford.edu)"; 
     4 
     5  var $doNotInit = {}; 
     6   
     7  this.create = function(declarations) { 
     8     
     9    var constructor = function() { 
     10      if (arguments[0] !== $doNotInit) { 
     11        this._runTimeDeclarations = {}; 
     12        if (this[vocab['init']]) 
     13          this[vocab['init']].apply(this, arguments); 
     14      } 
     15    }; 
     16 
     17    if (declarations) { 
     18      var ownPrototype = function() { 
     19        for (var name in declarations) { 
     20          declarations[name].ancestor = baseInstance[name]; 
     21          __attachClassProperty(name, declarations[name], this); 
     22        } 
     23        __ensureDefaults(this, declarations); 
     24        __ensureOwnPrototypeMemory(this, declarations); 
     25      }; 
     26 
     27      var base = declarations.extending || {}; 
     28      var baseInstance = __inherit(ownPrototype, base); 
     29       
     30      declarations['getBaseInstance'] = Class.encap(baseInstance); 
     31       
     32      __setupAttachDelete(declarations); 
     33      __inherit(constructor, ownPrototype); 
     34      __enableMimicry(constructor); // experimental 
     35 
     36      constructor['extend'] = function(declarations) { 
     37        declarations['extending'] = constructor; 
     38        return Class.create(declarations); 
     39      } // a la Dean Edwards' Base.js 
    540    } 
    6   } 
    7 
     41     
     42    return constructor; 
     43  }; 
    844 
     45  var __enableMimicry = function(__ctor) { 
     46    var __old = __ctor.prototype; 
     47    __ctor['mimic'] = function(obj) { 
     48      var __new = Object.extend(obj, __old); 
     49      __ensureDefaults(__new, __old); 
     50      return Object.extend(function() { 
     51        return __ctor.apply(this, arguments); 
     52      }, { 'prototype': __new }); 
     53    }; 
     54  }; 
     55 
     56  var __inherit = function(subclass, superclass) { 
     57     
     58    switch (typeof(superclass)) { 
     59      case 'object': default: 
     60        superclass[vocab['init']] = superclass.constructor; 
     61        subclass.prototype = superclass; break; 
     62      case 'function': 
     63        superclass.getInstance = superclass.getInstance || 
     64          Class.encap(new superclass($doNotInit)); 
     65        subclass.prototype = superclass.getInstance(); 
     66    } 
     67     
     68    return subclass.prototype; 
     69     
     70  }; 
     71 
     72  var __setupAttachDelete = function(declarations) { 
     73    return Object.extend(declarations, { 
     74       
     75      'attachMethod': function(fnName, func) { 
     76        if (!this.ownPrototypeHas(fnName)) { 
     77          this._runTimeDeclarations[fnName] = true; 
     78          func.ancestor = this[fnName]; 
     79          __attachClassProperty(fnName, func, this); 
     80        } else throw "Can't replace existing methods." 
     81      }, 
     82       
     83      'deleteMethod': function(fnName) { 
     84        if (this._runTimeDeclarations[fnName]) { 
     85          __attachClassProperty(fnName, null, this, true); 
     86          this._runTimeDeclarations[fnName] = false; 
     87        } else throw "Only attachMethod additions can be deleted." 
     88      } 
     89       
     90    }); 
     91  }; 
     92 
     93  var __validOverride = function(propName, hasAncestor) { 
     94    switch (propName) { 
     95    case vocab['super']: case 'valueOf': 
     96    case 'attachMethod': case 'deleteMethod': 
     97    case 'getBaseInstance': return false; 
     98    default: return !!hasAncestor; 
     99    } 
     100  }; 
     101   
     102  var __attachClassProperty = function(propName, prop, obj, 
     103                                       /*optional*/ removeInstead) { 
     104    if (removeInstead) { 
     105       
     106      if (obj.ownPrototypeHas(propName)) 
     107        delete obj[propName]; 
     108       
     109    } else if (typeof(prop) == 'function' && 
     110               __validOverride(propName, !!prop.ancestor)) { 
     111                  
     112      obj[propName] = function() { 
     113        var __superSaver = this[vocab['super']]; 
     114        this[vocab['super']] = prop.ancestor; 
     115        try { var result = prop.apply(this, arguments); } 
     116        catch (ex) { throw ex; } 
     117        finally { this[vocab['super']] = __superSaver; } 
     118        return result; 
     119      }; 
     120       
     121      obj[propName].valueOf = Class.encap(prop); 
     122 
     123      var __origStr = prop.toString(); 
     124      prop.toString = obj[propName].toString = function() { 
     125        return __origStr.replace(/^\s*function/, propName); 
     126      }; 
     127       
     128    } else obj[propName] = prop; 
     129     
     130  }; 
     131 
     132  var __ensureDefaults = function(ownPrototype, declarations) { 
     133    ['toString', 'toLocaleString', 'valueOf'].each(function(propName) { 
     134      var prop = declarations[propName]; 
     135      if (!!prop) { 
     136        prop.ancestor = ownPrototype[propName]; 
     137        __attachClassProperty(propName, prop, ownPrototype); 
     138      } 
     139    }); 
     140  }; 
     141 
     142  var __ensureOwnPrototypeMemory = function(ownPrototype, declarations) { 
     143    ownPrototype.ownPrototypeHas = function(property) { 
     144      return (typeof(declarations[property]) != 'undefined' || 
     145              (this._runTimeDeclarations && // present if instantiated 
     146               this._runTimeDeclarations[property])); 
     147    }; 
     148  }; 
     149 
     150  // convenient mechanism for creating accessor functions 
     151  this.encap = function(__val, mutable) { 
     152    if (!mutable) return function() { return __val; } 
     153    else return function(/* optional new value */) { 
     154      if (arguments.length > 0) __val = arguments[0]; 
     155      return __val; 
     156    } 
     157  }; 
     158   
     159})( // the vocabulary is arbitrary: 
     160{'super': 'sup', 'init': 'initialize'}); 
     161 
    9162var Abstract = new Object(); 
    10163 
    11164Object.extend = function(destination, source) {