diff --git a/lib/class.js b/lib/class.js index ec398cd..ae370b4 100644 --- a/lib/class.js +++ b/lib/class.js @@ -422,7 +422,12 @@ var implement = function() arg = args[ i ]; // copy all interface methods to the class (does not yet deep copy) - util.propCopy( arg.prototype, dest ); + util.propParse( arg.prototype, { + method: function( name, func, is_abstract, keywords ) + { + dest[ name ] = func; + }, + } ); implemented.push( arg ); } diff --git a/lib/util.js b/lib/util.js index 111c34e..a69ab06 100644 --- a/lib/util.js +++ b/lib/util.js @@ -252,111 +252,6 @@ exports.propParse = function( data, options ) }; -/** - * Copies properties to the destination object - * - * If the method already exists, it will be overridden and accessible via either - * the parent prototype or by invoking this.__super(). - * - * The destination object is directly modified. - * - * The result data will be populated with information from the copy that may be - * useful to the creation of the class (e.g. list of the abstract methods). - * - * @param {Object} props properties to copy - * @param {Object} dest destination object - * @param {Object} actions parser actions (see propParse()) - * - * @return undefined - */ -exports.propCopy = function( props, dest, actions ) -{ - actions = actions || {}; - - var useOr = function( use, or ) - { - if ( use instanceof Function ) - { - // allow the override to invoke the default implementation - use.performDefault = or; - return use; - } - - // use the default - return or; - }; - - // substitute default functionality if needed - var parse_actions = { - each: useOr( actions.each, function( name, value ) - { - // methods can only be overridden with methods - if ( ( dest[ name ] instanceof Function ) - && ( !( value instanceof Function ) ) - ) - { - throw new TypeError( "Cannot override method with non-method" ); - } - } ), - - property: useOr( actions.property, function( name, value ) - { - dest[ name ] = value; - } ), - - getter: useOr( actions.getter, function( name, func ) - { - dest.__defineGetter__( name, func ); - } ), - - setter: useOr( actions.setter, function( name, func ) - { - dest.__defineSetter__( name, func ); - } ), - - method: useOr( actions.method, function( name, func, is_abstract ) - { - var pre = dest[ name ]; - - // check for override - if ( pre !== undefined ) - { - if ( pre instanceof Function ) - { - // use provided method override action, or fall back to - // generic override - var overrideFunc = useOr( actions.methodOverride, - function( name, pre, func ) - { - return exports.overrideMethod( name, pre, func ); - } - ); - - // use call(), passing self in as context, to ensure 'this' - // will reference the function itself - dest[ name ] = overrideFunc.call( - overrideFunc, name, pre, func - ); - } - else - { - throw new TypeError( - "Cannot override property '" + name + "' with method" - ); - } - } - else - { - // simply copy over the method - dest[ name ] = func; - } - } ), - }; - - exports.propParse( props, parse_actions ); -}; - - /** * Creates an abstract method * @@ -403,73 +298,6 @@ exports.isAbstractMethod = function( func ) }; -/** - * Overrides a method - * - * The given method must be a function or an exception will be thrown. - * - * @param {string} name method name - * @param {Function} super_method method to override - * @param {Function} new_method method to override with - * @param {Array.=} abstract_methods list of abstract methods - * - * @return {Function} overridden method - */ -exports.overrideMethod = function( - name, super_method, new_method, abstract_methods -) -{ - abstract_methods = abstract_methods || []; - - // it's much faster to lookup a hash than it is to iterate through an entire - // array each time we need to find an existing abstract method - var abstract_map = {}; - for ( var i = 0, len = abstract_methods.length; i < len; i++ ) - { - var method = abstract_methods[ i ]; - abstract_map[ method ] = i; - } - - if ( abstract_map[ name ] !== undefined ) - { - var is_abstract = exports.isAbstractMethod( new_method ); - - if ( super_method.definition instanceof Array ) - { - var arg_len = ( is_abstract ) - ? new_method.definition.length - : new_method.length; - - // ensure the concrete definition is compatible with - // that of its supertype - if ( arg_len < super_method.definition.length ) - { - throw new TypeError( - "Declaration of " + name + " must be compatiable " + - "with that of its supertype" - ); - } - } - } - - // this is the method that will be invoked when the requested - // method is called, so note that in the context of this - // function, `this` will represent the current class instance - return function() - { - var tmp = this.__super; - - // assign _super temporarily for the method invocation so - // that the method can call the parent method - this.__super = super_method; - var retval = new_method.apply( this, arguments ); - this.__super = tmp; - - return retval; - } -}; - - /** * Shrinks an array, removing undefined elements * diff --git a/test/test-util-prop-copy.js b/test/test-util-prop-copy.js deleted file mode 100644 index e574f65..0000000 --- a/test/test-util-prop-copy.js +++ /dev/null @@ -1,145 +0,0 @@ -/** - * Tests util.propCopy - * - * Copyright (C) 2010 Mike Gerwitz - * - * This file is part of ease.js. - * - * ease.js is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - * - * @author Mike Gerwitz - * @package test - */ - -var common = require( './common' ), - assert = require( 'assert' ), - propCopy = common.require( 'util' ).propCopy; - - get_set = ( Object.prototype.__defineGetter__ ) ? true : false; - - props = { - one: 1, - two: 2, - - method: function two() {}, - }, - dest = {} -; - -if ( get_set ) -{ - props.__defineGetter__( 'val', function () {} ); - props.__defineSetter__( 'val', function () {} ); -} - -propCopy( props, dest ); -assert.ok( - ( ( dest.one === props.one ) && ( dest.two === props.two ) ), - "All properties should be copied to the destination object" -); - -var each = false, - prop = false, - method = false, - getter = false, - setter = false, - override = false, - - override_data = []; - -var test_val = 'foobar', - dest2_orig_method = function() { return test_val; }; - -var dest2 = { - // will cause methodOverride action to be invoked - method: dest2_orig_method, -}; - -propCopy( props, dest2, { - each: function foo() - { - each = this.performDefault; - }, - - property: function() - { - prop = this.performDefault; - }, - - method: function( name, func ) - { - // perform default action to ensure methodOverride() is called - ( method = this.performDefault )( name, func ); - }, - - getter: function() - { - getter = this.performDefault; - }, - - setter: function() - { - setter = this.performDefault; - }, - - methodOverride: function( name, pre, func ) - { - override = this.performDefault; - override_data = [ name, pre, func ]; - }, -} ); - -var check = [ each, prop, method, override ], - check_i = check.length, - item = null -; - -if ( get_set ) -{ - check.push( getter ); - check.push( setter ); -} - -while ( check_i-- ) -{ - item = check[ check_i ]; - - assert.notEqual( - item, - false, - "Can override propCopy() parser functions [" + check_i + "]" - ); - - assert.ok( - ( item instanceof Function ), - "propCopy() parser function overrides can invoke default " + - "functionality [" + check_i + "]" - ); -} - -assert.ok( - ( override_data[ 0 ] === 'method' ), - "methodOverride action is passed correct method name" -); - -assert.ok( - ( override_data[ 1 ]() === test_val ), - "methodOverride action is passed correct original function" -); - -assert.ok( - ( override_data[ 2 ] === props.method ), - "methodOverride action is passed correct override function" -); -