diff --git a/examples/example.js b/examples/example.js index 0e0eb09..a885c61 100644 --- a/examples/example.js +++ b/examples/example.js @@ -4,7 +4,9 @@ import { EventEmitter } from 'events' let emitter = new EventEmitter() -let process = new Ready({emitter: emitter}) +// handler: (r)=> console.log('result:',r) + +let process = new Ready({emitter: emitter, verbose:true}) const tObs = new Observable(subscriber => { subscriber.next('on') @@ -17,7 +19,7 @@ const tObs = new Observable(subscriber => { }) const tPromise = new Promise(function(resolve) { - setTimeout(()=>resolve('yes'),3000) + setTimeout(()=>resolve('yes'),1500) }) process.addObserver('e') @@ -26,8 +28,9 @@ process.addObserver('pe',emitter) process.addObserver('obs',tObs) process.addObserver('pr',tPromise) -console.log(process.size) -process.subscribe() +process.subscribe(val => console.log('---------------Ready Changed to :',val)) +// process.subscribe('obs',val => console.log('obs',val)) + emitter.emit('ec',{test:true}) emitter.emit('e','sure') diff --git a/package.json b/package.json index 3b71926..804f7f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@uci-utils/ready", - "version": "0.1.1", + "version": "0.1.2", "description": "A Class to Observe the reduced to boolean combined state of a map of observables", "main": "src/ready.js", "scripts": { @@ -26,6 +26,7 @@ }, "homepage": "https://github.com/uCOMmandIt/uci-utils#readme", "dependencies": { + "@uci-utils/to-boolean": "^0.1.1", "is-observable": "^2.0.0", "p-is-promise": "^3.0.0", "rxjs": "^6.5.4" diff --git a/src/ready.js b/src/ready.js index 3a15ea6..54f286c 100644 --- a/src/ready.js +++ b/src/ready.js @@ -1,11 +1,10 @@ -import { from, fromEvent, combineLatest } from 'rxjs' -import { map, startWith, tap } from 'rxjs/operators' +import { from, fromEvent, combineLatest, Subject } from 'rxjs' +import { map, startWith, tap, pairwise, filter } from 'rxjs/operators' import isObservable from 'is-observable' import isPromise from 'p-is-promise' - -import { createBoolean } from '../../to-boolean' - -const toBool = createBoolean({undefined:true}) +// UCI dependencies +import { createBoolean } from '@uci-utils/to-boolean' +const toBool = createBoolean({undefined:true}) // make default make null event emission cast to TRUE class Ready extends Map { constructor(opts) { @@ -15,8 +14,11 @@ class Ready extends Map { this.condition = opts.condition || ( (ev) => toBool(ev) ) this.subscriptions = new Map() this._state = {} - this._updateObserversList() - this.handler = opts.handler || ( ([r,s]) => {console.log('ready:',r,'states:',s,'\n---------------------------')}) + this.logger = new Subject() + this.log = this.logger.next.bind(this.logger) + if (opts.verbose) this.logger.subscribe(console.log) + this._updateObserversList() // initialize + this.handler = opts.handler || console.log } get state() {return this._state} @@ -34,9 +36,9 @@ class Ready extends Map { if (!obs || !isObservable(obs)) return false this.set(name, obs .pipe( - tap((ev) => console.log(name,'emitted/resolved=>',ev)), + tap(val => this.logger.next(`${name} emitted/resolved the value =>${JSON.stringify(val)}`)), map(condition||this.condition), - tap((b) => console.log('boolean:',b)), + tap(val => this.log(`boolean: ${val}`)), startWith(false), ) ) @@ -69,37 +71,15 @@ class Ready extends Map { _updateObserversList() { this._state = combineLatest(Array.from(this.values())).pipe( - // tap((states)=>console.log('states',states)), - map(states=> { - return [states.reduce((res,state) => {return res && state},true), Array.from(this.keys()).map((name,index) => [name,states[index]])] - }) + tap(states => this.log( Array.from(this.keys()).map((name,index) => [name,states[index]]))), + map( states => states.reduce((res,state) => {return res && state},true)), + pairwise(), + filter( ([p,c]) => (p ^ c)), // only emit on change + map( r => r[1] ) //remove previous ) } -} -// const toBoolean = (cond) => -// pipe( -// map(cond), -// startWith(false), -// ) - -const rTrue=['t','true','y','yes','on','positive','up','enabled','affirmative','yea'] -const rFalse=['f','false','n','no','off','negative','down','disabled','nope'] - -function castBoolean (opts={}) { - return (value => { - if (value===undefined) return opts.undefined - if (value===null) return opts.null - if (!isNaN(Number(value))) return Number(value) <1 ? false :true - if (typeof value==='string') { - value = value.trim() - value = value.toLowerCase() - if ((opts.rTrue || rTrue).includes(value)) return true - if ((opts.rFalse || rFalse).includes(value)) return false - } - return !!value - }) -} +} // end class export default Ready export { Ready }