moved code to ig-stoppable...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-07-05 23:26:59 +03:00
parent dcb1321e6a
commit 6d85d8718c
3 changed files with 30 additions and 137 deletions

132
object.js
View File

@ -21,6 +21,12 @@
(function(require){ var module={} // make module AMD/node compatible... (function(require){ var module={} // make module AMD/node compatible...
/*********************************************************************/ /*********************************************************************/
var STOP =
module.STOP =
require('ig-stoppable').STOP
//---------------------------------------------------------------------
// Function methods to link into a constructor producing a callable // Function methods to link into a constructor producing a callable
// defined via .__call__(..) // defined via .__call__(..)
@ -344,18 +350,6 @@ function(obj){
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Helper objects/constructors... // Helper objects/constructors...
// NOTE: these are missing from JavaScript for some reason...
//
// XXX should these be global???
var Generator =
module.Generator =
(function*(){}).constructor
var AsyncGenerator =
module.AsyncGenerator =
(async function*(){}).constructor
BOOTSTRAP(function(){ BOOTSTRAP(function(){
// Error with some JS quirks fixed... // Error with some JS quirks fixed...
@ -377,119 +371,9 @@ BOOTSTRAP(function(){
//return Reflect.construct(Error, args, this.constructor) }, //return Reflect.construct(Error, args, this.constructor) },
}) })
// Value trigger iteration stop and to carry results...
//
module.STOP =
Constructor('STOP', {
doc: 'stop iteration.',
__init__: function(value){
this.value = value },
})
}) })
// Wrap a callable in a STOP handler
//
// stoppable(func)
// -> func
//
// stoppable(gen)
// -> gen
//
// stoppable(asyncgen)
// -> asyncgen
//
//
// The client callable can be one of:
// - function
// - generator
// - async generator
//
// The returned callable will be of the same type as the input callable.
//
// The wrapper handles STOP slightly differently if the client is a
// function or if it is a generator / async generator:
// - function
// STOP returned / thrown
// -> return undefined
// STOP(value) returned / thrown
// -> return value
// - generator / async generator
// STOP yielded / thrown
// -> iteration stops
// STOP(value) yielded / thrown
// -> value yielded and iteration stops
//
//
// NOTE: this repeats the same code at lest twice, not sure yet how to avoid
// this...
//
// XXX user doc!!!
var stoppable =
module.stoppable =
function(func){
return Object.assign(
func instanceof Generator ?
// NOTE: the only difference between Generator/AsyncGenerator
// versions of this is the async keyword -- keep them
// in sync...
function*(){
try{
for(var res of func.call(this, ...arguments)){
if(res === STOP){
return }
if(res instanceof STOP){
yield res.value
return }
yield res }
} catch(err){
if(err === STOP){
return
} else if(err instanceof STOP){
yield err.value
return }
throw err } }
: func instanceof AsyncGenerator ?
// NOTE: the only difference between Generator/AsyncGenerator
// versions of this is the async keyword -- keep them
// in sync...
async function*(){
try{
for(var res of func.call(this, ...arguments)){
if(res === STOP){
return }
if(res instanceof STOP){
yield res.value
return }
yield res }
} catch(err){
if(err === STOP){
return
} else if(err instanceof STOP){
yield err.value
return }
throw err } }
: function(){
try{
var res = func.call(this, ...arguments)
// NOTE: this is here for uniformity...
if(res === STOP){
return }
if(res instanceof STOP){
return res.value }
return res
} catch(err){
if(err === STOP){
return
} else if(err instanceof STOP){
return err.value }
throw err } },
{ toString: function(){
return func.toString() }, }) }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Prototype chain content access... // Prototype chain content access...
@ -523,7 +407,7 @@ function*(obj, name, props=false){
&& name == '__call__' && name == '__call__'
&& typeof(obj) == 'function' ? && typeof(obj) == 'function' ?
obj obj
: obj[name] : obj[name],
] }} ] }}
// XXX // XXX
@ -1448,6 +1332,8 @@ function(base, ...objects){
// NOTE: this will also match base... // NOTE: this will also match base...
// NOTE: if base matches directly callback(..) will get undefined as parent // NOTE: if base matches directly callback(..) will get undefined as parent
// NOTE: for more docs on the callback(..) see sources(..) // NOTE: for more docs on the callback(..) see sources(..)
//
// XXX should this be a generator???
var mixins = var mixins =
module.mixins = module.mixins =
function(base, object, callback){ function(base, object, callback){

View File

@ -28,5 +28,8 @@
"c8": "^7.3.5", "c8": "^7.3.5",
"colors": "1.4.0", "colors": "1.4.0",
"ig-test": "^1.4.8" "ig-test": "^1.4.8"
},
"dependencies": {
"ig-stoppable": "^2.0.0"
} }
} }

24
test.js
View File

@ -328,19 +328,20 @@ var setups = test.Setups({
method: function(){ method: function(){
var x, y var x, y
assert.array( assert.array(
object.values(c, 'x'), [...object._values(c, 'x')],
['c', 'a', 'b'], ['c', 'a', 'b'],
'reach all values of attr') 'reach all values of attr')
assert.array( assert.array(
object.values(c, 'x', function(v, o){ [...object._values(c, 'x')]
.map(function(v){
return v.toUpperCase() }), return v.toUpperCase() }),
['C', 'A', 'B'], ['C', 'A', 'B'],
'reach all values of attr') 'reach all values of attr')
assert.array( assert.array(
object.sources(c, 'method'), [...object._sources(c, 'method')],
// NOTE: not passing an explicit list as we need // NOTE: not passing an explicit list as we need
// to account for mixins... // to account for mixins...
object.sources(c) [...object._sources(c)]
.filter(function(s){ .filter(function(s){
return s.hasOwnProperty('method') }), return s.hasOwnProperty('method') }),
'reach all values of method') 'reach all values of method')
@ -376,16 +377,17 @@ var setups = test.Setups({
method(){ method(){
// XXX this is almost the same as for js_prototype... // XXX this is almost the same as for js_prototype...
assert.array( assert.array(
object.values(c, 'x'), [...object._values(c, 'x')],
['z', 'y', 'x'], ['z', 'y', 'x'],
'reach all values of attr (class)') 'reach all values of attr (class)')
assert.array( assert.array(
object.values(c, 'x', function(v, o){ [...object._values(c, 'x')]
.map(function(v){
return v.toUpperCase() }), return v.toUpperCase() }),
['C', 'A', 'B'], ['C', 'A', 'B'],
'reach all values of attr (class)') 'reach all values of attr (class)')
assert.array( assert.array(
object.sources(c, 'method'), [...object._sources(c, 'method')],
[Z.prototype, X.prototype], [Z.prototype, X.prototype],
'reach all values of method (class)') 'reach all values of method (class)')
assert( assert(
@ -578,12 +580,12 @@ var tests = test.Tests({
var test = function(obj, name){ var test = function(obj, name){
var a, b var a, b
return assert(arrayCmp( return assert(arrayCmp(
a = object.values(obj, '__call__') a = [...object._values(obj, '__call__')]
.map(function(func){ .map(function(func){
return func.call(obj) }) return func.call(obj) })
.flat(), .flat(),
// get all callables in prototype chain and call them... // get all callables in prototype chain and call them...
b = object.sources(obj) b = [...object._sources(obj)]
.filter(function(o){ .filter(function(o){
return typeof(o) == 'function' return typeof(o) == 'function'
|| o.hasOwnProperty('__call__') }) || o.hasOwnProperty('__call__') })
@ -661,11 +663,12 @@ var cases = test.Cases({
obj.x = 321 obj.x = 321
assert.array( assert.array(
object.values(obj, 'x', true) [...object._values(obj, 'x', true)]
.map(function(e){ return e.value }), .map(function(e){ return e.value }),
// XXX assert ignores the order here -- this should fail... // XXX assert ignores the order here -- this should fail...
[123, 321], '.values(.., true) ') [123, 321], '.values(.., true) ')
/* XXX GENERATOR not relevant...
assert( assert(
object.values(obj, 'x', function(){ return object.STOP })[0] == 321, object.values(obj, 'x', function(){ return object.STOP })[0] == 321,
// XXX assert ignores the order here -- this should fail... // XXX assert ignores the order here -- this should fail...
@ -678,6 +681,7 @@ var cases = test.Cases({
object.values(obj, 'x', function(){ return object.STOP(555) }, true)[0] == 555, object.values(obj, 'x', function(){ return object.STOP(555) }, true)[0] == 555,
// XXX assert ignores the order here -- this should fail... // XXX assert ignores the order here -- this should fail...
'.values(.., func, true) with explicit stop value') '.values(.., func, true) with explicit stop value')
//*/
}, },
deepKeys: function(assert){ deepKeys: function(assert){