From 243f056d01a360fac7a5968e8ba1a1966575fb9d Mon Sep 17 00:00:00 2001 From: Robert Massa Date: Sun, 31 Oct 2010 13:58:28 +0100 Subject: [PATCH] Added getter and setter inheritance + tests --- classy.js | 48 +++++++++++++++++++++++++++++++++--------------- tests/core.js | 15 +++++++++++++++ tests/data.js | 17 ++++++++++++++++- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/classy.js b/classy.js index 2740d41..d7abd47 100644 --- a/classy.js +++ b/classy.js @@ -1,7 +1,7 @@ /** * Classy - classy classes for JavaScript * - * :copyright: (c) 2010 by Armin Ronacher. + * :copyright: (c) 2010 by Armin Ronacher. * :license: BSD. */ @@ -44,6 +44,26 @@ return rv; } + /* wraps a function adding a $super variable */ + function wrapForSuper(super_prototype, meth, name, type) { + return function() { + var old_super = getOwnProperty(this, '$super'); + if (type === 'getter') + this.$super = super_prototype.__lookupGetter__(name); + else if (type === 'setter') + this.$super = super_prototype.__lookupSetter__(name); + else + this.$super = super_prototype[name]; + + try { + return meth.apply(this, arguments); + } + finally { + setOrUnset(this, '$super', old_super); + } + }; + } + /* the base class we export */ var Class = function() {}; @@ -83,7 +103,7 @@ prototype[name] = mixin[name]; } } - + /* copy class vars from the superclass */ properties.__classvars__ = properties.__classvars__ || {}; if (prototype.__classvars__) @@ -95,24 +115,22 @@ /* copy all properties over to the new prototype */ for (var name in properties) { + var getter = properties.__lookupGetter__(name), + setter = properties.__lookupSetter__(name); + if (getter || setter) { + if (getter) + prototype.__defineGetter__(name, usesSuper(getter) ? wrapForSuper(super_prototype, getter, name, 'getter') : getter); + if (setter) + prototype.__defineSetter__(name, usesSuper(setter) ? wrapForSuper(super_prototype, setter, name, 'setter') : setter); + continue; + } + var value = getOwnProperty(properties, name); if (name === '__include__' || value === undefined) continue; - prototype[name] = typeof value === 'function' && usesSuper(value) ? - (function(meth, name) { - return function() { - var old_super = getOwnProperty(this, '$super'); - this.$super = super_prototype[name]; - try { - return meth.apply(this, arguments); - } - finally { - setOrUnset(this, '$super', old_super); - } - }; - })(value, name) : value + prototype[name] = typeof value === 'function' && usesSuper(value) ? wrapForSuper(super_prototype, value, name) : value } /* dummy constructor */ diff --git a/tests/core.js b/tests/core.js index 8c25f22..3c140fa 100644 --- a/tests/core.js +++ b/tests/core.js @@ -79,6 +79,21 @@ test('basic classical inheritence works', function() { 'base HouseCat is not affected by subclass mutations'); }); +test('inheritance of getters and setters works', function() { + cat = Cat(); + parasite = Parasite(); + lion = Lion(); + + equal(cat.furryness, 20, + 'getter was inherted from base') + + equal(parasite.furryness, 0, + 'getters can override base') + + equal(lion.furryness, 40, + 'getters can use $super to get base getter') +}); + test('instanceof works', function() { var lion = Lion(); ok(lion instanceof Lion, diff --git a/tests/data.js b/tests/data.js index 5b17e20..94040aa 100644 --- a/tests/data.js +++ b/tests/data.js @@ -7,6 +7,7 @@ var Animal = Class.$extend({ // required defaults this.name = (typeof(options.name) == 'string' ? options.name : 'Animal'); this.health = (typeof(options.health) == 'integer' ? options.health : 100); + this._furryness = (typeof(options.furryness) == 'integer' ? options.furryness : 20); }, die: function() { @@ -19,6 +20,14 @@ var Animal = Class.$extend({ dead: function() { return (this.health <= 0); + }, + + get furryness() { + return this._furryness; + }, + + set furryness(val) { + this._furryness = val; } }); @@ -26,6 +35,9 @@ var Parasite = Animal.$extend({ eat: function(animal) { this.$super(animal); animal.health -= 5; + }, + get furryness() { + return 0; } }); @@ -43,5 +55,8 @@ var HouseCat = Cat.$extend({ var Lion = Cat.$extend({ 'cute': false, - 'scary': true + 'scary': true, + get furryness() { + return this.$super() * 2; + } });