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)
- [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(<object>, <name>, <callback>)
```
callback(<source>)
-> 'stop' | false
-> STOP
-> 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(..)`
@ -482,8 +507,9 @@ values(<object>, <name>, <callback>)
```
callback(<value>, <source>)
-> 'stop' | false
-> STOP
-> undefined
-> <value>
```
@ -496,10 +522,12 @@ values(<object>, <name>, <callback>, true)
```
callback(<descriptor>, <source>)
-> 'stop' | false
-> STOP
-> undefined
-> <value>
```
See [`sources(..)`](#sources) for docs on `callback(..)`
### `parent(..)`
@ -573,10 +601,13 @@ mixins(<base>, [<object>, ..], <callback>)
```
callback(<match>, <object>, <parent>)
-> 'stop' | false
-> STOP
-> undefined
-> <value>
```
See [`sources(..)`](#sources) for docs on `callback(..)`
### `hasMixin(..)`

101
object.js
View File

@ -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...

View File

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