1
0
Fork 0

Merge branch 'master' into doc/master

Conflicts:
	Makefile
closure/master
Mike Gerwitz 2011-03-13 04:52:13 -04:00
commit 7cee1cf40e
24 changed files with 1163 additions and 61 deletions

View File

@ -5,6 +5,10 @@ PATH_TOOLS=${CWD}/tools
PATH_COMBINE_OUTPUT=${PATH_BUILD}/ease.js
PATH_COMBINE_OUTPUT_FULL=${PATH_BUILD}/ease-full.js
PATH_BROWSER_TEST=${PATH_TOOLS}/browser-test.html
PATH_TEST=./test
PATH_PERF_TEST=${PATH_TEST}/perf
PERF_TESTS := $(shell find "$(PATH_PERF_TEST)" -name 'perf-*.js')
PATH_DOC=${CWD}/doc
PATH_DOC_OUTPUT=${PATH_BUILD}/doc
@ -17,11 +21,14 @@ PATH_MANUAL_TEXI=${PATH_DOC}/manual.texi
COMBINE=${PATH_TOOLS}/combine
TESTS_JS := $(shell find "./test" -name 'test-*.js')
TESTS_SHELL := $(shell find "./test" -name 'test-[^\.]*')
TESTS := $(shell find "$(PATH_TEST)" \
-name 'test-*' \
-a ! -name 'test-combine.js'\
)
TEST_COMBINE := $(PATH_TEST)/test-combine.js
.PHONY: test doc
.PHONY: test test-combine doc
default: combine
@ -39,11 +46,17 @@ combine: mkbuild
cp "${PATH_BROWSER_TEST}" "${PATH_BUILD}"
# run tests
test: default $(TESTS_JS) $(TESTS_SHELL)
test: default $(TESTS) test-combine
test-combine: default $(TEST_COMBINE)
test-%.js: default
node $@
node $@
test-%: default
./$@
./$@
# performance tests
perf: default $(PERF_TESTS)
perf-%.js: default
@node $@
# generate texinfo documentation (twice to generate TOC), then remove the extra
# files that were generated

3
TODO
View File

@ -5,6 +5,9 @@
[ target: 0.1.0 ]
Misc
- Class module is becoming too large; refactor
- Disallow member redeclaration in definition
- Permit binding on class methods
- Provide ability to free class from memory (class data stored in internal vars)
Member Keywords
- Restrictions; throw exceptions when unknown keywords are used

View File

@ -457,6 +457,9 @@ var extend = ( function( extending )
}
}
// increment class identifier
class_id++;
util.propParse( props, {
each: function( name, value, keywords )
{
@ -498,7 +501,8 @@ var extend = ( function( extending )
method: function( name, func, is_abstract, keywords )
{
member_builder.buildMethod(
members, null, name, func, keywords, getMethodInstance
members, null, name, func, keywords, getMethodInstance,
class_id
);
if ( is_abstract )
@ -531,13 +535,13 @@ var extend = ( function( extending )
// set up the new class
var new_class = createCtor( cname, abstract_methods, members );
attachPropInit( prototype, prop_init, members );
attachPropInit( prototype, prop_init, members, class_id );
new_class.prototype = prototype;
new_class.constructor = new_class;
// important: call after setting prototype
setupProps( new_class, abstract_methods, ++class_id );
setupProps( new_class, abstract_methods, class_id );
// lock down the new class (if supported) to ensure that we can't add
// members at runtime
@ -761,24 +765,27 @@ function initInstance( iid, instance )
* ensuring that their data is not shared with other instances (this is not a
* problem with primitive data types).
*
* The __initProps() method will also initialize any parent properties
* (recursive) to ensure that subtypes do not have a referencing issue, and
* subtype properties take precedence over those of the parent.
* The method will also initialize any parent properties (recursive) to ensure
* that subtypes do not have a referencing issue, and subtype properties take
* precedence over those of the parent.
*
* @param {Object} prototype prototype to attach method to
* @param {Object} properties properties to initialize
* @param {number} cid class id
*
* @param {{public: Object, protected: Object, private: Object}} members
*
* @return {undefined}
*/
function attachPropInit( prototype, properties, members )
function attachPropInit( prototype, properties, members, cid )
{
util.defineSecureProp( prototype, '__initProps', function( inherit )
{
// defaults to false
// defaults to false, sid = super identifier
inherit = !!inherit;
var iid = this.__iid;
// first initialize the parent's properties, so that ours will overwrite
// them
var parent_init = prototype.parent.__initProps;
@ -790,21 +797,17 @@ function attachPropInit( prototype, properties, members )
parent_init.call( this, true );
}
// this will return our property proxy, if supported by our environment,
// otherwise just a normal object with everything merged in
var inst_props = propobj.createPropProxy(
this, class_instance[ this.__iid ], properties[ 'public' ]
this, class_instance[ iid ], properties[ 'public' ]
);
// use whatever was returned by the property proxy (which may not be a
// proxy, depending on JS engine support)
class_instance[ this.__iid ] = inst_props;
// if we're inheriting, perform a setup that doesn't include everything
// that we don't want (e.g. private properties)
var setup = ( inherit )
? propobj.setupInherited
: propobj.setup
;
setup( inst_props, properties, members );
class_instance[ iid ][ cid ] = propobj.setup(
inst_props, properties, members
);
});
}
@ -981,21 +984,28 @@ function getMeta( id )
/**
* Returns the instance object associated with the given method
*
* The instance object contains the protected and private members. This object
* can be passed as the context when calling a method in order to give that
* method access to those members.
* The instance object contains the protected members. This object can be passed
* as the context when calling a method in order to give that method access to
* those members.
*
* One level above the instance object on the prototype chain is the object
* containing the private members. This is swappable, depending on the class id
* associated with the provided method call. This allows methods that were not
* overridden by the subtype to continue to use the private members of the
* supertype.
*
* @param {function()} method method to look up instance object for
* @param {number} cid class id
*
* @return {Object,null} instance object if found, otherwise null
*/
function getMethodInstance( method )
function getMethodInstance( inst, cid )
{
var iid = method.__iid,
data = class_instance[ method.__iid ];
var iid = inst.__iid,
data = class_instance[ iid ];
return ( iid && data )
? data
? data[ cid ]
: null
;
}

View File

@ -62,11 +62,12 @@ exports.initMembers = function( mpublic, mprotected, mprivate )
* @param {Object=} instCallback function to call in order to retrieve
* object to bind 'this' keyword to
* @param {number} cid class id
*
* @return {undefined}
*/
exports.buildMethod = function(
members, meta, name, value, keywords, instCallback
members, meta, name, value, keywords, instCallback, cid
)
{
var prev;
@ -109,7 +110,7 @@ exports.buildMethod = function(
if ( prev )
{
// override the method
dest[ name ] = overrideMethod( prev, value, instCallback );
dest[ name ] = overrideMethod( prev, value, instCallback, cid );
}
else if ( keywords[ 'abstract' ] )
{
@ -120,7 +121,7 @@ exports.buildMethod = function(
{
// we are not overriding the method, so simply copy it over, wrapping it
// to ensure privileged calls will work properly
dest[ name ] = overrideMethod( value, null, instCallback );
dest[ name ] = overrideMethod( value, null, instCallback, cid );
}
};
@ -303,10 +304,11 @@ function scanMembers( members, name, cmp )
*
* @param {Object=} instCallback function to call in order to retrieve
* object to bind 'this' keyword to
* @param {number} cid class id
*
* @return {function()} override method
*/
function overrideMethod( super_method, new_method, instCallback )
function overrideMethod( super_method, new_method, instCallback, cid )
{
instCallback = instCallback || function() {};
@ -319,7 +321,7 @@ function overrideMethod( super_method, new_method, instCallback )
{
override = function()
{
var context = instCallback( this ) || this,
var context = instCallback( this, cid ) || this,
retval = undefined
;
@ -344,7 +346,7 @@ function overrideMethod( super_method, new_method, instCallback )
// we are defining a new method
override = function()
{
var context = instCallback( this ) || this,
var context = instCallback( this, cid ) || this,
retval = undefined
;

View File

@ -31,43 +31,37 @@ var util = require( './util' ),
/**
* Sets up properties when inheriting
* Sets up properties (non-inheriting)
*
* This does not include private members.
* This includes all members (including private). Private members will be set up
* in a separate object, so that they can be easily removed from the mix. That
* object will include the destination object in the prototype, so that the
* access should be transparent. This object is returned.
*
* @param {Object} dest destination object
* @param {Object} properties properties to copy
* @param {Object=} methods methods to copy
*
* @return {undefined}
* @return {Object} object containing private members and dest as prototype
*/
exports.setupInherited = function( dest, properties, methods )
exports.setup = function( dest, properties, methods )
{
// this constructor is an extra layer atop of the destination object, which
// will contain the private methods
var obj_ctor = function() {};
obj_ctor.prototype = dest;
var obj = new obj_ctor();
// initialize each of the properties for this instance to
// ensure we're not sharing references to prototype values
doSetup( dest, properties[ 'public' ] );
doSetup( dest, properties[ 'protected' ], methods[ 'protected'] );
};
/**
* Sets up properties (non-inheriting)
*
* This includes all members (including private).
*
* @param {Object} dest destination object
* @param {Object} properties properties to copy
* @param {Object=} methods methods to copy
*
* @return {undefined}
*/
exports.setup = function( dest, properties, methods )
{
// first, set up the public and protected members
exports.setupInherited( dest, properties, methods );
// then add the private parts
doSetup( dest, properties[ 'private' ], methods[ 'private' ] );
doSetup( obj, properties[ 'private' ], methods[ 'private' ] );
return obj;
};

8
test/perf/README 100644
View File

@ -0,0 +1,8 @@
This directory contains the performance tests. These tests contain basic
routines that perform a single action and output the result in seconds, with a
basic description of what has been done. The timing is done via the native Date
object to ensure that it can be run both server and client-side.
It is important that each test performs only a single operation to ensure that
the prior operations have no consequences on the previous, at least when run
server-side by invoking a separate executable for each.

View File

@ -0,0 +1,99 @@
/**
* Common performance testing functionality
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
/**
* Stores start time
* @type {number}
*/
var start = 0;
/**
* Includes a module from the lib directory
*
* @param {string} name module name
*
* @return {Object} module exports
*/
exports.require = function( name )
{
return require( '../../lib/' + name );
};
/**
* A simple wrapper to perform testing and output the result
*
* The count is not used to call the function multiple times, because that would
* greatly impact the test results. Instead, you should pass the number of times
* the test was performed in a loop.
*
* @param {function()} test performance test to perform
* @param {number} count number of times the test was performed
* @param {string=} desc test description
*
* @return {undefined}
*/
exports.test = function( test, count, desc )
{
exports.start();
test();
exports.report( count, desc );
};
/**
* Starts the timer
*
* @return {undefined}
*/
exports.start = function()
{
start = ( new Date() ).getTime();
};
/**
* Outputs the time elapsed, followed by the description (if available)
*
* @param {number} count number of times the test was performed
* @param {string=} desc test description
*
* @return {undefined}
*/
exports.report = function( count, desc )
{
count = +count;
desc = desc || '';
var end = ( new Date() ).getTime(),
total = ( ( end - start ) / 1000 ).toFixed( 3 ),
pers = ( total / count ).toFixed( 10 )
;
console.log( total + "s (x" + count + " = " + pers + "s each)" +
( ( desc ) ? ( ': ' + desc ) : '' )
);
};

View File

@ -0,0 +1,47 @@
/**
* Tests amount of time taken to declare 1000 classes with a few members,
* private keyword
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( {
'private a': function() {},
'private b': function() {},
'private c': function() {},
} );
}
}, count, 'Declare ' + count + ' anonymous classes with private members' );

View File

@ -0,0 +1,47 @@
/**
* Tests amount of time taken to declare 1000 classes with a few members,
* protected keyword
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( {
'protected a': function() {},
'protected b': function() {},
'protected c': function() {},
} );
}
}, count, 'Declare ' + count + ' anonymous classes with protected members' );

View File

@ -0,0 +1,47 @@
/**
* Tests amount of time taken to declare 1000 classes with a few members, public
* keyword
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( {
'public a': function() {},
'public b': function() {},
'public c': function() {},
} );
}
}, count, 'Declare ' + count + ' anonymous classes with public members' );

View File

@ -0,0 +1,47 @@
/**
* Tests amount of time taken to declare 1000 classes with a few members, no
* keywords
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( {
a: function() {},
b: function() {},
c: function() {},
} );
}
}, count, 'Declare ' + count + ' anonymous classes with few methods' );

View File

@ -0,0 +1,42 @@
/**
* Tests amount of time taken to declare 1000 classes
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( 'Foo', {} );
}
}, count, 'Declare ' + count + ' empty named classes' );

View File

@ -0,0 +1,47 @@
/**
* Tests amount of time taken to declare 1000 classes with a few properties,
* private keyword
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( {
'private a': 'foo',
'private b': 10,
'private c': false,
} );
}
}, count, 'Declare ' + count + ' anonymous classes with private properties' );

View File

@ -0,0 +1,47 @@
/**
* Tests amount of time taken to declare 1000 classes with a few properties,
* protected keyword
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( {
'protected a': 'foo',
'protected b': 10,
'protected c': false,
} );
}
}, count, 'Declare ' + count + ' anonymous classes with protected properties' );

View File

@ -0,0 +1,47 @@
/**
* Tests amount of time taken to declare 1000 classes with a few properties,
* public keyword
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( {
'public a': 'foo',
'public b': 10,
'public c': false,
} );
}
}, count, 'Declare ' + count + ' anonymous classes with public properties' );

View File

@ -0,0 +1,47 @@
/**
* Tests amount of time taken to declare 1000 classes with few properties, no
* keywords
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( {
a: 'foo',
b: 10,
c: false,
} );
}
}, count, 'Declare ' + count + ' anonymous classes with few properties' );

View File

@ -0,0 +1,42 @@
/**
* Tests amount of time taken to declare 1000 classes
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 1000
;
common.test( function()
{
var i = count;
while ( i-- )
{
Class( {} );
}
}, count, 'Declare ' + count + ' empty anonymous classes' );

View File

@ -0,0 +1,101 @@
/**
* Tests amount of time taken to declare read properties internally and
* externally
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' ),
// we need many tests for a measurable result
count = 500000
// instance of anonymous class
foo = Class( {
'public pub_bar': 'foo',
'protected prot_bar': 'bar',
'private priv_bar': 'baz',
'public testInternal': function()
{
var _self = this;
common.test( function()
{
var i = count,
val = null
;
while ( i-- )
{
val = _self.pub_bar;
}
}, count, 'Read public properties internally' );
common.test( function()
{
var i = count,
val = null
;
while ( i-- )
{
val = _self.prot_bar;
}
}, count, 'Read protected properties internally' );
common.test( function()
{
var i = count,
val = null
;
while ( i-- )
{
val = _self.priv_bar;
}
}, count, 'Read private properties internally' );
},
} )()
;
common.test( function()
{
var i = count,
val = null
;
while ( i-- )
{
val = foo.pub_bar;
}
}, count, 'Read public properties externally' );
// run the same test internally
foo.testInternal();

View File

@ -0,0 +1,43 @@
/**
* Tests amount of time taken to instantiate anonymous classes
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 5000,
Foo = Class( {} )
;
common.test( function()
{
var i = count;
while ( i-- )
{
Foo();
}
}, count, 'Instantiate ' + count + ' empty anonymous classes' );

View File

@ -0,0 +1,44 @@
/**
* Tests amount of time taken to instantiate named classes
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' )
count = 5000,
Foo = Class( 'Foo', {} )
;
common.test( function()
{
var i = count;
while ( i-- )
{
// to be extra confident that V8 or another compiler won't realize this
// is useless and optimize it out
Foo();
}
}, count, 'Instantiate ' + count + ' empty named classes' );

View File

@ -0,0 +1,111 @@
/**
* Tests amount of time taken to invoke Class methods
*
* The expected results are as follows:
* - Method invocations are expected to be slower than invoking a method on a
* conventional constructor instance. This is because of the method wrapper
* used by ease.js.
* - Public methods externally should be invoked very quickly. They are part
* of the class's prototype and therefore easily accessible.
* - Public methods /internally/ are likely to be invoked slightly more
* slowly. This is because it takes one extra step down the prototype chain
* to access them. The difference should be minute.
* - Protected and private methods internally should be accessed fairly
* quickly since, like public methods externally, they are first on the
* prototype chain.
* - Protected members will be accessed more slowly than private members,
* because they are one step lower on the prototype chain. Future versions
* will remove this performance hit if the Class contains no private
* members.
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' ),
count = 500000,
// used to ensure v8 doesn't optimize functions away
i = 0,
// instance of anonymous class
foo = Class( {
'public pub': function() { i++; },
'protected prot': function() { i++; },
'private priv': function() { i++; },
'public testInternal': function()
{
var _self = this;
common.test( function()
{
var i = count;
while ( i-- )
{
_self.pub();
}
}, count, 'Invoke public methods internally' );
common.test( function()
{
var i = count;
while ( i-- )
{
_self.prot();
}
}, count, 'Invoke protected methods internally' );
common.test( function()
{
var i = count;
while ( i-- )
{
_self.priv();
}
}, count, 'Invoke private methods internally' );
},
} )()
;
common.test( function()
{
var i = count;
while ( i-- )
{
foo.pub();
}
}, count, 'Invoke public methods externally' );
// run the same test internally
foo.testInternal();

View File

@ -0,0 +1,33 @@
/**
* Tests amount of time spent on requiring class module
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' );
// we run this test once because require() will cache the object in memory
common.test( function()
{
common.require( 'class' );
}, 1, 'Require class module' );

View File

@ -0,0 +1,101 @@
/**
* Tests amount of time taken to declare read properties internally and
* externally
*
* 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 <http://www.gnu.org/licenses/>.
*
* @author Mike Gerwitz
* @package performance
*/
var common = require( __dirname + '/common.js' ),
Class = common.require( 'class' ),
// we need many tests for a measurable result
count = 500000
// instance of anonymous class
foo = Class( {
'public pub_bar': 'foo',
'protected prot_bar': 'bar',
'private priv_bar': 'baz',
'public testInternal': function()
{
var _self = this;
common.test( function()
{
var i = count,
val = null
;
while ( i-- )
{
_self.pub_bar = 'foo';
}
}, count, 'Write public properties internally' );
common.test( function()
{
var i = count,
val = null
;
while ( i-- )
{
_self.prot_bar = 'foo';
}
}, count, 'Write protected properties internally' );
common.test( function()
{
var i = count,
val = null
;
while ( i-- )
{
_self.priv_bar = 'foo';
}
}, count, 'Write private properties internally' );
},
} )()
;
common.test( function()
{
var i = count,
val = null
;
while ( i-- )
{
foo.pub_bar = 'foo';
}
}, count, 'Write public properties externally' );
// run the same test internally
foo.testInternal();

View File

@ -73,6 +73,24 @@ var common = require( './common' ),
{
// override me
},
'public getPrivProp': function()
{
return this.parts;
},
'public invokePriv': function()
{
return this._priv();
},
'private _priv': function()
{
return priv;
},
}),
// instance of Foo
@ -80,13 +98,28 @@ var common = require( './common' ),
// subtype
SubFoo = Foo.extend({
'private _pfoo': 'baz',
'public getSelfOverride': function()
{
// return this from overridden method
return this;
},
/**
* We have to override this so that 'this' is not bound to the supertype
*/
'public getProp': function( name )
{
// return property, allowing us to break encapsulation for
// protected/private properties (for testing purposes)
return this[ name ];
},
}),
sub_foo = SubFoo()
sub_foo = SubFoo(),
sub_sub_foo = SubFoo.extend( {} )()
;
@ -362,3 +395,50 @@ var common = require( './common' ),
);
} )();
/**
* This one's a particularly nasty bug that snuck up on me. Private members
* should not be accessible to subtypes; that's a given. However, they need to
* be accessible to the parent methods. For example, let's say class Foo
* contains public method bar(), which invokes private method _baz(). This is
* perfectly legal. Then SubFoo extends Foo, but does not override method bar().
* Invoking method bar() should still be able to invoke private method _baz(),
* because, from the perspective of the parent class, that operation is
* perfectly legal.
*
* The resolution of this bug required a slight system redesign. The short-term
* fix was to declare any needed private members are protected, so that they
* were accessible by the subtype.
*/
( function testParentMethodsCanAccessPrivateMembersOfParent()
{
// properties
assert.equal(
sub_foo.getPrivProp(),
priv,
"Parent methods should have access to the private properties of the " +
"parent"
);
// methods
assert.equal(
sub_foo.invokePriv(),
priv,
"Parent methods should have access to the private methods of the parent"
);
// should apply to super-supertypes too
assert.equal(
sub_sub_foo.getPrivProp(),
priv,
"Parent methods should have access to the private properties of the " +
"parent (2)"
);
assert.equal(
sub_sub_foo.invokePriv(),
priv,
"Parent methods should have access to the private methods of the " +
"parent (2)"
);
} )();