diff --git a/.gitignore b/.gitignore index e71a333..80885ca 100755 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ -.npm* +.* *.vim *.sw[po] -.git coverage node_modules npm-debug.log diff --git a/.npmignore b/.npmignore index 5d2f460..f6ec9f4 100755 --- a/.npmignore +++ b/.npmignore @@ -1,8 +1,6 @@ -.npm* +.* *.vim *.sw[po] -.git -.github coverage node_modules npm-debug.log diff --git a/README.md b/README.md index fe4114a..3788cfd 100755 --- a/README.md +++ b/README.md @@ -844,6 +844,15 @@ or: - attribute values are identical. +Non-strict match +``` +match(base, obj, true) + -> bool +``` + +Like the default case but uses _equality_ instead of _identity_ to match +values. + ## Limitations diff --git a/object.js b/object.js index a2b49a8..a071b56 100755 --- a/object.js +++ b/object.js @@ -115,11 +115,19 @@ function(text, tab_size, leading_tabs){ // - attr names are the same and, // - attr values are identical. // +// +// Non-strict match... +// match(a, b, true) +// +// This is similar to the default case but uses equality rather than +// identity to match values. +// +// // NOTE: this will do a shallow test using Object.keys(..) thus .__proto__ // attributes are ignored... var match = module.match = -function(base, obj){ +function(base, obj, non_strict){ // identity... if(base === obj){ return true } @@ -135,7 +143,10 @@ function(base, obj){ return [k, obj[k]] }) while(o.length > 0){ var [k, v] = o.pop() - if(!base.hasOwnProperty(k) || base[k] !== v){ + if(!base.hasOwnProperty(k) + || (non_strict ? + base[k] != v + : base[k] !== v)){ return false } } return true } @@ -162,6 +173,12 @@ module.STOP = // sources(obj, '__call__', callback) // -> list // -> [] +// +// Get full chain... +// sources(obj) +// sources(obj, callback) +// -> list +// // // callback(obj) // -> STOP @@ -192,11 +209,17 @@ module.STOP = var sources = module.sources = function(obj, name, callback){ + // get full chain... + if(typeof(name) == 'function'){ + callback = name + name = undefined + } var o var res = [] while(obj != null){ //if(obj.hasOwnProperty(name)){ - if(obj.hasOwnProperty(name) + if(name === undefined + || obj.hasOwnProperty(name) || (name == '__call__' && typeof(obj) == 'function')){ // handle callback... o = callback @@ -258,11 +281,13 @@ function(obj, name, callback, props){ var c = typeof(callback) == 'function' && function(obj){ return callback(_get(obj, name), obj) } - return sources(...(c ? - [obj, name, c] - : [obj, name])) - .map(function(obj){ - return _get(obj, name) }) } + return c ? + // NOTE: we do not need to handle the callback return values as + // this is fully done in sources(..) + sources(obj, name, c) + : sources(obj, name) + .map(function(obj){ + return _get(obj, name) }) } // Find the next parent attribute in the prototype chain. diff --git a/package.json b/package.json index c73b9d7..7b5ba50 100755 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "ig-object", - "version": "5.0.6", + "version": "5.0.7", "description": "", "main": "object.js", "scripts": { - "test": "node ./test.js", + "test": "c8 node ./test.js", "cover-lcov": "c8 -r lcov node ./test.js", "cover": "c8 node ./test.js", "prepublishOnly": "npm test" diff --git a/test.js b/test.js index 4fbfe91..cc98611 100755 --- a/test.js +++ b/test.js @@ -85,13 +85,13 @@ var arrayCmp = function(a, b){ var ka = Object.keys(a) var kb = Object.keys(a) return a === b - || ka.length == kb.length - && ka - // keep only non matching stuff... - .filter(function(k){ - return a[k] !== b[k] - && a[k] != a[k] }) - .length == 0 } + || (a.length == b.length + && ka + // keep only non matching stuff... + .filter(function(k){ + return a[k] !== b[k] + && a[k] != a[k] }) + .length == 0) } @@ -407,6 +407,7 @@ module.setups = { Object.entries(objs) .forEach(function([k, o]){ assert(typeof(o) == 'function', 'instance is callable', k) }) + return Object.assign(res, objs) }, // inherit from native constructors... @@ -465,15 +466,24 @@ module.setups = { x: 'c', method: function(){ assert(arrayCmp( - object.values(c, 'x').join(''), + object.values(c, 'x'), ['c', 'a', 'b']), 'reach all values of attr') + assert(arrayCmp( + object.values(c, 'x', function(v, o){ + return v.toUpperCase() }), + ['C', 'A', 'B']), + 'reach all values of attr') assert(arrayCmp( object.sources(c, 'method'), [c, a]), 'reach all values of method') - assert(object.parent(c, 'x') == 'b', 'reach parent attr') - assert(object.parentCall(c.method, this) == 'a', 'reach parent method', 'c') + assert( + object.parent(c, 'x') == 'b', + 'reach parent attr') + assert( + object.parentCall(c.method, this) == 'a', + 'reach parent method', 'c') return 'c' }, }, d: d = { @@ -498,10 +508,16 @@ module.setups = { Z: Z = class extends Y { x = 'z' method(){ + // XXX this is almost the same as for js_prototype... assert(arrayCmp( - object.values(c, 'x').join(''), + object.values(c, 'x'), ['z', 'y', 'x']), 'reach all values of attr (class)') + assert(arrayCmp( + object.values(c, 'x', function(v, o){ + return v.toUpperCase() }), + ['C', 'A', 'B']), + 'reach all values of attr (class)') assert(arrayCmp( object.sources(c, 'method'), [Z.prototype, X.prototype]), @@ -621,15 +637,39 @@ module.tests = { // callables... callables: function(assert, setup){ + // test special case .values(x, '__call__') + var test = function(obj, name){ + var a, b + return assert(arrayCmp( + 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) + .filter(function(o){ + return typeof(o) == 'function' + || o.hasOwnProperty('__call__') }) + .map(function(o){ + return o.hasOwnProperty('__call__') ? + o.__call__.call(obj) + // NOTE: not all callables are instances of Function... + : Reflect.apply(Function.prototype, o, [obj]) })), + 'values of .__call__ of '+ name +': got:', a, 'expected:', b) } + instances(setup) - .forEach(function([k, o]){ + .filter(function([_, o]){ // NOTE: not all callables are instances of Function... - typeof(o) == 'function' - && (o.__non_function ? - assert(!(o instanceof Function), 'non-instanceof Function', k) - : assert(o instanceof Function, 'instanceof Function', k)) - typeof(o) == 'function' - && assert(o(), 'call', k) }) + return typeof(o) == 'function' }) + .forEach(function([k, o]){ + o.__non_function ? + assert(!(o instanceof Function), 'non-instanceof Function', k) + : assert(o instanceof Function, 'instanceof Function', k) + + assert(o(), 'call', k) + + test(o, k) + }) return setup }, }