Skip to content

Instantly share code, notes, and snippets.

@rwaldron
Forked from tbtlr/def.js
Created March 22, 2011 01:37
Show Gist options
  • Save rwaldron/880602 to your computer and use it in GitHub Desktop.
Save rwaldron/880602 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();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment