mirror of
https://github.com/flynx/object.js.git
synced 2025-10-30 11:00:08 +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