Skip to content

Instantly share code, notes, and snippets.

@bttmly
Last active August 29, 2015 14:01
Show Gist options
  • Save bttmly/40b0a753de3062ab2d3d to your computer and use it in GitHub Desktop.
Save bttmly/40b0a753de3062ab2d3d to your computer and use it in GitHub Desktop.
Function to compose a class from other classes.
compose = do ->
each = ( obj, itr ) ->
list = if Array.isArray( obj ) then obj.map ( e, i ) -> i else Object.keys( obj )
i = 0
while i < list.length
itr( obj[ list[i] ], list[ i ], obj )
i += 1
obj
isFunction = ( obj ) ->
obj and Object.prototype.toString.call( obj ) is "[object Function]"
getPrototypeChain = ( obj ) ->
chain = []
obj = obj.prototype if isFunction( obj )
chain.push( obj )
chain.push( obj ) while obj = Object.getPrototypeOf( obj )
chain
getPrototypeMethods = ( proto ) ->
proto = proto.prototype if isFunction( proto )
Object.getOwnPropertyNames( proto ).filter ( propName ) ->
isFunction proto[ propName ]
( opt ) ->
{ parent, toCompose, bindMethods, bindCallbacks } = opt
each toCompose, ( cl, prop ) =>
each getPrototypeChain( cl.prototype ), ( proto ) =>
each getPrototypeMethods( proto ), ( method ) =>
unless parent::[method]
parent::[method] = ->
context = if bindMethods then @ else @[prop]
args = [].slice.call arguments
if bindCallbacks
args = args.map ( arg ) ->
if isFunction( arg ) then arg.bind( context ) else arg
proto[method].apply( context, args )
var compose;
compose = (function() {
var each, getPrototypeChain, getPrototypeMethods, isFunction;
each = function(obj, itr) {
var i, list;
list = Array.isArray(obj) ? obj.map(function(e, i) {
return i;
}) : Object.keys(obj);
i = 0;
while (i < list.length) {
itr(obj[list[i]], list[i], obj);
i += 1;
}
return obj;
};
isFunction = function(obj) {
return obj && Object.prototype.toString.call(obj) === "[object Function]";
};
getPrototypeChain = function(obj) {
var chain;
chain = [];
if (isFunction(obj)) {
obj = obj.prototype;
}
chain.push(obj);
while (obj = Object.getPrototypeOf(obj)) {
chain.push(obj);
}
return chain;
};
getPrototypeMethods = function(proto) {
if (proto.constructor !== Function) {
proto = proto.constructor;
}
if (isFunction(proto)) {
proto = proto.prototype;
}
return Object.getOwnPropertyNames(proto).filter(function(propName) {
return isFunction(proto[propName]);
});
};
return function(opt) {
var bindCallbacks, bindMethods, parent, toCompose;
parent = opt.parent, toCompose = opt.toCompose, bindMethods = opt.bindMethods, bindCallbacks = opt.bindCallbacks;
return each(toCompose, (function(_this) {
return function(cl, prop) {
return each(getPrototypeChain(cl.prototype), function(proto) {
return each(getPrototypeMethods(proto), function(method) {
if (!parent.prototype[method]) {
return parent.prototype[method] = function() {
var args, context;
context = bindMethods ? this : this[prop];
args = [].slice.call(arguments);
if (bindCallbacks) {
args = args.map(function(arg) {
if (isFunction(arg)) {
return arg.bind(context);
} else {
return arg;
}
});
}
return proto[method].apply(context, args);
};
}
});
});
};
})(this));
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment