Skip to content

Instantly share code, notes, and snippets.

@tbtlr
Created July 14, 2010 08:15
Show Gist options
  • Save tbtlr/475171 to your computer and use it in GitHub Desktop.
Save tbtlr/475171 to your computer and use it in GitHub Desktop.
/*
* def.js: Simple Ruby-style inheritance for JavaScript
*
* Copyright (c) 2010 Tobias Schneider
* This script is freely distributable under the terms of the MIT license.
*/
(function(global) {
__super__ = function(){
var caller = __super__.caller;
if(caller !== caller._super){ return caller._super.apply(caller, arguments); }
}
// used to defer setup of superclass and plugins
var deferred;
function addPlugins(plugins) {
augment(this.prototype, plugins);
return this;
}
// TODO: Ensure we fix IE to iterate over shadowed properties
// of those further up the prototype chain. There is also a
// bug in Safari 2 that will match the shadowed property and
// the one further up the prototype chain.
function augment(destination, source) {
for (var key in source) {
var existing = destination[key], newValue = source[key];
// check if we're overwriting an existing function
destination[key] = typeof newValue == "function" && typeof existing == "function" ?
(function(_super, base){
return function(){
var self = this;
base._super = function(){
_super.apply(self, arguments);
}
return base.apply(this, arguments);
}
})(existing, newValue) : newValue;
}
}
// dummy subclass
function Subclass() { }
function def(klassName, context) {
context || (context = global);
if(context[klassName]) return context[klassName];
// create class on given context (defaults to global object)
var Klass =
context[klassName] = function Klass() {
// called as a constructor
if (this != context) {
// allow the init method to return a different class/object
return this.init && this.init.apply(this, arguments);
}
// called as a method
// defer setup of superclass and plugins
deferred._super = Klass;
deferred._plugins = arguments[0] || { };
};
// add static helper method
Klass.addPlugins = addPlugins;
// called as function when not
// inheriting from a superclass
deferred = function(plugins) {
return Klass.addPlugins(plugins);
};
// valueOf is called to setup
// inheritance from a superclass
deferred.valueOf = function() {
var Superclass = deferred._super;
if (!Superclass) return Klass;
Subclass.prototype = Superclass.prototype;
Klass.prototype = new Subclass;
Klass.superclass = Superclass;
Klass.prototype.constructor = Klass;
return Klass.addPlugins(deferred._plugins);
};
return deferred;
}
// expose
global.def = def;
})(this);
// Example
def ('Person') ({
'init': function(name) {
this.name = name;
},
'speak': function(text) {
alert(text || 'Hi, my name is ' + this.name);
}
});
def ('Ninja') << Person ({
'init': function(name) {
__super__();
},
'kick': function() {
this.speak('I kick u!');
}
});
var ninjy = new Ninja('JDD');
ninjy.speak();
ninjy.kick();
@bgerrissen
Copy link

new Ninja('JDD'); didn't pass the argument to super.
Fix:

__super__ = function(){
    var caller = __super__.caller;
    if(caller !== caller._super){ return caller._super.apply(caller, arguments); }
}

@tbtlr
Copy link
Author

tbtlr commented Jul 14, 2010

Oh, you're right... Totally overlooked it. Thx!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment