Last active
March 28, 2016 12:27
-
-
Save jcoglan/fa555de2e97923e87e58 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var Object_create, Object_assign, Module, Include, Kernel, Class; | |
var hasOwnProperty = Object.prototype.hasOwnProperty; | |
Object_create = Object.create || function(prototype) { | |
var f = function() {}; | |
f.prototype = prototype; | |
return new f(); | |
}; | |
Object_assign = Object.assign || function(destination, source) { | |
for (var key in source) destination[key] = source[key]; | |
return destination; | |
}; | |
/*----------------------------------------------------------------------------*/ | |
Module = function(name, methods) { | |
if (typeof name !== 'string') { | |
methods = name; | |
} | |
this.__id = ++ Module.__ID; | |
this.__name = name; | |
this.__super = this.__super || null; | |
this.__includes = {}; | |
this.__methods = {}; | |
this.__source = this; | |
this.include(methods); | |
}; | |
Module.__ID = 0; | |
Object_assign(Module.prototype, { | |
__ancList: null, | |
__ancSet: null, | |
__id: null, | |
__includes: null, | |
__methods: null, | |
__name: null, | |
__source: null, | |
__super: null, | |
inspect: function() { | |
return this.__name; | |
}, | |
ancestors: function() { | |
if (this.__ancList) return this.__ancList; | |
var rest = this.__super ? this.__super.ancestors() : [], | |
list = [this.__source].concat(rest); | |
return this.__ancList = list; | |
}, | |
_ancestorSet: function() { | |
if (this.__ancSet) return this.__ancSet; | |
var rest = this.__super ? this.__super._ancestorSet() : null, | |
set = Object_create(rest); | |
set[this.__source.__id] = true; | |
return this.__ancSet = set; | |
}, | |
define: function(name, method) { | |
this.__methods[name] = method; | |
this._propagate(name); | |
}, | |
_propagate: function(name, method) { | |
for (var id in this.__includes) | |
this.__includes[id]._propagate(name, method); | |
}, | |
include: function(methods) { | |
var mixins, name, value, i, n; | |
if (methods instanceof Module) return this._includeModule(methods); | |
if (typeof methods !== 'object') return; | |
mixins = methods.extend; | |
if (typeof mixins === 'object') { | |
mixins = [].concat(mixins); | |
for (i = 0, n = mixins.length; i < n; i++) this.extend(mixins[i]); | |
} | |
mixins = methods.include; | |
if (typeof mixins === 'object') { | |
mixins = [].concat(mixins); | |
for (i = 0, n = mixins.length; i < n; i++) this.include(mixins[i]); | |
} | |
for (name in methods) { | |
value = methods[name]; | |
if (typeof value === 'function') this.define(name, value); | |
} | |
}, | |
_includeModule: function(module) { | |
var ours = this._ancestorSet(), | |
theirs = module.ancestors(), | |
host = this.__host || this, | |
next = this, | |
prev = this.__super, | |
ancestor, include; | |
var i = 0, n = theirs.length; | |
while (n - i++) { | |
ancestor = theirs[i - 1]; | |
if (ancestor.__id in ours) continue; | |
include = ancestor._createInclude(host); | |
include.__sub = next; | |
next.__super = include; | |
this._prune(ancestor); | |
include._cascade(); | |
next = include; | |
} | |
next.__super = prev; | |
if (prev) prev._subclass(next); | |
for (var id in this.__includes) | |
this.__includes[id]._includeModule(module); | |
}, | |
_createInclude: function(host) { | |
var include = new Include(this, host); | |
this.__includes[include.__id] = include; | |
return include; | |
}, | |
_prune: function(module) { | |
this.__ancList = this.__ancSet = null; | |
} | |
}); | |
/*----------------------------------------------------------------------------*/ | |
Include = function(source, host) { | |
this.__id = ++ Module.__ID; | |
this.__source = source; | |
this.__methods = source.__methods; | |
this.__host = host; | |
}; | |
Object_assign(Include.prototype, { | |
__ancList: null, | |
__ancSet: null, | |
__host: null, | |
__id: null, | |
__methods: null, | |
__source: null, | |
__sub: null, | |
__super: null, | |
ancestors: Module.prototype.ancestors, | |
_ancestorSet: Module.prototype._ancestorSet, | |
_includeModule: Module.prototype._includeModule, | |
_subclass: function(module) { | |
this.__sub = module; | |
}, | |
_cascade: function() { | |
for (var name in this.__methods) this._propagate(name); | |
}, | |
_propagate: function(name, method) { | |
if (this.__host.constructor === Module) return; | |
if (hasOwnProperty.call(this.__methods, name)) | |
method = this.__methods[name]; | |
this.__sub._propagate(name, method); | |
}, | |
_prune: function(module) { | |
this.__ancList = this.__ancSet = null; | |
var sub = this.__sub; | |
if (module && sub.__source === module) { | |
this.__sub = sub.__sub; | |
this.__sub.__super = this; | |
delete sub.__source.__includes[sub.__id]; | |
this.__sub._prune(null); | |
} else { | |
return sub._prune(module); | |
} | |
} | |
}); | |
/*----------------------------------------------------------------------------*/ | |
Kernel = new Module('Kernel', { | |
__eigen__: function() { | |
if (!this.__meta) { | |
var name = '#<Class:' + this.inspect() + '>', | |
parent = (this.superclass || {}).__meta || this.klass; | |
this.__meta = new Class(name, parent, {}, {_target: this, _virtual: true}); | |
} | |
return this.__meta; | |
}, | |
extend: function(module) { | |
this.__eigen__().include(module, {_extended: this}); | |
} | |
}); | |
/*----------------------------------------------------------------------------*/ | |
Class = function(name, superclass, methods, options) { | |
if (typeof name !== 'string') { | |
options = methods; methods = superclass; superclass = name; name = ''; | |
} | |
if (typeof superclass !== 'function') { | |
options = methods; methods = superclass; superclass = null; | |
} | |
if (typeof options === 'undefined') { | |
options = {}; | |
} | |
var self = function() { | |
var value = this.initialize && this.initialize.apply(this, arguments); | |
return value || this; | |
}; | |
Object_assign(self, this); | |
if (superclass) self.prototype = Object_create(superclass.prototype); | |
self.prototype.constructor = self.prototype.klass = self; | |
self.__super = self.superclass = superclass || null; | |
self.__subs = {}; | |
self.__target = options._target || self.prototype; | |
self.__cache = {}; | |
Module.call(self, name, methods); | |
self.include(Kernel); | |
if (options._virtual) { | |
superclass = self.__super; | |
for (name in superclass.__cache) | |
self._propagate(name, superclass.__cache[name]); | |
} else { | |
self.__eigen__(); | |
} | |
return self; | |
}; | |
Class.prototype = Object_assign(Object_create(Module.prototype), { | |
__cache: null, | |
__subs: null, | |
__target: null, | |
_subclass: function(module) { | |
var host = module.__host || module; | |
this.__subs[host.__id] = module; | |
}, | |
_propagate: function(name, method) { | |
if (hasOwnProperty.call(this.__methods, name)) | |
method = this.__methods[name]; | |
this.__cache[name] = method; | |
if (this.__target[name] !== method) | |
this.__target[name] = method; | |
for (var id in this.__subs) | |
this.__subs[id]._propagate(name, method); | |
}, | |
_prune: function(module) { | |
this.__ancList = this.__ancSet = null; | |
var id, sub; | |
for (id in this.__subs) { | |
sub = this.__subs[id]; | |
if (module && sub.__source === module) { | |
this.__subs[sub.__host.__id] = sub.__sub; | |
sub.__sub.__super = this; | |
delete sub.__source.__includes[sub.__id]; | |
sub.__sub._prune(null); | |
} else { | |
sub._prune(module); | |
} | |
} | |
} | |
}); | |
/*----------------------------------------------------------------------------*/ | |
(function() { | |
var Ruby = {Module: Module, Kernel: Kernel, Class: Class}; | |
var bootstrap = function(name, parent) { | |
var klass = Ruby[name]; | |
Object_assign(klass, Class.prototype); | |
klass.constructor = klass.klass = Class; | |
klass.__id = ++ Module.__ID; | |
klass.__name = name; | |
klass.__super = klass.superclass = parent || null; | |
klass.__subs = {}; | |
klass.__includes = {}; | |
klass.__methods = Object_assign({}, klass.prototype); | |
klass.__source = klass; | |
klass.__target = klass.prototype; | |
klass.__cache = {}; | |
klass.include(Kernel); | |
klass.prototype.constructor = klass.prototype.klass = klass; | |
}; | |
bootstrap('Module'); | |
bootstrap('Class', Module); | |
var eigen = Kernel.__methods.__eigen__; | |
eigen.call(Module); | |
eigen.call(Class); | |
Module.__super._cascade(); | |
module.exports = Ruby; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment