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

Changeset 7833

Show
Ignore:
Timestamp:
10/11/07 05:02:07 (9 months ago)
Author:
sam
Message:

prototype: Clean up the new class API.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • spinoffs/prototype/trunk/CHANGELOG

    r7811 r7833  
    11*SVN* 
     2 
     3* Clean up the new class API.  [sam, Tobie Langel] 
     4  - Add Class#addMethods for adding instance methods to classes.   
     5  - Remove Class.extend and Class.mixin.   
     6  - Class.create now takes a variable number of arguments: if the first argument is a class, the newly created class inherits from that class; all other arguments are treated as successive calls to addMethods. 
    27 
    38* Fix contentloaded event initialization in IE.  Closes #9457, #9488, #9707.  [Mislav Marohnić] 
  • spinoffs/prototype/trunk/src/base.js

    r7808 r7833  
    11/* Based on Alex Arnell's inheritance implementation. */ 
    22var Class = { 
    3   create: function(parent, properties) { 
    4     if (arguments.length == 1 && !Object.isFunction(parent)) 
    5       properties = parent, parent = null; 
     3  create: function() { 
     4    var parent = null, properties = $A(arguments); 
     5    if (Object.isFunction(properties[0])) 
     6      parent = properties.shift(); 
    67     
    78    function klass() { 
    89      this.initialize.apply(this, arguments); 
    910    } 
    10    
     11     
     12    Object.extend(klass, Class.Methods); 
    1113    klass.superclass = parent; 
    1214    klass.subclasses = []; 
    13    
     15     
    1416    if (parent) { 
    1517      var subclass = function() { }; 
     
    1820      parent.subclasses.push(klass); 
    1921    } 
    20  
    21     if (properties) Class.extend(klass, properties); 
     22     
     23    for (var i = 0; i < properties.length; i++) 
     24      klass.addMethods(properties[i]); 
     25       
    2226    if (!klass.prototype.initialize) 
    2327      klass.prototype.initialize = Prototype.emptyFunction; 
    24        
     28     
    2529    klass.prototype.constructor = klass; 
    26  
     30     
    2731    return klass; 
    28   }, 
    29    
    30   extend: function(destination, source) { 
    31     var ancestor = destination.superclass && destination.superclass.prototype; 
     32  } 
     33}; 
     34 
     35Class.Methods = { 
     36  addMethods: function(source) { 
     37    var ancestor = this.superclass && this.superclass.prototype; 
    3238 
    3339    for (var property in source) { 
     
    4248        }); 
    4349      } 
    44       destination.prototype[property] = value; 
    45     } 
    46      
    47     return destination; 
    48   }, 
    49  
    50   mixin: function(destination, source) { 
    51     return Object.extend(destination.prototype, source); 
     50      this.prototype[property] = value; 
     51    } 
     52     
     53    return this; 
    5254  } 
    5355}; 
  • spinoffs/prototype/trunk/test/unit/base.html

    r7808 r7833  
    7474  // empty subclass 
    7575  var Mouse = Class.create(Animal, {}); 
    76  
     76   
     77  //mixins  
     78  var Sellable = { 
     79    getValue: function(pricePerKilo) { 
     80      return this.weight * pricePerKilo; 
     81    }, 
     82     
     83    inspect: function() { 
     84      return '#<Sellable: #{weight}kg>'.interpolate(this); 
     85    } 
     86  }; 
     87 
     88  var Reproduceable = { 
     89    reproduce: function(partner) { 
     90      if (partner.constructor != this.constructor || partner.sex == this.sex) 
     91        return null; 
     92      var weight = this.weight / 10, sex = Math.random(1).round() ? 'male' : 'female'; 
     93      return new this.constructor('baby', weight, sex); 
     94    } 
     95  }; 
     96   
     97  // base class with mixin 
     98  var Plant = Class.create(Sellable, { 
     99    initialize: function(name, weight) { 
     100      this.name = name; 
     101      this.weight = weight; 
     102    }, 
     103 
     104    inspect: function() { 
     105      return '#<Plant: #{name}>'.interpolate(this); 
     106    } 
     107  }); 
     108   
     109  // subclass with mixin 
     110  var Dog = Class.create(Animal, Reproduceable, { 
     111    initialize: function($super, name, weight, sex) { 
     112      this.weight = weight; 
     113      this.sex = sex; 
     114      $super(name); 
     115    } 
     116  }); 
     117   
     118  // subclass with mixins 
     119  var Ox = Class.create(Animal, Sellable, Reproduceable, { 
     120    initialize: function($super, name, weight, sex) { 
     121      this.weight = weight; 
     122      this.sex = sex; 
     123      $super(name); 
     124    }, 
     125     
     126    eat: function(food) { 
     127      if (food instanceof Plant) 
     128        this.weight += food.weight; 
     129    }, 
     130     
     131    inspect: function() { 
     132      return '#<Ox: #{name}>'.interpolate(this); 
     133    } 
     134  }); 
     135   
    77136  new Test.Unit.Runner({ 
    78137     
     
    420479    testClassCreate: function() { with(this) {  
    421480      assert(Object.isFunction(Animal), 'Animal is not a constructor'); 
    422       assertEnumEqual([Cat, Mouse], Animal.subclasses); 
     481      assertEnumEqual([Cat, Mouse, Dog, Ox], Animal.subclasses); 
    423482      Animal.subclasses.each(function(subclass) { 
    424483        assertEqual(Animal, subclass.superclass); 
     
    473532    }}, 
    474533 
    475     testClassExtend: function() { with(this) { 
     534    testClassAddMethods: function() { with(this) { 
    476535      var tom   = new Cat('Tom'); 
    477536      var jerry = new Mouse('Jerry'); 
    478537       
    479       Class.extend(Animal,
     538      Animal.addMethods(
    480539        sleep: function() { 
    481540          return this.say('ZZZ'); 
     
    483542      }); 
    484543       
    485       Class.extend(Mouse,
     544      Mouse.addMethods(
    486545        sleep: function($super) { 
    487546          return $super() + " ... no, can't sleep! Gotta steal cheese!"; 
     
    499558      assertUndefined(new Animal().escape); 
    500559       
    501       Class.extend(Animal,
     560      Animal.addMethods(
    502561        sleep: function() { 
    503562          return this.say('zZzZ'); 
     
    506565       
    507566      assertEqual("Jerry: zZzZ ... no, can't sleep! Gotta steal cheese!", jerry.sleep()); 
    508     }} 
     567    }}, 
     568     
     569    testBaseClassWithMixin: function() { with(this) { 
     570      var grass = new Plant('grass', 3); 
     571      assertRespondsTo('getValue', grass);       
     572      assertEqual('#<Plant: grass>', grass.inspect()); 
     573    }}, 
     574     
     575    testSubclassWithMixin: function() { with(this) { 
     576      var snoopy = new Dog('Snoopy', 12, 'male'); 
     577      assertRespondsTo('reproduce', snoopy);       
     578   }}, 
     579    
     580   testSubclassWithMixins: function() { with(this) { 
     581      var cow = new Ox('cow', 400, 'female'); 
     582      assertEqual('#<Ox: cow>', cow.inspect()); 
     583      assertRespondsTo('reproduce', cow); 
     584      assertRespondsTo('getValue', cow); 
     585   }} 
    509586 
    510587  }, 'testlog');