diff --git a/object.js b/object.js index 7bef63b..6ff922f 100755 --- a/object.js +++ b/object.js @@ -21,6 +21,12 @@ (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 // defined via .__call__(..) @@ -344,18 +350,6 @@ function(obj){ //--------------------------------------------------------------------- // 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(){ // Error with some JS quirks fixed... @@ -377,119 +371,9 @@ BOOTSTRAP(function(){ //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... @@ -523,7 +407,7 @@ function*(obj, name, props=false){ && name == '__call__' && typeof(obj) == 'function' ? obj - : obj[name] + : obj[name], ] }} // XXX @@ -1448,6 +1332,8 @@ function(base, ...objects){ // NOTE: this will also match base... // NOTE: if base matches directly callback(..) will get undefined as parent // NOTE: for more docs on the callback(..) see sources(..) +// +// XXX should this be a generator??? var mixins = module.mixins = function(base, object, callback){ diff --git a/package.json b/package.json index 1a406c8..066c9fc 100755 --- a/package.json +++ b/package.json @@ -28,5 +28,8 @@ "c8": "^7.3.5", "colors": "1.4.0", "ig-test": "^1.4.8" + }, + "dependencies": { + "ig-stoppable": "^2.0.0" } } diff --git a/test.js b/test.js index 37f7614..c9cfe1e 100755 --- a/test.js +++ b/test.js @@ -328,21 +328,22 @@ var setups = test.Setups({ method: function(){ var x, y assert.array( - object.values(c, 'x'), + [...object._values(c, 'x')], ['c', 'a', 'b'], 'reach all values of attr') assert.array( - object.values(c, 'x', function(v, o){ - return v.toUpperCase() }), + [...object._values(c, 'x')] + .map(function(v){ + return v.toUpperCase() }), ['C', 'A', 'B'], 'reach all values of attr') assert.array( - object.sources(c, 'method'), + [...object._sources(c, 'method')], // NOTE: not passing an explicit list as we need // to account for mixins... - object.sources(c) - .filter(function(s){ - return s.hasOwnProperty('method') }), + [...object._sources(c)] + .filter(function(s){ + return s.hasOwnProperty('method') }), 'reach all values of method') assert( (x = object.parent(c, 'x')) == 'b', @@ -376,16 +377,17 @@ var setups = test.Setups({ method(){ // XXX this is almost the same as for js_prototype... assert.array( - object.values(c, 'x'), + [...object._values(c, 'x')], ['z', 'y', 'x'], 'reach all values of attr (class)') assert.array( - object.values(c, 'x', function(v, o){ - return v.toUpperCase() }), + [...object._values(c, 'x')] + .map(function(v){ + return v.toUpperCase() }), ['C', 'A', 'B'], 'reach all values of attr (class)') assert.array( - object.sources(c, 'method'), + [...object._sources(c, 'method')], [Z.prototype, X.prototype], 'reach all values of method (class)') assert( @@ -578,12 +580,12 @@ var tests = test.Tests({ var test = function(obj, name){ var a, b return assert(arrayCmp( - a = object.values(obj, '__call__') + a = [...object._values(obj, '__call__')] .map(function(func){ return func.call(obj) }) .flat(), // get all callables in prototype chain and call them... - b = object.sources(obj) + b = [...object._sources(obj)] .filter(function(o){ return typeof(o) == 'function' || o.hasOwnProperty('__call__') }) @@ -661,11 +663,12 @@ var cases = test.Cases({ obj.x = 321 assert.array( - object.values(obj, 'x', true) + [...object._values(obj, 'x', true)] .map(function(e){ return e.value }), // XXX assert ignores the order here -- this should fail... [123, 321], '.values(.., true) ') + /* XXX GENERATOR not relevant... assert( object.values(obj, 'x', function(){ return object.STOP })[0] == 321, // 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, // XXX assert ignores the order here -- this should fail... '.values(.., func, true) with explicit stop value') + //*/ }, deepKeys: function(assert){