updated docs, tests and notes..

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-06-01 02:49:00 +03:00
parent 17a4104514
commit b4ceef5c93
4 changed files with 100 additions and 36 deletions

View File

@ -373,6 +373,13 @@ var LowLevel = object.Constructor('LowLevel', {
``` ```
The value `.__new__(..)` returns is used as the instance and gets linked
to the prototype chain by the calling constructor's `.__rawinstance__(..)`,
the constructor then will call `.__init__(..)` if defined.
_Note that `.__init__(..)` is called by the constructor and not by
`RawInstance(..)` or `.__rawinstance__(..)`._
Like [_function constructor_ and `.__call__(..)`](#callable-instances) Like [_function constructor_ and `.__call__(..)`](#callable-instances)
this also has two contexts, but the internal context is different -- as this also has two contexts, but the internal context is different -- as
it is the job of `.__new__(..)` to create an instance, at time of call it is the job of `.__new__(..)` to create an instance, at time of call
@ -389,10 +396,6 @@ Contexts:
(`window` or `global` by default), the same as for function constructor (`window` or `global` by default), the same as for function constructor
and `.__call__(..)`. and `.__call__(..)`.
The value `.__new__(..)`returns is used as the instance and gets linked
in the prototype chain.
This has priority over the callable protocols above, thus the user must This has priority over the callable protocols above, thus the user must
take care of both the _function constructor_ and `prototype.__call__(..)` take care of both the _function constructor_ and `prototype.__call__(..)`
handling. handling.

View File

@ -115,6 +115,8 @@ function(text, tab_size, keep_tabs){
// - attr names are the same and, // - attr names are the same and,
// - attr values are identical. // - attr values are identical.
// //
// NOTE: this will do a shallow test using Object.keys(..) thus .__proto__
// attributes are ignored...
var match = var match =
module.match = module.match =
function(base, obj){ function(base, obj){

View File

@ -1,6 +1,6 @@
{ {
"name": "ig-object", "name": "ig-object",
"version": "5.0.2", "version": "5.0.3",
"description": "", "description": "",
"main": "object.js", "main": "object.js",
"scripts": { "scripts": {

121
test.js
View File

@ -30,6 +30,13 @@ module.VERBOSE = process ?
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// helpers... // helpers...
var deepKeys = function(obj, stop){
var res = []
while(obj !== stop && obj != null){
res.push(Object.keys(obj))
obj = obj.__proto__ }
return [...(new Set(res.flat()))] }
// a constructor is a thing that starts with a capital and has a .prototype // a constructor is a thing that starts with a capital and has a .prototype
var constructors = function(obj){ var constructors = function(obj){
return Object.entries(obj) return Object.entries(obj)
@ -75,8 +82,38 @@ var setups = {
// initialization... // initialization...
init: function(assert){ init: function(assert){
var A, B, C
return { return {
// init...
A: A = assert(object.C('A', {
msg: '.__init__()',
__init__: function(){
this.init_has_run = true },
test_init: function(){
this.__created_raw ?
assert(!this.init_has_run, this.msg+' did not run')
: assert(this.init_has_run, this.msg+' run') },
}), 'basic .__init__(..)'),
// new...
B: B = assert(object.C('B', {
__new__: function(){
var o = {}
o.new_has_run = true
return o
},
test_new: function(){
assert(this.new_has_run, '.__new__() run') },
}), 'basic .__new__(..)'),
// new + init...
C: C = assert(object.C('C', B, {
msg: '.__init__() after .__new__()',
__init__: function(){
this.init_has_run = true },
test_init: A.prototype.test_init,
}), `inherit .__new__()`),
// XXX gen2 and extended stuff???
// XXX
} }, } },
// callable instances... // callable instances...
@ -89,6 +126,7 @@ var setups = {
return 'A' return 'A'
}), 'callable'), }), 'callable'),
B: B = assert(object.C('B', { B: B = assert(object.C('B', {
__non_function: true,
__call__: function(){ __call__: function(){
return 'B' return 'B'
}, },
@ -161,55 +199,79 @@ var modifiers = {
res[n+'g'+gen] = object.C(n+'g'+gen, O, {}) res[n+'g'+gen] = object.C(n+'g'+gen, O, {})
return res }, {}) }, return res }, {}) },
gen3: function(assert, setup){ gen3: function(assert, setup){
return this.gen2(assert, this.gen2(assert, setup), '3') } return this.gen2(assert, this.gen2(assert, setup), '3') },
// XXX // generate instances...
// NOTE: these are re-used as tests too...
instance: function(assert, setup, mode){
return constructors(setup)
.reduce(function(res, [k, O]){
var o = res[k.toLowerCase()] =
mode == 'no_new' ?
assert(O(), `new:`, k)
: mode == 'raw' ?
assert(O.__rawinstance__(), `.__rawinstance__()`, k)
: assert(new O(), `new:`, 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 }, {}) },
instance_no_new: function(assert, setup){
return this.instance(assert, setup, 'no_new') },
// NOTE: here we mark the raw instances with .__created_raw
instance_raw: function(assert, setup){
var res = this.instance(assert, setup, 'raw')
Object.values(res)
.forEach(function(e){
Object.assign(
e,
{__created_raw: true}) })
return res },
} }
var tests = { var tests = {
// instance creation... // instance creation...
instance: function(assert, setup, mode){ instance: modifiers.instance,
return constructors(setup) instance_no_new: modifiers.instance_no_new,
.reduce(function(res, [k, O]){ instance_raw: modifiers.instance_raw,
var o = res[k.toLowerCase()] =
mode == 'no_new' ?
assert(O(), `new:`, k)
: mode == 'raw' ?
assert(O.__rawinstance__(), `.__rawinstance__()`, k)
: assert(new O(), `new:`, 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 }, {}) },
instance_no_new: function(assert, setup){
return this.instance(assert, setup, 'no_new') },
instance_raw: function(assert, setup){
return this.instance(assert, setup, 'raw') },
/*/ XXX /*/ XXX
attributes: function(assert, setup){ attributes: function(assert, setup){
return {} }, return {} },
//*/ //*/
// XXX
methods: function(assert, setup){ methods: function(assert, setup){
instances(setup)
.forEach(function([k, o]){
deepKeys(o)
.forEach(function(m){
typeof(o[m]) == 'function'
// skip special methods...
&& !m.startsWith('__')
&& o[m]() }) })
return {} },
constructor_methods: function(assert, setup){
constructors(setup) constructors(setup)
.forEach(function([k, O]){ .forEach(function([k, O]){
Object.keys(O).forEach(function(m){ deepKeys(O)
typeof(O[m]) == 'function' .forEach(function(m){
&& O[m]() }) typeof(O[m]) == 'function'
}) // skip special methods...
&& !m.startsWith('__')
&& O[m]() }) })
return {} }, return {} },
callables: function(assert, setup){ callables: function(assert, setup){
return instances(setup) return instances(setup)
.map(function([k, o]){ .map(function([k, o]){
// NOTE: not all callables are instances of Function... // NOTE: not all callables are instances of Function...
//assert(typeof(o) == 'function' typeof(o) == 'function'
// && o instanceof Function, 'instanceof Function', k) && (o.__non_function ?
assert(!(o instanceof Function), 'non-instanceof Function', k)
: assert(o instanceof Function, 'instanceof Function', k))
return typeof(o) == 'function' return typeof(o) == 'function'
&& assert(o(), 'call', k) }) }, && assert(o(), 'call', k) }) },
} }
@ -245,7 +307,6 @@ var runner = function(){
assertions: 0, assertions: 0,
failures: 0, failures: 0,
} }
// tests... // tests...
Object.keys(tests) Object.keys(tests)
.forEach(function(t){ .forEach(function(t){
@ -268,12 +329,10 @@ var runner = function(){
.forEach(function(c){ .forEach(function(c){
stats.tests += 1 stats.tests += 1
cases[c]( makeAssert(`case:${c}:`, stats) ) }) cases[c]( makeAssert(`case:${c}:`, stats) ) })
// stats... // stats...
console.log('Tests run:', stats.tests, console.log('Tests run:', stats.tests,
'Assertions:', stats.assertions, 'Assertions:', stats.assertions,
'Failures:', stats.failures) 'Failures:', stats.failures)
return stats } return stats }