diff --git a/benchmarks/creation.js b/benchmarks/creation.js index d251d9c..f976af7 100644 --- a/benchmarks/creation.js +++ b/benchmarks/creation.js @@ -8,7 +8,7 @@ var B = require('benchmark'), var suite = new B.Suite(), store = new Freezer( initialData ), - mutable = new Freezer( initialData, true ), + mutable = new Freezer( initialData, {mutable: true} ), data = store.getData(), leaf = data[1][0][0][0][0], mutableData = mutable.get(), @@ -33,7 +33,7 @@ suite new Freezer( initialData ); }) .add( 'Freezer mutable creation', function(){ - new Freezer( initialData, true ); + new Freezer( initialData, {mutable: true} ); }) .add( 'Immutable creation', function(){ Immutable.fromJS( initialData ); @@ -75,4 +75,4 @@ suite //console.log( this ); }) .run({ async: true}) -; \ No newline at end of file +; diff --git a/src/freezer.js b/src/freezer.js index 1d16a81..ef897cd 100644 --- a/src/freezer.js +++ b/src/freezer.js @@ -7,8 +7,11 @@ var Utils = require( './utils.js' ), ; //#build -var Freezer = function( initialValue, mutable ) { - var me = this; +var Freezer = function( initialValue, options ) { + var me = this, + mutable = ( options && options.mutable ) || false, + live = ( options && options.live ) || live + ; // Immutable data var frozen; @@ -25,7 +28,7 @@ var Freezer = function( initialValue, mutable ) { freeze = function( obj ){ Object.freeze( obj ); }; // Create the frozen object - frozen = Frozen.freeze( initialValue, notify, freeze ); + frozen = Frozen.freeze( initialValue, notify, freeze, live ); // Listen to its changes immediately var listener = frozen.getListener(); @@ -37,6 +40,9 @@ var Freezer = function( initialValue, mutable ) { if( prevNode != frozen ) return; + if( live ) + return me.trigger( 'update', updated ); + frozen = updated; // Trigger on next tick diff --git a/src/frozen.js b/src/frozen.js index 1d03275..b7649d3 100644 --- a/src/frozen.js +++ b/src/frozen.js @@ -7,7 +7,7 @@ var Utils = require( './utils' ), //#build var Frozen = { - freeze: function( node, notify, freezeFn ){ + freeze: function( node, notify, freezeFn, live ){ if( node && node.__ ){ return node; } @@ -28,14 +28,15 @@ var Frozen = { parents: [], notify: notify, dirty: false, - freezeFn: freezeFn + freezeFn: freezeFn, + live: live || false }}); // Freeze children Utils.each( node, function( child, key ){ cons = child && child.constructor; if( cons == Array || cons == Object ){ - child = me.freeze( child, notify, freezeFn ); + child = me.freeze( child, notify, freezeFn, live ); } if( child && child.__ ){ @@ -78,7 +79,7 @@ var Frozen = { }); } else { - frozen = this.freeze( node, node.__.notify, node.__.freezeFn ); + frozen = this.freeze( node, node.__.notify, node.__.freezeFn, node.__.live ); } return frozen; @@ -121,7 +122,7 @@ var Frozen = { cons = val && val.constructor; if( cons == Array || cons == Object ) - val = me.freeze( val, notify, node.__.freezeFn ); + val = me.freeze( val, notify, node.__.freezeFn, node.__.live ); if( val && val.__ ) me.addParent( val, frozen ); @@ -137,7 +138,7 @@ var Frozen = { cons = val && val.constructor; if( cons == Array || cons == Object ) - val = me.freeze( val, notify, node.__.freezeFn ); + val = me.freeze( val, notify, node.__.freezeFn, node.__.live ); if( val && val.__ ) me.addParent( val, frozen ); @@ -162,7 +163,7 @@ var Frozen = { if( cons == Array || cons == Object ) { - frozen = me.freeze( replacement, __.notify, __.freezeFn ); + frozen = me.freeze( replacement, __.notify, __.freezeFn, __.live ); frozen.__.parents = __.parents; @@ -265,7 +266,7 @@ var Frozen = { con = child && child.constructor; if( con == Array || con == Object ) - child = this.freeze( child, __.notify, __.freezeFn ); + child = this.freeze( child, __.notify, __.freezeFn, __.live ); if( child && child.__ ) this.addParent( child, frozen ); @@ -570,4 +571,4 @@ var Frozen = { }; //#build -module.exports = Frozen; \ No newline at end of file +module.exports = Frozen; diff --git a/tests/hash-spec.js b/tests/hash-spec.js index c1f4b5a..680ddd9 100644 --- a/tests/hash-spec.js +++ b/tests/hash-spec.js @@ -9,7 +9,7 @@ var freezer, data; var example = { a: 1, - b: { z: 0, y: 1, x:[ 'A', 'B'] }, + b: { z: 0, y: 1, x:[ 'A', 'B' ] }, c: [1, 2, {w: 3}], d: null }; @@ -54,6 +54,28 @@ describe("Freezer hash test", function(){ assert.equal( updated.b.x, data.b.x ); }); + it( "Setting a detached element should has no effect on others", function(){ + var b, x = data.b.x; + + x.push(1); + x.push(2); + x.push(3); + + b = freezer.get().b; + b.set({ y:7 }); + b.set({ y:8 }); + b.set({ y:9 }); + + b = freezer.get().b; + b.set({z:10}); + b.set({z:11}); + b.set({z:12}); + + assert.deepEqual( freezer.get().b.x, [ 'A', 'B', 1] ); + assert.equal( freezer.get().b.y, 7 ); + assert.equal( freezer.get().b.z, 10 ); + }); + it( "Remove a hash element", function(){ var chained = data.remove('a'); @@ -171,4 +193,4 @@ describe("Freezer hash test", function(){ assert.deepEqual( data.toJS(), example ); }); -}); \ No newline at end of file +}); diff --git a/tests/listener-spec.js b/tests/listener-spec.js index e9c8456..d7553cd 100644 --- a/tests/listener-spec.js +++ b/tests/listener-spec.js @@ -29,7 +29,9 @@ describe("Freezer events test", function(){ }); it( "Listen to node updates", function( done ){ - var listener = data.b.getListener(); + var listener = data.b.getListener(), + count = 0 + ; listener.on( 'update', function( data ){ try { @@ -45,6 +47,39 @@ describe("Freezer events test", function(){ data.b.set( {c: 3} ); }); + it( "Listen to multiple node updates", function( done ){ + var listener = data.b.getListener(), + count = 0 + ; + + freezer.on( 'update', function( data ){ + assert.equal( data.b.c, 3 ); + done(); + }); + + freezer.get().b.set( {c: 1} ); + freezer.get().b.set( {c: 2} ); + freezer.get().b.set( {c: 3} ); + }); + + it( "Listen to multiple node updates, live mode", function( done ){ + var freezer = new Freezer( example, { live: true } ), + listener = freezer.get().b.getListener(), + count = 0 + ; + + freezer.on( 'update', function( data ){ + if( ++count == 3 ){ + assert.equal( data.b.c, 3 ); + done(); + } + }); + + freezer.get().b.set( {c: 1} ); + freezer.get().b.set( {c: 2} ); + freezer.get().b.set( {c: 3} ); + }); + it( "Listen to root updates", function( done ){ freezer.on( 'update', function(){ @@ -55,6 +90,34 @@ describe("Freezer events test", function(){ data.b.set( {c: 3} ); }); + it( "Listen to multiple root updates", function( done ){ + freezer.on( 'update', function( data ){ + assert.equal( data.b.c, 3 ); + done(); + }); + + freezer.get().b.set( {c: 1} ); + freezer.get().b.set( {c: 2} ); + freezer.get().b.set( {c: 3} ); + }); + + it( "Listen to multiple root updates, live mode", function( done ){ + var freezer = new Freezer( example, { live: true }), + count = 0 + ; + + freezer.on( 'update', function( data ){ + if( ++count == 3 ){ + assert.equal( data.b.c, 3 ); + done(); + } + }); + + freezer.get().b.set( {c: 1} ); + freezer.get().b.set( {c: 2} ); + freezer.get().b.set( {c: 3} ); + }); + it( "Listen to updates adding a duplicate", function( done ){ var listener = data.c.getListener(); @@ -178,4 +241,4 @@ describe("Freezer events test", function(){ freezer.getData().b.set('foo', 'bar'); }); -}); \ No newline at end of file +});