Created
May 4, 2009 02:47
-
-
Save appden/106277 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
// FUNCTION BINDING | |
Function.prototype.bind = function(bind, args){ | |
var self = this.unbind(); | |
if (args != null) args = $splat(args); | |
var fn = function(){ | |
return self.apply(bind, args || arguments); | |
}; | |
fn._bound_ = self; | |
return fn; | |
}; | |
Function.prototype.unbind = function(){ | |
return (this._bound_) ? this._bound_.unbind() : this; | |
}; | |
Function.prototype.unbound = function(){ | |
this._unbound_ = true; | |
return this; | |
}; | |
// ACCESSOR -- NOW WITH ABILITY TO PASS IN PRIVATE OBJECT | |
this.Accessor = new Native('Accessor', function(name, accessor){ | |
var Name = (name || '').capitalize(); | |
accessor = accessor || {}; | |
this['define' + Name] = function(key, value){ | |
accessor[key] = value; | |
return this; | |
}.setMany(); | |
this['lookup' + Name] = function(key, value){ | |
return accessor.hasOwnProperty(key) ? accessor[key] : null; | |
}.getMany(); | |
}); | |
// MODIFIED CLASS | |
(function(){ | |
this.Class = new Native('Class', function(params){ | |
if (instanceOf(params, Function)) params = {initialize: params}; | |
var newClass = function(){ | |
resetAll(this); | |
if (newClass._prototyping_) return this; | |
// POST INIT MUTATORS | |
for (var modifier in initializers){ | |
if (this[modifier]) this[modifier] = initializers[modifier].call(this, this[modifier]); | |
} | |
// WRAP METHODS AND AUTO-BIND | |
for (var method in this){ | |
if (this[method]._wrap_) this[method] = wrap.call(this, newClass, method, this[method]); | |
} | |
this._current_ = nil; | |
var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; | |
this._current_ = this.caller = null; | |
return value; | |
}.extend(this); | |
// APPLY CLASS MUTATORS | |
for (var mutator in mutators){ | |
if (!params[mutator]) continue; | |
params[mutator] = mutators[mutator].call(newClass, params[mutator], params); | |
if (params[mutator] == null) delete params[mutator]; | |
} | |
newClass.implement(params); | |
newClass.constructor = Class; | |
newClass.prototype.constructor = newClass; | |
return newClass; | |
}); | |
var resetOne = function(object, key){ | |
delete object[key]; | |
switch (typeOf(object[key])){ | |
case 'object': | |
var F = function(){}; | |
F.prototype = object[key]; | |
var instance = new F; | |
object[key] = resetAll(instance); | |
break; | |
case 'array': object[key] = Object.clone(object[key]); break; | |
} | |
return object; | |
}; | |
var resetAll = function(object){ | |
for (var p in object) resetOne(object, p); | |
return object; | |
}; | |
var getPrototype = function(klass){ | |
klass._prototyping_ = true; | |
var proto = new klass; | |
delete klass._prototyping_; | |
return proto; | |
}; | |
var wrap = function(klass, key, method){ | |
var self = this; | |
if (method._origin_) method = method._origin_; | |
return function(){ | |
if (method._protected_ && self._current_ == null) throw new Error('The method "' + key + '" cannot be called.'); | |
var caller = self.caller, current = self._current_; | |
self.caller = current; self._current_ = arguments.callee; | |
// IF METHOD MARKED UNBOUND, DO NOT BIND | |
var result = method.apply(method._unbound_ ? this : self, arguments); | |
self._current_ = current; self.caller = caller; | |
return result; | |
}.extend({_owner_: klass, _origin_: method, _name_: key}); | |
}; | |
// NOW TAKES A CLASS AS AN ARGUMENT | |
Class.implement('implement', function(key, value){ | |
if (typeof key != 'string'){ | |
if (instanceOf(key, Function)) key = getPrototype(key); | |
for (var prop in key) this.implement(prop, key[prop]); | |
return this; | |
} | |
var proto = this.prototype; | |
switch (typeOf(value)){ | |
case 'function': | |
if (value._hidden_) return this; | |
value._wrap_ = true; // MARK FOR WRAPPING ON INIT | |
proto[key] = value; | |
// proto[key] = wrap(this, key, value); | |
break; | |
case 'object': | |
var previous = proto[key]; | |
if (typeOf(previous) == 'object') Object.merge(previous, value); | |
else proto[key] = Object.clone(value); | |
break; | |
case 'array': | |
proto[key] = Object.clone(value); | |
break; | |
default: proto[key] = value; | |
} | |
return this; | |
}); | |
// PRIVATE TO THIS CLOSURE, ACCESSIBLE TO OUTSIDE WORLD THRU ACCESSORS | |
var mutators = { | |
Extends: function(parent){ | |
this.parent = parent; | |
this.prototype = getPrototype(parent); | |
if (this.prototype.parent == null) this.implement('parent', function(){ | |
var name = this.caller._name_, previous = this.caller._owner_.parent.prototype[name]; | |
if (!previous) throw new Error('The method "' + name + '" has no parent.'); | |
return previous.apply(this, arguments); | |
}.protect()); | |
}, | |
// TEST FOR PASSING IN OTHER CLASSES NOW INSIDE IMPLEMENT METHOD | |
Implements: function(items){ | |
Array.from(items).forEach(function(item){ | |
this.implement(item); | |
}, this); | |
} | |
}; | |
Class.extend(new Accessor('Mutator', mutators)); | |
// POST INIT MUTATORS | |
var initializers = {}; | |
Class.extend(new Accessor('Initializer', initializers)); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment