diff --git a/lib/member_builder.js b/lib/member_builder.js index 0b50692..371f70b 100644 --- a/lib/member_builder.js +++ b/lib/member_builder.js @@ -43,6 +43,46 @@ exports.buildProp = function( members, meta, name, value, keywords ) }; +/** + * Copies a getter to the appropriate member prototype, depending on + * visibility, and assigns necessary metadata from keywords + * + * @param {{public: Object, protected: Object, private: Object}} members + * + * @param {Object} meta metadata container + * @param {string} name getter name + * @param {*} value getter value + * + * @param {Object.} keywords parsed keywords + * + * @return {undefined} + */ +exports.buildGetter = function( members, meta, name, value, keywords ) +{ + getMemberVisibility( members, keywords ).__defineGetter__( name, value ); +}; + + +/** + * Copies a setter to the appropriate member prototype, depending on + * visibility, and assigns necessary metadata from keywords + * + * @param {{public: Object, protected: Object, private: Object}} members + * + * @param {Object} meta metadata container + * @param {string} name setter name + * @param {*} value setter value + * + * @param {Object.} keywords parsed keywords + * + * @return {undefined} + */ +exports.buildSetter = function( members, meta, name, value, keywords ) +{ + getMemberVisibility( members, keywords ).__defineSetter__( name, value ); +}; + + /** * Returns member prototype to use for the requested visibility * diff --git a/test/test-member_builder-gettersetter.js b/test/test-member_builder-gettersetter.js new file mode 100644 index 0000000..4fe908c --- /dev/null +++ b/test/test-member_builder-gettersetter.js @@ -0,0 +1,170 @@ +/** + * Tests getter/setter builder + * + * 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' ), + + buildGetter = common.require( 'member_builder' ).buildGetter, + buildSetter = common.require( 'member_builder' ).buildSetter, + + // member visibility types are quoted because they are reserved keywords + members = {}, + meta = {}, + + // stub values + name = 'foo', + value = function() {} +; + + +function setUp() +{ + // clear out the members for a fresh start + members = { 'public': {}, 'protected': {}, 'private': {} }; +} + + +/** + * Partially applied function to quickly build getter from common test data + */ +function buildGetterSetterQuick( keywords, val ) +{ + keywords = keywords || {}; + val = val || value; + + setUp(); + + buildGetter( members, meta, name, val, keywords ); + buildSetter( members, meta, name, val, keywords ); +} + + +/** + * Asserts that the given property exists only in the prototype for the + * requested visibility + */ +function assertOnlyVisibility( vis, name, value, message ) +{ + var check = [ 'public', 'protected', 'private' ], + i = check.length, + visi = '', + cmp; + + // forEach not used for pre-ES5 browser support + while ( i-- ) + { + visi = check[ i ]; + cmp = ( visi === vis ) ? value : undefined; + + assert.deepEqual( + members[ visi ].__lookupGetter__( name ), + cmp, + ( message + " (0)" ) + ); + + assert.deepEqual( + members[ visi ].__lookupSetter__( name ), + cmp, + ( message + " (1)" ) + ); + } +} + + +( function testRecognizesPublicProperty() +{ + buildGetterSetterQuick( { 'public': true } ); + + assertOnlyVisibility( 'public', + name, + value, + "Public properties are copied only to the public member prototype" + ); +} )(); + + +( function testRecognizesProtectedProperty() +{ + buildGetterSetterQuick( { 'protected': true } ); + + assertOnlyVisibility( 'protected', + name, + value, + "Protected properties are copied only to the protected member prototype" + ); +} )(); + + +( function testRecognizesPrivateProperty() +{ + buildGetterSetterQuick( { 'private': true } ); + + assertOnlyVisibility( 'private', + name, + value, + "Private properties are copied only to the private member prototype" + ); +} )(); + + +( function testCopiedIntoPublicPrototypeByDefault() +{ + buildGetterSetterQuick(); + + assertOnlyVisibility( 'public', + name, + value, + "Properties are copied only to the public member prototype by default" + ); +} )(); + + +( function testThrowsTypeErrorIfMultipleVisibilityKeywordsAreGiven() +{ + assert.throws( function() + { + buildGetterSetterQuick( { + 'public': true, + 'protected': true, + } ); + }, TypeError, "Cannot specify multiple visibility keywords (0)" ); + + assert.throws( function() + { + buildGetterSetterQuick( { + 'public': true, + 'private': true, + } ); + }, TypeError, "Cannot specify multiple visibility keywords (1)" ); + + assert.throws( function() + { + buildGetterSetterQuick( { + 'protected': true, + 'private': true, + } ); + }, TypeError, "Cannot specify multiple visibility keywords (2)" ); + +} )(); +