diff --git a/gun.js b/gun.js index 51ee1e18..347b2c05 100644 --- a/gun.js +++ b/gun.js @@ -8,7 +8,7 @@ ;(function(Util){ // Generic javascript utilities. ;(function(Type){ - Type.fns = Type.fn = {is: function(fn){ return (fn && fn instanceof Function) }} + Type.fns = Type.fn = {is: function(fn){ return (!!fn && fn instanceof Function) }} Type.fn.apply = function(){} Type.bi = {is: function(b){ return (b instanceof Boolean || typeof b == 'boolean') }} Type.num = {is: function(n){ return !Type.list.is(n) && (Infinity === n || n - parseFloat(n) + 1 >= 0) }} @@ -144,6 +144,10 @@ Act.chain.stun = function(){ this.halt = true; } + Act.chain.off = function(){ + this.fn = noop; + } + function noop(){}; function Event(tag, arg, at, t){ var ctx = this, ons = ctx.ons || (ctx.ons = {}), on = ons[tag] || (ons[tag] = {s: []}), act, mem; if(arg instanceof Function){ @@ -152,18 +156,30 @@ return; } if(emit){ emit(tag, arg, on, ctx) } - var i = 0, acts = on.s, l = acts.length, arr = (arg instanceof Array),act; + var i = 0, acts = on.s, l = acts.length, arr = (arg instanceof Array), off, act; for(i; i < l; i++){ act = acts[i]; if(!arr){ act.fn.call(act.at, arg, act); } else { act.fn.apply(act.at, arg); } + if(noop === act.fn){ + off = true; + } if(act.halt){ act.halt = false; break; } } + if(off){ + var still = []; + for(i = 0; i < l; i++){ act = acts[i]; + if(noop !== act.fn){ + still.push(act); + } + } + on.s = still; + } if(at && at instanceof Function){ at(arg, t); } @@ -464,13 +480,21 @@ } Gun.HAM.node = function(gun, node, opt){ if(!node){ return } - var soul = is_node_soul(node); - if(!soul){ return } - var vertex = gun.__.graph[soul]; - if(vertex === node){ return vertex } - vertex = gun.__.graph[soul] = vertex || is_node_ify({}, soul); opt = num_is(opt)? {state: opt} : opt || {}; - var machine = opt.state || gun.__.opt.state(); + if(gun instanceof Gun){ + var soul = is_node_soul(node); + if(!soul){ return } + var vertex = gun.__.graph[soul]; + if(vertex === node){ return vertex } + vertex = gun.__.graph[soul] = vertex || is_node_ify({}, soul); + var machine = opt.state || gun.__.opt.state(); + } else { + var soul = is_node_soul(gun); + if(!soul){ return } + var vertex = gun; + if(vertex === node){ return vertex } + var machine = opt.state; + } obj_map(node._, meta, vertex); if(!is_node(node, map, {node:node,vertex:vertex,machine:machine,opt:opt})){ return } return vertex; @@ -555,15 +579,20 @@ }); }()); - /*Gun.on('put', function(gun, graph, cb, opt){ - Gun.is.graph(graph, function(node, soul){ // TODO: PERF! CACHE! - Gun.on('stream').emit(err, node); + Gun.on('put', function(at){ var to; + Gun.is.graph(at.graph, function(node, soul){ // TODO: PERF! CACHE! + if(!(to = at.gun.__.by[soul])){ return } + to._.on('stream', [null, node]); }); - });*/ + }); ;(function(){ function stream(at){ - at.get(at.err, at.node); + if(at.get){ + at.get(at.err, at.node); + } else { + at.on('chain', at); + } } function got(err, node){ if(err){ Gun.log(err) } @@ -802,7 +831,6 @@ var state = at.put.state; Gun.ify(data, end, { node: function(env, cb){ var eat = env.at; - console.debug(2, 'soul', eat); if(1 === eat.path.length && at.node){ eat.soul = Gun.is.rel(at.node[eat.path[0]]); } @@ -820,28 +848,50 @@ } return; // TODO: BUG! Chain emit?? } + key.call(at, err, env); // TODO: Turn into an event emitter! //console.log("??????????????????", at.lex); at.lex.soul = at.lex.soul || is_node_soul(env.root); at.cache = env.root; Gun.put(Gun.at.copy(at, {graph: env.graph, cb: ack})); // TODO: RESUME EXECUTION CHAIN. } + function key(err, env){ // TODO: Belongs somewhere else! + var at = this; + if(at.put.opt.key){ return } + Gun.is.graph(env.graph, function(node, soul){ + var key = {node: at.gun.__.graph[soul]}, tmp; + if(!Gun.is.node.soul(key.node, 'key')){ return } + //if(!gun.__.by(soul).end){ gun.__.by(soul).end = 1 } + Gun.is.node(key.node, function each(rel, s){ + var n = at.gun.__.graph[s]; + if(n && is_node_soul(n, 'key')){ + is_node(n, each); + return; + } + rel = env.graph[s] = env.graph[s] || Gun.is.node.soul.ify({}, s); + Gun.is.node(node, function(v,f){ + is_node_state_ify(rel, {field: f, value: v, state: is_node_state(node, f) }); + //Gun.is.node.state.ify([rel, node], f, v) + }); + Gun.obj.del(env.graph, soul); + }); + }); + } function ack(err, ok){ var cb; var at = this; if((cb = at.put.any) && cb instanceof Function){ cb.call(at.gun, err, ok); } - console.debug(3, 'put done', at); at.on('chain', at); } Gun.chain.put = function(data, cb, opt){ var gun = this.back? this : this.chain(), at = Gun.at.copy(gun._, {put: {}}), put = at.put; - console.debug(1, 'put', data); //var back = this, gun = back.chain(), at = gun._, put = at.put || (at.put = {}); put.any = cb; put.data = data; put.state = Gun.time.is(); // TODO: BUG! Should use NTS capable stuff. //put.state = opt.state(); + put.opt = opt || {}; /* // START CACHE SHORTCUT var cache, rel, from = back._, soul; @@ -863,34 +913,37 @@ }()); ;(function(){ function key(err, node){ // TODO: Belongs someplace else! + if(!is_node_soul(node, 'key')){ return } var at = this; var pseudo = is_node_ify({}, is_node_soul(node)); - console.log("--------------------------------------------------") is_node(node, function(n, f){ + at.gun.get(f); // TODO: This is an ASYNC call assuming SYNC behavior. n = at.gun.__.graph[f]; - console.log("oh", n); - is_node(n, function(v, f){ - console.log(v, f, is_node_state(n, f)); - is_node_state_ify(pseudo, {field: f, value: v, state: is_node_state(n, f) }) - }); + HAM_node(pseudo, n); }); - console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", pseudo, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); + at.node = pseudo; } - function got(err, node){ - var at = this;// opt = at.opt, cb; - key.call(at, err, node); - at.on('any', [err, at.node]); + function link(cat){ var at = this; + key.call(at, cat.err, cat.node); // TODO: Turn into event emitter! + at.on('any', [cat.err, cat.node]); + at.on('chain', at); + } + function got(err, node){ var at = this; + key.call(at, err, node); // TODO: Turn into event emitter! + at.on('any', [err, node]); + if(err){ at.on('err', err) } + if(node){ at.on('ok', node) } at.on('chain', at); } function cache(by, soul, back){ var gun = by[soul] = back.chain(), at = gun._; at.lex.soul = soul; at.get = got; + //at.on('chain', link, at); return gun; } Gun.chain.get = function(lex, cb, opt){ var gun, back = this, by = back.__.by, tmp; - console.debug(3, 'get', lex, back.__.graph); if(typeof lex === 'string'){ if(!(gun = by[lex])){ gun = cache(by, lex, back); @@ -899,7 +952,6 @@ if(tmp = lex[_soul]){ if(!(gun = by[tmp])){ gun = cache(by, tmp, back); - console.debug(4, 'yipes', gun); } } else if(tmp = lex.soul){ @@ -920,12 +972,10 @@ if(cex.soul === lex.key){ return } at.obj = (1 === is_node_soul(cat.node, 'key'))? obj_copy(cat.node) : obj_put({}, lex.soul, is_rel_ify(lex.soul)); obj_as((at.put = is_node_ify(at.obj, at.key, true))._, 'key', 1); - console.debug(4, 'keying', at, cat, 'save', at.put); - at.gun.__.gun.put(at.put, function(err, ok){ console.debug(5, 'what?', err, ok); at.any.call(this, err, ok)}/*, {chain: opt.chain, key: true, init: true}*/); + at.gun.__.gun.put(at.put, function(err, ok){ console.debug(5, 'what?', err, ok); at.any.call(this, err, ok)}, {/*chain: opt.chain,*/ key: true, init: true}); } Gun.chain.key = function(key, cb, opt){ - console.debug(3, 'key', key); - var gun = this, at = Gun.at.copy(gun._, {key: key, any: cb || function(){} }); + var gun = this, at = Gun.at.copy(gun._, {key: key, any: cb || function(){}, opt: opt }); gun.on('chain', index, at); return gun; } diff --git a/test/mocha/common.js b/test/mocha/common.js index 04fa67f0..7ef005be 100644 --- a/test/mocha/common.js +++ b/test/mocha/common.js @@ -401,54 +401,49 @@ describe('Gun', function(){ }); */ }); - describe('On', function(){ - it('chain', function(){ - var on = Gun.on.create(); - expect(on('foo').emit).to.be.ok(); - expect(on('foo').event).to.be.ok(); - }); + describe.only('On', function(){ it('subscribe', function(done){ - var on = Gun.on.create(); - on('foo', function(a){ + var e = {on: Gun.on}; + e.on('foo', function(a){ done.first = true; expect(a).to.be(1); }); - on('foo').event(function(a){ + e.on('foo', function(a){ expect(a).to.be(1); expect(done.first).to.be.ok(); done(); }); - on('foo').emit(1); + e.on('foo', 1); }); it('unsubscribe', function(done){ - var on = Gun.on.create(); - on('foo', function(a){ - this.off(); + var e = {on: Gun.on}; + e.on('foo', function(a, ev){ + ev.off(); done.first = a; expect(a).to.be(1); }); - on('foo').event(function(a){ + e.on('foo', function(a, ev){ expect(a).to.be(done.second? 2 : 1); expect(done.first).to.be(1); done.second = true; if(a === 2){ setTimeout(function(){ - expect(on('foo').s.ons.foo.length).to.be(1); + expect(e.ons.foo.s.length).to.be(1); done(); }, 10); } }); - on('foo').emit(1); - on('foo').emit(2); + e.on('foo', 1); + e.on('foo', 2); }); - it('stop', function(done){ - var on = Gun.on.create(); - on('foo', function(a){ + it('stun', function(done){ + var e = {on: Gun.on}; + e.on('foo', function(a, ev){ if(2 === a){ done.first2 = true; return; } - this.stop(); + ev.stun(); setTimeout(function(){ expect(done.second).to.not.be.ok(); expect(done.second2).to.be.ok(); @@ -456,31 +451,31 @@ describe('Gun', function(){ done(); },10); }); - on('foo').event(function(a){ + e.on('foo', function(a, ev){ if(2 === a){ done.second2 = true; } else { done.second = true; } }); - on('foo').emit(1); - on('foo').emit(2); + e.on('foo', 1); + e.on('foo', 2); }); - it('go', function(done){ - var on = Gun.on.create(); - on('foo', function(a){ - var go = this.stop(go); + it('resume', function(done){ + var e = {on: Gun.on}; + e.on('foo', function(a, ev){ + var resume = ev.stun(resume); setTimeout(function(){ expect(done.second).to.not.be.ok(); - go(); + resume(); },10); }); - on('foo').event(function(a){ + e.on('foo', function(a){ done.second = true; expect(a).to.be(1); done(); }); - on('foo').emit(1); + e.on('foo', 1); }); it('double go', function(done){ var on = Gun.on.create(); @@ -1299,7 +1294,7 @@ describe('Gun', function(){ }); }); - describe.only('API', function(){ + describe('API', function(){ var gopt = {wire:{put:function(n,cb){cb()},get:function(k,cb){cb()}}}; var gun = Gun(); @@ -1471,20 +1466,16 @@ describe('Gun', function(){ }); it('put node key get', function(done){ - Gun.log.debug = 1; window.gun = gun; console.log("-----------------------"); gun.put({hello: "key"}).key('yes/key', function(err, ok){ - console.log("****************************", err, ok); expect(err).to.not.be.ok(); done.w = 1; if(done.c){ return } if(done.r){ done(); done.c = 1 }; }).get('yes/key', function(err, node){ // CHANGELOG: API 0.3 BREAKING CHANGE FROM err, graph - console.log("2 ****************************", err, node); - console.log('oye', err, node); expect(err).to.not.be.ok(); expect(Gun.is.node.soul(node)).to.be('yes/key'); expect(node.hello).to.be('key'); done.r = 1; if(done.c){ return } if(done.w){ done(); done.c = 1 }; }); - });return; + }); it('put node key gun get', function(done){ gun.put({hello: "a key"}).key('yes/a/key', function(err, ok){ @@ -1498,25 +1489,27 @@ describe('Gun', function(){ done(); done.c = 1; }); }); - + it('gun key', function(){ // Revisit this behavior? try{ gun.key('fail/key') } catch(err){ expect(err).to.be.ok(); } }); - + it('get key no override', function(done){ var gun = Gun(); gun.put({cream: 'pie'}).key('cream/pie').get('cream/pie', function(err, node){ + console.log("********************", err, node); expect(Gun.is.node.soul(node)).to.be('cream/pie'); if(done.c >= 2){ return } if(done.c){ done(); done.c = 2; return; } done.c = 1; }); gun.get('cream/pie').key('pie/cream'); + Gun.log.debug = 1; window.gun = gun; console.log("----------------"); gun.get('pie/cream').put({pie: 'cream'}); }); - + return; it('get key', function(done){ gun.get('yes/key', function(err, node){ expect(err).to.not.be.ok();