/** * Expose `Delegator`. */ module.exports = Delegator; /** * Initialize a delegator. * * @param {Object} proto * @param {String} target * @api public */ function Delegator(proto, target) { if (!(this instanceof Delegator)) return new Delegator(proto, target); this.proto = proto; this.target = target; this.methods = []; this.getters = []; this.setters = []; this.fluents = []; } /** * Automatically delegate properties * from a target prototype * * @param {Object} proto * @param {object} targetProto * @param {String} targetProp * @api public */ Delegator.auto = function(proto, targetProto, targetProp) { let delegator = Delegator(proto, targetProp); let properties = Object.getOwnPropertyNames(targetProto); for (let i = 0; i < properties.length; i++) { let property = properties[i]; let descriptor = Object.getOwnPropertyDescriptor(targetProto, property); if (descriptor.get) { delegator.getter(property); } if (descriptor.set) { delegator.setter(property); } if (descriptor.hasOwnProperty('value')) { // could be undefined but writable let value = descriptor.value; if (value instanceof Function) { delegator.method(property); } else { delegator.getter(property); } if (descriptor.writable) { delegator.setter(property); } } } }; /** * Delegate method `name`. * * @param {String} name * @return {Delegator} self * @api public */ Delegator.prototype.method = function(name) { let proto = this.proto; let target = this.target; this.methods.push(name); proto[name] = function() { return this[target][name].apply(this[target], arguments); }; return this; }; /** * Delegator accessor `name`. * * @param {String} name * @return {Delegator} self * @api public */ Delegator.prototype.access = function(name) { return this.getter(name).setter(name); }; /** * Delegator getter `name`. * * @param {String} name * @return {Delegator} self * @api public */ Delegator.prototype.getter = function(name) { let proto = this.proto; let target = this.target; this.getters.push(name); proto.__defineGetter__(name, function() { return this[target][name]; }); return this; }; /** * Delegator setter `name`. * * @param {String} name * @return {Delegator} self * @api public */ Delegator.prototype.setter = function(name) { let proto = this.proto; let target = this.target; this.setters.push(name); proto.__defineSetter__(name, function(val) { return this[target][name] = val; }); return this; }; /** * Delegator fluent accessor * * @param {String} name * @return {Delegator} self * @api public */ Delegator.prototype.fluent = function(name) { let proto = this.proto; let target = this.target; this.fluents.push(name); proto[name] = function(val) { if ('undefined' != typeof val) { this[target][name] = val; return this; } else { return this[target][name]; } }; return this; };