From e93a4db3e4a0fe3c28ca6290e4265af14504f5a9 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Mon, 4 Apr 2011 23:07:01 -0400 Subject: [PATCH] Began implementing public static members --- lib/class_builder.js | 40 +++++++++++--- test/test-class_builder-static.js | 89 +++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 test/test-class_builder-static.js diff --git a/lib/class_builder.js b/lib/class_builder.js index 5bb5dfa..5896172 100644 --- a/lib/class_builder.js +++ b/lib/class_builder.js @@ -158,8 +158,9 @@ exports.build = function extend() prototype = new base(), cname = '', - prop_init = member_builder.initMembers(), - members = member_builder.initMembers( prototype ), + prop_init = member_builder.initMembers(), + members = member_builder.initMembers( prototype ), + static_members = member_builder.initMembers(), abstract_methods = util.clone( exports.getMeta( base ).abstractMethods ) @@ -192,7 +193,8 @@ exports.build = function extend() base, prop_init, abstract_methods, - members + members, + static_members ); // reference to the parent prototype (for more experienced users) @@ -201,6 +203,7 @@ exports.build = function extend() // set up the new class var new_class = createCtor( cname, abstract_methods, members ); + attachStatic( new_class, static_members ); attachPropInit( prototype, prop_init, members, class_id ); new_class.prototype = prototype; @@ -371,7 +374,8 @@ function createAbstractCtor( cname ) function buildMembers( - props, class_id, base, prop_init, abstract_methods, members + props, class_id, base, prop_init, abstract_methods, members, + static_members ) { var hasOwn = Array.prototype.hasOwnProperty, @@ -405,10 +409,12 @@ function buildMembers( property: function( name, value, keywords ) { + var dest = ( keywords[ 'static' ] ) ? static_members : prop_init; + // build a new property, passing in the other members to compare // against for preventing nonsensical overrides member_builder.buildProp( - prop_init, null, name, value, keywords, base + dest, null, name, value, keywords, base ); }, @@ -428,6 +434,8 @@ function buildMembers( method: function( name, func, is_abstract, keywords ) { + var dest = ( keywords[ 'static' ] ) ? static_members : members; + // constructor check if ( public_methods[ name ] === true ) { @@ -440,7 +448,7 @@ function buildMembers( } member_builder.buildMethod( - members, null, name, func, keywords, getMethodInstance, + dest, null, name, func, keywords, getMethodInstance, class_id, base ); @@ -529,6 +537,26 @@ function attachPropInit( prototype, properties, members, cid ) } +/** + * Attaches static members to a constructor (class) + * + * @param {function()} ctor class + * @param {Object} members static members + * + * @return {undefined} + */ +function attachStatic( ctor, members ) +{ + var pub = members[ 'public' ]; + + // copy over public static members + for ( name in pub ) + { + ctor[ name ] = pub[ name ]; + } +} + + /** * Initializes class metadata for the given class * diff --git a/test/test-class_builder-static.js b/test/test-class_builder-static.js new file mode 100644 index 0000000..48a8c64 --- /dev/null +++ b/test/test-class_builder-static.js @@ -0,0 +1,89 @@ +/** + * Tests static members (this includes constants) + * + * 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' ), + builder = common.require( 'class_builder' ), + fallback = common.require( 'util' ).definePropertyFallback() +; + +/** + * Static members, by their nature, should be accessible through the class + * definition itself; that is, without instantiation. It should also not be + * available through the generated prototype (and therefore, be unavailable to + * instances). + */ +( function testPublicStaticMembersAreAccessibleViaClassDefinitionOnly() +{ + var val = 'foo', + val2 = 'bar', + Foo = builder.build( + { + 'public static foo': val, + + // should be public by default + 'static bar': val2, + + // the same rules should apply to methods + 'public static baz': function() + { + return val; + }, + + 'static foobar': function() + { + return val2; + }, + } ); + + // properties should be accessible via class definition + assert.equal( Foo.foo, val, + "Public static properties should be accessible via class definition" + ); + + // as long as the above test succeeded, we can then conclude that static + // members are public by default if the following succeeds + assert.equal( Foo.bar, val2, + "Static properties are public by default" + ); + + // methods should be accessible via class definition + assert.equal( Foo.baz(), val, + "Public static methods should be accessible via class definition" + ); + + // same rules as above, but with a method + assert.equal( Foo.foobar(), val2, + "Static methods are public by default" + ); + + // neither should be a part of the prototype + assert.equal( Foo.prototype.foo, undefined, + "Public static properties are *not* part of the prototype" + ); + assert.equal( Foo.prototype.baz, undefined, + "Public static methods are *not* part of the prototype" + ); +} )(); +