reworked the callback(..) symantics...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-05-24 00:37:52 +03:00
parent 6b6348c835
commit 342a07fd34
3 changed files with 101 additions and 41 deletions

View File

@ -126,6 +126,7 @@ class B extends A {
- [Inheriting from native constructor objects](#inheriting-from-native-constructor-objects) - [Inheriting from native constructor objects](#inheriting-from-native-constructor-objects)
- [Extending native `.constructor(..)`](#extending-native-constructor) - [Extending native `.constructor(..)`](#extending-native-constructor)
- [Components](#components) - [Components](#components)
- [`STOP`](#stop)
- [`sources(..)`](#sources) - [`sources(..)`](#sources)
- [`values(..)`](#values) - [`values(..)`](#values)
- [`parent(..)`](#parent) - [`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(..)` ### `sources(..)`
Get sources for attribute Get sources for attribute
@ -466,10 +475,26 @@ sources(<object>, <name>, <callback>)
``` ```
callback(<source>) callback(<source>)
-> 'stop' | false -> STOP
-> undefined -> undefined
-> <value>
``` ```
The `callback(..)` controls the output of `sources(..)` by returning
one of the following:
- `object.STOP`
This will make `sources(..)` stop and return the `<list>` including
the object that triggered the _stop_.
- `undefined`
Return the object triggering `callback(..)` in `<list>` 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.
- <value>
Returned as-is instead of the object triggering `callback(..)`.
### `values(..)` ### `values(..)`
@ -482,8 +507,9 @@ values(<object>, <name>, <callback>)
``` ```
callback(<value>, <source>) callback(<value>, <source>)
-> 'stop' | false -> STOP
-> undefined -> undefined
-> <value>
``` ```
@ -496,10 +522,12 @@ values(<object>, <name>, <callback>, true)
``` ```
callback(<descriptor>, <source>) callback(<descriptor>, <source>)
-> 'stop' | false -> STOP
-> undefined -> undefined
-> <value>
``` ```
See [`sources(..)`](#sources) for docs on `callback(..)`
### `parent(..)` ### `parent(..)`
@ -573,10 +601,13 @@ mixins(<base>, [<object>, ..], <callback>)
``` ```
callback(<match>, <object>, <parent>) callback(<match>, <object>, <parent>)
-> 'stop' | false -> STOP
-> undefined -> undefined
-> <value>
``` ```
See [`sources(..)`](#sources) for docs on `callback(..)`
### `hasMixin(..)` ### `hasMixin(..)`

View File

@ -142,6 +142,12 @@ function(base, obj){
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Prototype chain content access... // 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... // Get a list of source objects for a prop/attr name...
// //
// sources(obj, name) // sources(obj, name)
@ -150,18 +156,25 @@ function(base, obj){
// -> [] // -> []
// //
// callback(obj) // callback(obj)
// -> true | 'stop' // -> STOP
// -> .. // -> ..
// //
// //
// The callback(..) is called with each matching object. // The callback(..) is called with each matching object.
// //
// The callback(..) can be used to break/stop the search, returning // callback(..) return values:
// a partial list og matcges up untill and including the object // - STOP - stop the search and return the match list terminated
// triggering the stop. // 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 // instance/class or instance/prototype) bounderies and depends
// only on the object given as the starting point. // only on the object given as the starting point.
// It is possible to start the search from this, thus checking // It is possible to start the search from this, thus checking
@ -171,21 +184,23 @@ function(base, obj){
var sources = var sources =
module.sources = module.sources =
function(obj, name, callback){ function(obj, name, callback){
var stop var o
var res = [] var res = []
do { while(obj != null){
if(obj.hasOwnProperty(name)){ if(obj.hasOwnProperty(name)){
res.push(obj)
// handle callback... // handle callback...
stop = callback o = callback
&& callback(obj) && callback(obj)
// stop requested by callback... // manage results...
if(stop === true || stop == 'stop'){ res.push(
return res } (o === undefined || o === module.STOP) ?
} [obj]
obj = obj.__proto__ : o )
} while(obj !== null) // stop...
return res } 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... // Get a list of values/props set in source objects for a prop/attr name...
@ -202,11 +217,12 @@ function(obj, name, callback){
// -> list // -> list
// -> [] // -> []
// //
// callback(value, obj) // callback(value/prop, obj)
// -> true | 'stop' // -> STOP
// -> .. // -> ..
// //
// //
// NOTE: for more docs on the callback(..) see sources(..)
var values = var values =
module.values = module.values =
function(obj, name, callback, props){ function(obj, name, callback, props){
@ -219,7 +235,7 @@ function(obj, name, callback, props){
return callback( return callback(
props ? props ?
Object.getOwnPropertyDescriptor(obj, name) Object.getOwnPropertyDescriptor(obj, name)
: obj[name], : [ obj[name] ],
obj) } obj) }
return sources(...(c ? return sources(...(c ?
[obj, name, c] [obj, name, c]
@ -287,17 +303,22 @@ function(obj, name, callback, props){
var parent = var parent =
module.parent = module.parent =
function(proto, name){ function(proto, name){
// special case: method... // special case: get method...
if(typeof(name) != typeof('str')){ if(typeof(name) != typeof('str')){
that = name var that = name
name = proto.name name = proto.name
// sanity check...
if(name == ''){
throw new Error('parent(..): need a method with non-empty .name') }
// get first matching source... // get first matching source...
proto = sources(that, name, proto = sources(that, name,
function(obj){ return obj[name] === proto }) function(obj){
return obj[name] === proto
&& module.STOP })
.pop() } .pop() }
// get first source... // get first source...
var res = sources(proto, name, var res = sources(proto, name,
function(obj){ return 'stop' }) function(obj){ return module.STOP })
.pop() .pop()
return res ? return res ?
// get next value... // get next value...
@ -319,7 +340,9 @@ function(proto, name){
// get second source... // get second source...
var c = 0 var c = 0
var res = sources(proto, name, var res = sources(proto, name,
function(obj){ return c++ == 1 }) function(obj){
return c++ == 1
&& module.STOP })
.pop() .pop()
return res ? return res ?
// get next value... // get next value...
@ -416,12 +439,13 @@ function(base, ...objects){
// //
// //
// callback(base, obj, parent) // callback(base, obj, parent)
// -> 'stop' | false // -> STOP
// -> undefined // -> undefined
// //
// //
// NOTE: if base matches directly callback(..) will get undefined as parent // NOTE: if base matches directly callback(..) will get undefined as parent
// NOTE: this will also match base... // NOTE: this will also match base...
// NOTE: for more docs on the callback(..) see sources(..)
var mixins = var mixins =
module.mixins = module.mixins =
function(base, object, callback){ function(base, object, callback){
@ -429,22 +453,26 @@ function(base, object, callback){
object object
: [object] : [object]
var res = [] var res = []
var stop var o
var parent var parent
while(base != null){ while(base != null){
// match each object... // match each object...
for(var obj of object){ for(var obj of object){
if(match(base, obj)){ if(match(base, obj)){
res.push(base) o = callback
stop = callback
&& callback(base, obj, parent) && callback(base, obj, parent)
if(stop === true || stop == 'stop'){ // manage results...
return res } res.push(
(o === undefined || o === module.STOP) ?
[base]
: o )
if(o === module.STOP){
return res.flat() }
// match found, no need to test further... // match found, no need to test further...
break } } break } }
parent = base parent = base
base = base.__proto__ } base = base.__proto__ }
return res } return res.flat() }
// Check of base has mixin... // Check of base has mixin...
@ -452,10 +480,11 @@ function(base, object, callback){
// hasMixin(base, mixin) // hasMixin(base, mixin)
// -> bool // -> bool
// //
//
var hasMixin = var hasMixin =
module.hasMixin = module.hasMixin =
function(base, object){ 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... // Mix-out sets of methods/props/attrs out of an object prototype chain...

View File

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