From 342a07fd34784e01baef15629133fbec8afb4169 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Sun, 24 May 2020 00:37:52 +0300 Subject: [PATCH] reworked the callback(..) symantics... Signed-off-by: Alex A. Naanou --- README.md | 39 ++++++++++++++++++-- object.js | 101 +++++++++++++++++++++++++++++++++------------------ package.json | 2 +- 3 files changed, 101 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 0fa4321..481b211 100755 --- a/README.md +++ b/README.md @@ -126,6 +126,7 @@ class B extends A { - [Inheriting from native constructor objects](#inheriting-from-native-constructor-objects) - [Extending native `.constructor(..)`](#extending-native-constructor) - [Components](#components) + - [`STOP`](#stop) - [`sources(..)`](#sources) - [`values(..)`](#values) - [`parent(..)`](#parent) @@ -455,6 +456,14 @@ var l = object.RawInstance(null, Array, 'a', 'b', 'c') ``` + +### `STOP` + +Used in [`sources(..)`](#sources), [`values(..)`](#values) and +[`mixins(..)`](#mixins) to stop the search before it reaches the top of +the prototype chain. + + ### `sources(..)` Get sources for attribute @@ -466,10 +475,26 @@ sources(, , ) ``` callback() - -> 'stop' | false + -> STOP -> undefined + -> ``` +The `callback(..)` controls the output of `sources(..)` by returning +one of the following: + +- `object.STOP` + This will make `sources(..)` stop and return the `` including + the object that triggered the _stop_. +- `undefined` + Return the object triggering `callback(..)` in `` as-is. +- array + The containing values will be merged into the result list. This is a + way to either skip an object by returning `[]` or multiple values + instead of one. +- + Returned as-is instead of the object triggering `callback(..)`. + ### `values(..)` @@ -482,8 +507,9 @@ values(, , ) ``` callback(, ) - -> 'stop' | false + -> STOP -> undefined + -> ``` @@ -496,10 +522,12 @@ values(, , , true) ``` callback(, ) - -> 'stop' | false + -> STOP -> undefined + -> ``` +See [`sources(..)`](#sources) for docs on `callback(..)` ### `parent(..)` @@ -573,10 +601,13 @@ mixins(, [, ..], ) ``` callback(, , ) - -> 'stop' | false + -> STOP -> undefined + -> ``` +See [`sources(..)`](#sources) for docs on `callback(..)` + ### `hasMixin(..)` diff --git a/object.js b/object.js index 646f708..63cec6a 100755 --- a/object.js +++ b/object.js @@ -142,6 +142,12 @@ function(base, obj){ //--------------------------------------------------------------------- // Prototype chain content access... +// object to trigger iteration stop... +// +module.STOP = + {doc: 'stop iteration.'} + + // Get a list of source objects for a prop/attr name... // // sources(obj, name) @@ -150,18 +156,25 @@ function(base, obj){ // -> [] // // callback(obj) -// -> true | 'stop' +// -> STOP // -> .. // -// +// // The callback(..) is called with each matching object. -// -// The callback(..) can be used to break/stop the search, returning -// a partial list og matcges up untill and including the object -// triggering the stop. // +// callback(..) return values: +// - STOP - stop the search and return the match list terminated +// with the object triggering the stop. +// - undefined - return the triggering object as-is +// NOTE: this is the same as returning [obj] +// - array - merge array content into the result insteaad of +// the triggering value. +// NOTE: an ampty array will effectively omit the +// triggering object from the results. +// - other - return a value instead of the triggering object. +// // -// NOTE: this go up the prototype chain, not caring about any role ( +// NOTE: this gos up the prototype chain, not caring about any role ( // instance/class or instance/prototype) bounderies and depends // only on the object given as the starting point. // It is possible to start the search from this, thus checking @@ -171,21 +184,23 @@ function(base, obj){ var sources = module.sources = function(obj, name, callback){ - var stop + var o var res = [] - do { + while(obj != null){ if(obj.hasOwnProperty(name)){ - res.push(obj) // handle callback... - stop = callback + o = callback && callback(obj) - // stop requested by callback... - if(stop === true || stop == 'stop'){ - return res } - } - obj = obj.__proto__ - } while(obj !== null) - return res } + // manage results... + res.push( + (o === undefined || o === module.STOP) ? + [obj] + : o ) + // stop... + if(o === module.STOP){ + return res.flat() } } + obj = obj.__proto__ } + return res.flat() } // Get a list of values/props set in source objects for a prop/attr name... @@ -202,11 +217,12 @@ function(obj, name, callback){ // -> list // -> [] // -// callback(value, obj) -// -> true | 'stop' +// callback(value/prop, obj) +// -> STOP // -> .. // -// +// +// NOTE: for more docs on the callback(..) see sources(..) var values = module.values = function(obj, name, callback, props){ @@ -219,7 +235,7 @@ function(obj, name, callback, props){ return callback( props ? Object.getOwnPropertyDescriptor(obj, name) - : obj[name], + : [ obj[name] ], obj) } return sources(...(c ? [obj, name, c] @@ -287,21 +303,26 @@ function(obj, name, callback, props){ var parent = module.parent = function(proto, name){ - // special case: method... + // special case: get method... if(typeof(name) != typeof('str')){ - that = name + var that = name name = proto.name + // sanity check... + if(name == ''){ + throw new Error('parent(..): need a method with non-empty .name') } // get first matching source... proto = sources(that, name, - function(obj){ return obj[name] === proto }) + function(obj){ + return obj[name] === proto + && module.STOP }) .pop() } // get first source... var res = sources(proto, name, - function(obj){ return 'stop' }) + function(obj){ return module.STOP }) .pop() return res ? // get next value... - res.__proto__[name] + res.__proto__[name] : undefined } @@ -319,7 +340,9 @@ function(proto, name){ // get second source... var c = 0 var res = sources(proto, name, - function(obj){ return c++ == 1 }) + function(obj){ + return c++ == 1 + && module.STOP }) .pop() return res ? // get next value... @@ -416,12 +439,13 @@ function(base, ...objects){ // // // callback(base, obj, parent) -// -> 'stop' | false +// -> STOP // -> undefined // // // NOTE: if base matches directly callback(..) will get undefined as parent // NOTE: this will also match base... +// NOTE: for more docs on the callback(..) see sources(..) var mixins = module.mixins = function(base, object, callback){ @@ -429,22 +453,26 @@ function(base, object, callback){ object : [object] var res = [] - var stop + var o var parent while(base != null){ // match each object... for(var obj of object){ if(match(base, obj)){ - res.push(base) - stop = callback + o = callback && callback(base, obj, parent) - if(stop === true || stop == 'stop'){ - return res } + // manage results... + res.push( + (o === undefined || o === module.STOP) ? + [base] + : o ) + if(o === module.STOP){ + return res.flat() } // match found, no need to test further... break } } parent = base base = base.__proto__ } - return res } + return res.flat() } // Check of base has mixin... @@ -452,10 +480,11 @@ function(base, object, callback){ // hasMixin(base, mixin) // -> bool // +// var hasMixin = module.hasMixin = function(base, object){ - return mixins(base, object, function(){ return 'stop' }).length > 0 } + return mixins(base, object, function(){ return module.STOP }).length > 0 } // Mix-out sets of methods/props/attrs out of an object prototype chain... diff --git a/package.json b/package.json index a3a4c6e..e728d56 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ig-object", - "version": "4.0.4", + "version": "5.0.0", "description": "", "main": "object.js", "scripts": {