mirror of
				https://github.com/flynx/object.js.git
				synced 2025-10-31 03:20:09 +00:00 
			
		
		
		
	reworked access to parent callable implementations...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									1b5d27afc1
								
							
						
					
					
						commit
						a5bab42336
					
				
							
								
								
									
										66
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								README.md
									
									
									
									
									
								
							| @ -213,9 +213,16 @@ var Base = object.Constructor('Base', { | |||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| var Item = object.Constructor('Item', Base, { | var Item = object.Constructor('Item', Base, { | ||||||
|  | 	method: function(){ | ||||||
|  | 		// ...  | ||||||
|  | 
 | ||||||
|  | 		// call the "super" method... | ||||||
|  | 		return object.parentCall(Item.prototype, 'method', this, ...arguments) | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
| 	__init__: function(){ | 	__init__: function(){ | ||||||
| 		// call the "super" method... | 		// call the "super" method... | ||||||
| 		object.parentCall(this.prototype.__init__, this) | 		object.parentCall(this.__init__, this, ...arguments) | ||||||
| 
 | 
 | ||||||
| 		this.item_attr = 'instance attribute value' | 		this.item_attr = 'instance attribute value' | ||||||
| 	}, | 	}, | ||||||
| @ -245,7 +252,8 @@ var Action = object.Constructor('Action', | |||||||
| 
 | 
 | ||||||
| var Action2 = object.Constructor('Action2', { | var Action2 = object.Constructor('Action2', { | ||||||
| 	__call__: function(context, ...args){ | 	__call__: function(context, ...args){ | ||||||
| 		return this | 		// call the callable parent... | ||||||
|  | 		return object.parentCall(Action2.prototype, '__call__', this, ...arguments) | ||||||
| 	}, | 	}, | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| @ -270,6 +278,17 @@ represent the two contexts relevant to the callable instance: | |||||||
| If the prototype is explicitly defined as a function then it is the  | If the prototype is explicitly defined as a function then it is the  | ||||||
| user's responsibility to call `.__call__(..)` method. | user's responsibility to call `.__call__(..)` method. | ||||||
| 
 | 
 | ||||||
|  | When calling the parent passing `'__call__'` will get the parent in both  | ||||||
|  | the function and `.__call__(..)` implementations, but extra care must be  | ||||||
|  | taken in passing the reference prototype to `.parentCall(..)`, the instance | ||||||
|  | is implemented as a proxy function that will pass the arguments to the  | ||||||
|  | implementation (i.e. `this.constructor.prototype(..)`) so this proxy  | ||||||
|  | function as well as the `.constructor.prototype(..)` are valid implementations | ||||||
|  | and both will be retrieved by `sources(this, '__call__')`,  | ||||||
|  | `values(this, '__call__')` and by extension `parent(this, '__call__')`  | ||||||
|  | and friends, so this is another reason not to use `this` in the general  | ||||||
|  | case. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| **Notes:** | **Notes:** | ||||||
| - the two approaches (_function_ vs. `.__call__(..)`) will produce  | - the two approaches (_function_ vs. `.__call__(..)`) will produce  | ||||||
| @ -497,6 +516,18 @@ one of the following: | |||||||
|   `callback(..)` and continue. |   `callback(..)` and continue. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | Special case: get callable implementations | ||||||
|  | ``` | ||||||
|  | sources(<object>, '__call__') | ||||||
|  | sources(<object>, '__call__', <callback>) | ||||||
|  | 	-> <list> | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | This will get the callable implementations regardless of the actual | ||||||
|  | implementation details, i.e. both function prototype or `.__call__(..)`  | ||||||
|  | methods will be matched. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ### `values(..)` | ### `values(..)` | ||||||
| 
 | 
 | ||||||
| Get values for attribute in prototype chain | Get values for attribute in prototype chain | ||||||
| @ -528,7 +559,7 @@ callback(<descriptor>, <source>) | |||||||
| 	-> <value> | 	-> <value> | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| See [`sources(..)`](#sources) for docs on `callback(..)` | See [`sources(..)`](#sources) for docs on `callback(..)` and special cases. | ||||||
| 
 | 
 | ||||||
| ### `parent(..)` | ### `parent(..)` | ||||||
| 
 | 
 | ||||||
| @ -537,18 +568,37 @@ Get parent attribute value or method | |||||||
| parent(<prototype>, <name>) | parent(<prototype>, <name>) | ||||||
| 	-> <parent-value> | 	-> <parent-value> | ||||||
| 	-> undefined | 	-> undefined | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
|  | It is recommended to use the relative`<constructor>.prototype` as  | ||||||
|  | `<prototype>` and in turn not recommended to use `this` or `this.__proto__`  | ||||||
|  | as they will not provide the appropriate reference point in the prototype  | ||||||
|  | chain for the current method and may result in infinite recursion. | ||||||
|  | 
 | ||||||
|  | For access to parent methods the following special case is better. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
| parent(<method>, <this>) | parent(<method>, <this>) | ||||||
| 	-> <parent-method> | 	-> <parent-method> | ||||||
| 	-> undefined | 	-> undefined | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| _Edge case: The `parent(<method>, ..)` has one potential pitfall -- in  | _Edge case: The `parent(<method>, ..)` has one potential pitfall -- in  | ||||||
| the rare case where a prototype chain contains two or more references  | the rare case where a prototype chain contains two or more references  | ||||||
| to the same method under the same name, `parent(..)` can't distinguish  | to the same method under the same name, `parent(..)` can't distinguish  | ||||||
| between these references and will always return the second one._ | between these references and will always return the second one._ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | Special case: get the parent callable implementation | ||||||
|  | ``` | ||||||
|  | parent(<prototype>, '__call__') | ||||||
|  | 	-> <parent-value> | ||||||
|  | 	-> undefined | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | See [`sources(..)`](#sources) for more info on the special case. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| ### `parentProperty(..)` | ### `parentProperty(..)` | ||||||
| 
 | 
 | ||||||
| @ -573,6 +623,15 @@ parentCall(<method>, <this>) | |||||||
| 	-> undefined | 	-> undefined | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | Special case: call the parent callable implementation | ||||||
|  | ``` | ||||||
|  | parentCall(<prototype>, '__call__', <this>) | ||||||
|  | 	-> <result> | ||||||
|  | 	-> undefined | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | See [`parent(..)`](#parent) and [`sources(..)`](#sources) for more details. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| ### `mixin(..)` | ### `mixin(..)` | ||||||
| 
 | 
 | ||||||
| @ -814,4 +873,5 @@ Still, this is worth some thought. | |||||||
| Copyright (c) 2019, Alex A. Naanou,   | Copyright (c) 2019, Alex A. Naanou,   | ||||||
| All rights reserved. | All rights reserved. | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| <!-- vim:set ts=4 sw=4 spell : --> | <!-- vim:set ts=4 sw=4 spell : --> | ||||||
|  | |||||||
							
								
								
									
										93
									
								
								object.js
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								object.js
									
									
									
									
									
								
							| @ -181,13 +181,18 @@ module.STOP = | |||||||
| // 		for any overloading in the instance, though this approach is 
 | // 		for any overloading in the instance, though this approach is 
 | ||||||
| // 		not very reusable....
 | // 		not very reusable....
 | ||||||
| // NOTE: this will not trigger any props...
 | // NOTE: this will not trigger any props...
 | ||||||
|  | //
 | ||||||
|  | // XXX document the '__call__' cpecial case...
 | ||||||
|  | // XXX in the call case need to skip the wrapper function... (???)
 | ||||||
| var sources = | var sources = | ||||||
| module.sources = | module.sources = | ||||||
| function(obj, name, callback){ | function(obj, name, callback){ | ||||||
| 	var o | 	var o | ||||||
| 	var res = [] | 	var res = [] | ||||||
| 	while(obj != null){ | 	while(obj != null){ | ||||||
| 		if(obj.hasOwnProperty(name)){ | 		//if(obj.hasOwnProperty(name)){
 | ||||||
|  | 		if(obj.hasOwnProperty(name)  | ||||||
|  | 				|| (name == '__call__' && typeof(obj) == 'function')){ | ||||||
| 			// handle callback...
 | 			// handle callback...
 | ||||||
| 			o = callback | 			o = callback | ||||||
| 				&& callback(obj) | 				&& callback(obj) | ||||||
| @ -223,27 +228,33 @@ function(obj, name, callback){ | |||||||
| // 		
 | // 		
 | ||||||
| //
 | //
 | ||||||
| // NOTE: for more docs on the callback(..) see sources(..)
 | // NOTE: for more docs on the callback(..) see sources(..)
 | ||||||
|  | //
 | ||||||
|  | // XXX document the '__call__' cpecial case...
 | ||||||
| var values = | var values = | ||||||
| module.values = | module.values = | ||||||
| function(obj, name, callback, props){ | function(obj, name, callback, props){ | ||||||
| 	props = callback === true ?  | 	props = callback === true ?  | ||||||
| 		callback  | 		callback  | ||||||
| 		: props | 		: props | ||||||
|  | 	var _get = function(obj, name){ | ||||||
|  | 		return props ? | ||||||
|  | 				Object.getOwnPropertyDescriptor(obj, name) | ||||||
|  | 			// handle callable instance...
 | ||||||
|  | 			: !(name in obj)  | ||||||
|  | 					&& name == '__call__'  | ||||||
|  | 					&& typeof(obj) == 'function' ? | ||||||
|  | 				obj | ||||||
|  | 			// normal attr...
 | ||||||
|  | 			: obj[name] } | ||||||
| 	// wrap the callback if given...
 | 	// wrap the callback if given...
 | ||||||
| 	var c = typeof(callback) == 'function' | 	var c = typeof(callback) == 'function' | ||||||
| 		&& function(obj){  | 		&& function(obj){  | ||||||
| 			return callback( | 			return callback(_get(obj, name), obj) } | ||||||
| 				props ? |  | ||||||
| 					Object.getOwnPropertyDescriptor(obj, name) |  | ||||||
| 					: [ obj[name] ], |  | ||||||
| 				obj) } |  | ||||||
| 	return sources(...(c ? | 	return sources(...(c ? | ||||||
| 			[obj, name, c] | 			[obj, name, c] | ||||||
| 			: [obj, name])) | 			: [obj, name])) | ||||||
| 		.map(function(obj){  | 		.map(function(obj){  | ||||||
| 			return props ? | 			return _get(obj, name) }) } | ||||||
| 				Object.getOwnPropertyDescriptor(obj, name) |  | ||||||
| 				: obj[name] }) } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // Find the next parent attribute in the prototype chain.
 | // Find the next parent attribute in the prototype chain.
 | ||||||
| @ -258,6 +269,10 @@ function(obj, name, callback, props){ | |||||||
| // 		-> meth
 | // 		-> meth
 | ||||||
| // 		-> undefined
 | // 		-> undefined
 | ||||||
| //
 | //
 | ||||||
|  | // 	Get parent object...
 | ||||||
|  | // 	parent(this)
 | ||||||
|  | // 		-> parent
 | ||||||
|  | //
 | ||||||
| // 
 | // 
 | ||||||
| // The two forms differ in:
 | // The two forms differ in:
 | ||||||
| // 	- in parent(method, ..) a method's .name attr is used for name.
 | // 	- in parent(method, ..) a method's .name attr is used for name.
 | ||||||
| @ -300,9 +315,20 @@ function(obj, name, callback, props){ | |||||||
| // 		and to the method after the match.
 | // 		and to the method after the match.
 | ||||||
| // NOTE: this is super(..) replacement, usable in any context without 
 | // NOTE: this is super(..) replacement, usable in any context without 
 | ||||||
| // 		restriction -- super(..) is restricted to class methods only...
 | // 		restriction -- super(..) is restricted to class methods only...
 | ||||||
|  | //
 | ||||||
|  | // XXX need to be able to get a callable prototype...
 | ||||||
|  | // 			parent(proto, '__call__')
 | ||||||
|  | // 		This would need to handle two cases transparently:
 | ||||||
|  | // 			- parent with .__call__(..) defined...
 | ||||||
|  | // 			- parent with callable prototype...
 | ||||||
|  | // 		...should this be handled here or in sources(..)???
 | ||||||
|  | // XXX document both __call__ cases...
 | ||||||
| var parent = | var parent = | ||||||
| module.parent = | module.parent = | ||||||
| function(proto, name){ | function(proto, name){ | ||||||
|  | 	// special case: get parent...
 | ||||||
|  | 	if(arguments.length == 1){ | ||||||
|  | 		return proto.__proto__ } | ||||||
| 	// special case: get method...
 | 	// special case: get method...
 | ||||||
| 	if(typeof(name) != typeof('str')){ | 	if(typeof(name) != typeof('str')){ | ||||||
| 		var that = name | 		var that = name | ||||||
| @ -317,13 +343,17 @@ function(proto, name){ | |||||||
| 						&& module.STOP }) | 						&& module.STOP }) | ||||||
| 			.pop() } | 			.pop() } | ||||||
| 	// get first source...
 | 	// get first source...
 | ||||||
|  | 	var c = 0 | ||||||
| 	var res = sources(proto, name,  | 	var res = sources(proto, name,  | ||||||
| 			function(obj){ return module.STOP }) | 			function(obj){  | ||||||
|  | 				return c++ == 1  | ||||||
|  | 					&& module.STOP }) | ||||||
| 		.pop()  | 		.pop()  | ||||||
| 	return res ? | 	return !res ? | ||||||
| 		// get next value...
 | 			undefined | ||||||
| 		res.__proto__[name] | 		:(!(name in res) && typeof(res) == 'function') ? | ||||||
| 		: undefined } | 			res | ||||||
|  | 		: res[name] } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // Find the next parent property descriptor in the prototype chain...
 | // Find the next parent property descriptor in the prototype chain...
 | ||||||
| @ -368,6 +398,8 @@ function(proto, name){ | |||||||
| // 		or:
 | // 		or:
 | ||||||
| // 			parent(method, this).call(this, ...)
 | // 			parent(method, this).call(this, ...)
 | ||||||
| // NOTE: for more docs see parent(..)
 | // NOTE: for more docs see parent(..)
 | ||||||
|  | //
 | ||||||
|  | // XXX in the call case need to skip the wrapper function... (???)
 | ||||||
| var parentCall = | var parentCall = | ||||||
| module.parentCall = | module.parentCall = | ||||||
| function(proto, name, that, ...args){ | function(proto, name, that, ...args){ | ||||||
| @ -575,7 +607,7 @@ function(context, constructor, ...args){ | |||||||
| 	var _mirror_doc = function(func, target){ | 	var _mirror_doc = function(func, target){ | ||||||
| 		Object.defineProperty(func, 'toString', { | 		Object.defineProperty(func, 'toString', { | ||||||
| 			value: function(...args){ | 			value: function(...args){ | ||||||
| 				var f = typeof(constructor.prototype) == 'function' ?  | 				var f = typeof(target.prototype) == 'function' ?  | ||||||
| 					target.prototype | 					target.prototype | ||||||
| 					: target.prototype.__call__ | 					: target.prototype.__call__ | ||||||
| 				return typeof(f) == 'function' ? | 				return typeof(f) == 'function' ? | ||||||
| @ -603,8 +635,13 @@ function(context, constructor, ...args){ | |||||||
| 					return ( | 					return ( | ||||||
| 						// .prototype is a function...
 | 						// .prototype is a function...
 | ||||||
| 						typeof(constructor.prototype) == 'function' ? | 						typeof(constructor.prototype) == 'function' ? | ||||||
| 							constructor.prototype | 							// NOTE: we are not using .call(..) here as it
 | ||||||
| 								.call(obj, this, ...arguments) | 							// 		may not be accesible through the prototype
 | ||||||
|  | 							// 		chain, this can occur when creating a 
 | ||||||
|  | 							// 		callable instance from a non-callable 
 | ||||||
|  | 							// 		parent...
 | ||||||
|  | 							Reflect.apply( | ||||||
|  | 								constructor.prototype, obj, [this, ...arguments]) | ||||||
| 						// .__call__(..)
 | 						// .__call__(..)
 | ||||||
| 						: constructor.prototype.__call__ | 						: constructor.prototype.__call__ | ||||||
| 							.call(obj, this, ...arguments)) }, | 							.call(obj, this, ...arguments)) }, | ||||||
| @ -779,9 +816,21 @@ function Constructor(name, a, b, c){ | |||||||
| 
 | 
 | ||||||
| 	// handle: 
 | 	// handle: 
 | ||||||
| 	// 	Constructor(name, constructor, ..)
 | 	// 	Constructor(name, constructor, ..)
 | ||||||
|  | 	//
 | ||||||
|  | 	// NOTE: this is a bit too functional in style by an if-tree would 
 | ||||||
|  | 	// 		be more bulky and less readable...
 | ||||||
| 	constructor_proto | 	constructor_proto | ||||||
| 		&& proto.__proto__ === Object.prototype | 		// XXX need a better test -- need to test if .__proto__ was set 
 | ||||||
|  | 		// 		manually and not mess it up...
 | ||||||
|  | 		&& (proto.__proto__ === Object.prototype | ||||||
|  | 				|| proto.__proto__ === Function.prototype) | ||||||
| 			&& (proto.__proto__ = constructor_proto.prototype) | 			&& (proto.__proto__ = constructor_proto.prototype) | ||||||
|  | 			// restore func .toString(..) that was replaced to object's .toString(..) 
 | ||||||
|  | 			// in the previous op but only if it was not set by user...
 | ||||||
|  | 			&& (typeof(proto) == 'function' | ||||||
|  | 					&& proto.toString === Object.prototype.toString) | ||||||
|  | 				// XXX should we wrap this in normalizeIndent(..) ???
 | ||||||
|  | 				&& (proto.toString = Function.prototype.toString) | ||||||
| 
 | 
 | ||||||
| 	// handle: .__extends__
 | 	// handle: .__extends__
 | ||||||
| 	if(!constructor_proto){ | 	if(!constructor_proto){ | ||||||
| @ -802,9 +851,7 @@ function Constructor(name, a, b, c){ | |||||||
| 			constructor_mixin = mixinFlat({}, constructor_mixin) | 			constructor_mixin = mixinFlat({}, constructor_mixin) | ||||||
| 			delete constructor_mixin.__extends__ } | 			delete constructor_mixin.__extends__ } | ||||||
| 		!!constructor_proto | 		!!constructor_proto | ||||||
| 			&& (proto.__proto__ = constructor_proto.prototype) | 			&& (proto.__proto__ = constructor_proto.prototype) } | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| 	// the constructor base...
 | 	// the constructor base...
 | ||||||
| 	var _constructor = function Constructor(){ | 	var _constructor = function Constructor(){ | ||||||
| @ -829,8 +876,8 @@ function Constructor(name, a, b, c){ | |||||||
| 	// set .toString(..)...
 | 	// set .toString(..)...
 | ||||||
| 	// NOTE: do this only if .toString(..) is not defined by user...
 | 	// NOTE: do this only if .toString(..) is not defined by user...
 | ||||||
| 	// XXX revise this test...
 | 	// XXX revise this test...
 | ||||||
| 	;((constructor_mixin || {}).toString === Function.toString | 	;((constructor_mixin || {}).toString === Function.prototype.toString | ||||||
| 			|| (constructor_mixin || {}).toString === ({}).toString) | 			|| (constructor_mixin || {}).toString === Object.prototype.toString) | ||||||
| 		&& Object.defineProperty(_constructor, 'toString', { | 		&& Object.defineProperty(_constructor, 'toString', { | ||||||
| 			value: function(){  | 			value: function(){  | ||||||
| 				var args = proto.__init__ ? | 				var args = proto.__init__ ? | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "ig-object", |   "name": "ig-object", | ||||||
|   "version": "5.0.0", |   "version": "5.0.1", | ||||||
|   "description": "", |   "description": "", | ||||||
|   "main": "object.js", |   "main": "object.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|  | |||||||
							
								
								
									
										144
									
								
								test.js
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								test.js
									
									
									
									
									
								
							| @ -12,6 +12,12 @@ var object = require('./object') | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | //---------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  | module.VERBOSE = false | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| //---------------------------------------------------------------------
 | //---------------------------------------------------------------------
 | ||||||
| // helpers...
 | // helpers...
 | ||||||
| 
 | 
 | ||||||
| @ -27,59 +33,125 @@ var instances = function(obj){ | |||||||
| 			return k[0] == k[0].toLowerCase() && o.constructor }) } | 			return k[0] == k[0].toLowerCase() && o.constructor }) } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | var assert = function(pre, stats){ | ||||||
|  | 	return function(e, msg, ...args){ | ||||||
|  | 		stats | ||||||
|  | 			&& (stats.assertions += 1) | ||||||
|  | 			&& !e | ||||||
|  | 				&& (stats.failures += 1) | ||||||
|  | 		module.VERBOSE | ||||||
|  | 			&& console.log(pre +': '+ msg, ...args) | ||||||
|  | 		console.assert(e, pre +': '+ msg, ...args) | ||||||
|  | 		return e } } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| //---------------------------------------------------------------------
 | //---------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| var setups = { | var setups = { | ||||||
| 	basic: function(msg){ | 	basic: function(assert){ | ||||||
| 		var X, Y, A, B, C | 		var X, Y, A, B, C | ||||||
| 		return { | 		return { | ||||||
| 			X: X = object.Constructor('A'), | 			X: X = assert(object.Constructor('A'), `Constructor`), | ||||||
| 			Y: Y = object.C('Y', { }), | 			Y: Y = assert(object.C('Y', { }), ` C`), | ||||||
| 
 | 
 | ||||||
| 			A: A = object.C('A', Y, { }), | 			A: A = assert(object.C('A', Y, { }), `inherit (gen1)`), | ||||||
| 			B: B = object.C('B', A, { }), | 			B: B = assert(object.C('B', A, { }), `inherit (gen2)`), | ||||||
| 			C: C = object.C('C', B, { }), | 			C: C = assert(object.C('C', B, { }), `inherit (gen3)`), | ||||||
| 		} }, | 		} }, | ||||||
| 	init: function(msg){ | 	init: function(assert){ | ||||||
| 		return { | 		return { | ||||||
| 
 | 
 | ||||||
| 		} }, | 		} }, | ||||||
| 	call: function(msg){ | 	call: function(assert){ | ||||||
|  | 		var A, B, C, D, F, G | ||||||
|  | 		return { | ||||||
|  | 			A: A = assert(object.C('A',  | ||||||
|  | 				function(){ | ||||||
|  | 					// XXX
 | ||||||
|  | 				}), 'callable'), | ||||||
|  | 			B: B = assert(object.C('B', { | ||||||
|  | 				__call__: function(){ | ||||||
|  | 					// XXX
 | ||||||
|  | 				}, | ||||||
|  | 			}), 'callable'), | ||||||
|  | 
 | ||||||
|  | 			C: C = assert(object.C('C', A, {}), 'basic inherit'), | ||||||
|  | 			D: D = assert(object.C('D', B, {}), 'basic inherit'), | ||||||
|  | 
 | ||||||
|  | 			E: E = assert(object.C('E', A, | ||||||
|  | 				function(){ | ||||||
|  | 					// XXX how do we get the parent callable???
 | ||||||
|  | 					object.parent(this) | ||||||
|  | 				}), 'call parent'), | ||||||
|  | 			F: F = assert(object.C('F', B, { | ||||||
|  | 				__call__: function(){ | ||||||
|  | 					object.parentCall(F.__call__, this) | ||||||
|  | 				}, | ||||||
|  | 			}), 'call parent\'s .__call__'), | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 		} }, | ||||||
|  | 	native: function(assert){ | ||||||
| 		return { | 		return { | ||||||
| 
 | 
 | ||||||
| 		} }, | 		} }, | ||||||
| 	native: function(msg){ | 	mixin: function(assert){ | ||||||
| 		return { | 		return { | ||||||
| 
 | 
 | ||||||
| 		} }, | 		} }, | ||||||
| 	instances: function(msg){ | 	instances: function(assert){ | ||||||
| 		// XXX generate using tests.instance*
 | 		// XXX generate using tests.instance*
 | ||||||
|  | 		// XXX need to be able to use different input setups...
 | ||||||
| 		return {} | 		return {} | ||||||
| 	}, | 	}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var modifiers = { | var modifiers = { | ||||||
| 	'as-is': function(msg, setup){ | 	// default...
 | ||||||
|  | 	'as-is': function(assert, setup){ | ||||||
| 		return setup } | 		return setup } | ||||||
|  | 
 | ||||||
|  | 	// XXX
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| var tests = { | var tests = { | ||||||
| 	instance: function(msg, setup, no_new){ | 	instance: function(assert, setup, mode){ | ||||||
| 		return constructors(setup)  | 		return constructors(setup)  | ||||||
| 			.reduce(function(res, [k, O]){ | 			.reduce(function(res, [k, O]){ | ||||||
| 				var o | 				var o = res[k.toLowerCase()] =  | ||||||
| 				no_new ? | 					mode == 'no_new' ? | ||||||
| 					console.assert(o = res[k.toLowerCase()] = O(), `${msg}: new:`, k) | 						assert(O(), `new:`, k) | ||||||
| 					: console.assert(o = res[k.toLowerCase()] = new O(), `${msg}: new:`, k) | 					: mode == 'raw' ? | ||||||
| 				console.assert(o instanceof O, `${msg}: instanceof:`, k) | 						assert(O.__rawinstance__(), `.__rawinstance__()`, k)	 | ||||||
| 				console.assert(o.constructor === O, `${msg}: constructor:`, k) | 					: assert(new O(), `new:`, k) | ||||||
| 				console.assert(o.__proto__ === O.prototype, `${msg}: __proto__:`, k) | 				assert(o instanceof O, `instanceof:`, k) | ||||||
|  | 				O.__proto__ instanceof Function | ||||||
|  | 					&& assert(o instanceof O.__proto__, `instanceof-nested:`, k) | ||||||
|  | 				assert(o.constructor === O, `.constructor:`, k) | ||||||
|  | 				assert(o.__proto__ === O.prototype, `.__proto__:`, k) | ||||||
| 				return res }, {}) }, | 				return res }, {}) }, | ||||||
| 	instance_no_new: function(msg, setup){ | 	instance_no_new: function(assert, setup){ | ||||||
| 		return this.instance(msg, setup, true) }, | 		return this.instance(assert, setup, 'no_new') }, | ||||||
|  | 	instance_raw: function(assert, setup){ | ||||||
|  | 		return this.instance(assert, setup, 'raw') }, | ||||||
|  | 
 | ||||||
|  | 	attributes: function(assert, setup){ | ||||||
|  | 		return {} | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
|  | 	// XXX
 | ||||||
|  | 	methods: function(assert, setup){ | ||||||
|  | 		constructors(setup) | ||||||
|  | 			.forEach(function([k, O]){ | ||||||
|  | 				Object.keys(O).forEach(function(m){ | ||||||
|  | 					typeof(O[m]) == 'function' | ||||||
|  | 						&& O[m]() }) | ||||||
|  | 			}) | ||||||
|  | 		return {} | ||||||
|  | 	}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -90,8 +162,18 @@ var cases = { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // XXX need to report stats...
 | //---------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  | // XXX need to have two modes:
 | ||||||
|  | // 		- clean
 | ||||||
|  | // 		- reuse test results again...
 | ||||||
| var runner = function(){ | var runner = function(){ | ||||||
|  | 	var stats = { | ||||||
|  | 		tests: 0, | ||||||
|  | 		assertions: 0, | ||||||
|  | 		failures: 0, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// tests...
 | 	// tests...
 | ||||||
| 	Object.keys(tests) | 	Object.keys(tests) | ||||||
| 		.forEach(function(t){ | 		.forEach(function(t){ | ||||||
| @ -102,15 +184,21 @@ var runner = function(){ | |||||||
| 					Object.keys(setups) | 					Object.keys(setups) | ||||||
| 						.forEach(function(s){ | 						.forEach(function(s){ | ||||||
| 							// run the test...
 | 							// run the test...
 | ||||||
| 							msg =`test:${t}.${s}.${m}` | 							stats.tests += 1 | ||||||
| 							tests[t](msg, modifiers[m](msg, setups[s](msg))) }) }) })  | 							var _assert = assert(`test:${t}.${s}.${m}`, stats) | ||||||
|  | 							tests[t](_assert,  | ||||||
|  | 								modifiers[m](_assert,  | ||||||
|  | 									setups[s](_assert))) }) }) })  | ||||||
| 	// cases...
 | 	// cases...
 | ||||||
| 	Object.keys(cases) | 	Object.keys(cases) | ||||||
| 		.forEach(function(c){ | 		.forEach(function(c){ | ||||||
| 			msg = `case:${c}:` | 			stats.tests += 1 | ||||||
| 			cases[c](msg) | 			cases[c]( assert(`case:${c}:`, stats) ) })  | ||||||
| 		}) | 
 | ||||||
| } | 	// stats...
 | ||||||
|  | 	console.log('Tests:', stats.tests,  | ||||||
|  | 		'Assertions:', stats.assertions,  | ||||||
|  | 		'Failures:', stats.failures) } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| runner() | runner() | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user