Skip to content

Commit

Permalink
Adds parseInstances option.
Browse files Browse the repository at this point in the history
  • Loading branch information
arqex committed Apr 3, 2016
1 parent 2ecdaf8 commit 356394c
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 37 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# Freezer Changelog
###v0.11.0
* Removes console.log calls
* Trigger an event now return the last callback return value that is not `undefined`.
* Now class instances are handled like tree leaves.
* Adds the freezeInstance options to handle class instances as freezer nodes.


###v0.10.0
* Fixes not returning the pivot on non-modifying updates. Thanks @oigewan
* Adds `getEventHub` method.
Expand Down
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,10 @@ var freezer = new Freezer({hi: 'hello'}, {mutable: true, live:true});
| ------------ | ------- | ------- | ----------- |
| **mutable** | boolean | `false` | Once you get used to freezer, you can see that immutability is not necessary if you learn that you shouldn't update the data directly. In that case, disable immutability in the case that you need a small performance boost. |
| **live** | boolean | `false` | With live mode on, freezer triggers the update events just when the changes happen, instead of batching all the changes and triggering the event on the next tick. This is useful if you want freezer to store input field values. |
| **freezeInstances** | boolean | `false` | It's possible to store class instances in freezer. They are handled like strings or numbers, added to the state like non-frozen leaves. Keep in mind that if their internal state changes, freezer won't `trigger` any update event. If you want freezer to handle them as freezer nodes, set 'freezerInstances: true'. They will be frozen and you will be able to update their attributes using freezer methods, but remember that any instance method that update its internal state may fail (the instance is frozen) and wouldn't trigger any `update` event. |

And then, Freezer's API is really simple and only has 2 methods: `get` and `set`. A freezer object also implements the [listener API](#listener-api).



#### get()

Returns a frozen object with the freezer data.
Expand Down Expand Up @@ -259,8 +258,6 @@ console.log( freezer.get() );

Both *Array* and *Object* nodes have a `set` method to update or add elements to the node and a `reset` method to replace the node with other data.

Class instances can be stored in a freezer store. They will be handled like objects but its methods will be preserved. Since the instance will be frozen, instance setter methods could be not working for update the object.

#### set( keyOrObject, value )
Arrays and hashes can update their children using the `set` method. It accepts a hash with the keys and values to update or two arguments: the key and the value.
```js
Expand Down Expand Up @@ -422,7 +419,19 @@ Register a function to be called once when an event occurs. After being called t
#### off( eventName, callback )
Can unregister all callbacks from a listener if the `eventName` parameter is omitted, or all the callbacks for a `eventName` if the `callback` parameter is omitted.
#### trigger( eventName [, param, param, ...] )
Trigger an event on the listener. All the extra parameters will be passed to the registered callbacks.
Trigger an event on the listener. All the extra parameters will be passed to the registered callbacks. `trigger` returns the return value of the latest callback that doesn't return `undefined`.
```
freezer
.on('whatever', function(){
return 'ok';
})
.on('whatever', function(){
// This doesn't return anything
})
;
console.log(freezer.trigger('whatever')); // logs 'ok'
```

### Event hooks
Freezer objects and nodes also emit `beforeAll` and `afterAll` events before and after any other event. Listeners bound to these events also receive the name of the triggered event in the arguments.
Expand Down
37 changes: 22 additions & 15 deletions build/freezer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* freezer-js v0.10.0 (3-3-2016)
/* freezer-js v0.11.0 (3-4-2016)
* https://github.com/arqex/freezer
* By arqex
* License: MIT
Expand Down Expand Up @@ -169,9 +169,12 @@ var Utils = {
return found;
},

isLeaf: function( node ){
var cons = node && node.constructor;
return !cons || cons == String || cons == Number || cons == Boolean;
isLeaf: function( node, freezeInstances ){
var cons;
return !node || !(cons = node.constructor) || (freezeInstances ?
(cons === String || cons === Number || cons === Boolean) :
(cons != Object && cons != Array)
);
}
};

Expand Down Expand Up @@ -340,8 +343,8 @@ var nodeCreator = {
if( cons === Object ){
return Object.create( FrozenObject );
}
// Class instances
else {
console.log('instance');
return Object.create( cons.prototype, objectMethods );
}
}
Expand Down Expand Up @@ -398,7 +401,7 @@ var emitterProto = {
listeners = this._events[ eventName ] || [],
onceListeners = [],
special = specialEvents.indexOf( eventName ) != -1,
i, listener
i, listener, returnValue, lastValue
;

special || this.trigger.apply( this, [BEFOREALL, eventName].concat( args ) );
Expand All @@ -408,14 +411,18 @@ var emitterProto = {
listener = listeners[i];

if( listener.callback )
listener.callback.apply( this, args );
lastValue = listener.callback.apply( this, args );
else {
// If there is not a callback, remove!
listener.once = true;
}

if( listener.once )
onceListeners.push( i );

if( lastValue !== undefined ){
returnValue = lastValue;
}
}

// Remove listeners marked as once
Expand All @@ -425,7 +432,7 @@ var emitterProto = {

special || this.trigger.apply( this, [AFTERALL, eventName].concat( args ) );

return this;
return returnValue;
}
};

Expand All @@ -452,7 +459,7 @@ var Frozen = {

// Freeze children
Utils.each( node, function( child, key ){
if( !Utils.isLeaf( child ) ){
if( !Utils.isLeaf( child, store.freezeInstances ) ){
child = me.freeze( child, store );
}

Expand Down Expand Up @@ -502,7 +509,7 @@ var Frozen = {
return frozen[ key ] = child;
}

if( !Utils.isLeaf( val ) )
if( !Utils.isLeaf( val, store.freezeInstances ) )
val = me.freeze( val, store );

if( val && val.__ )
Expand All @@ -517,7 +524,7 @@ var Frozen = {
for( key in attrs ) {
val = attrs[ key ];

if( !Utils.isLeaf( val ) )
if( !Utils.isLeaf( val, store.freezeInstances ) )
val = me.freeze( val, store );

if( val && val.__ )
Expand All @@ -539,7 +546,7 @@ var Frozen = {
frozen = replacement
;

if( !Utils.isLeaf( replacement ) ) {
if( !Utils.isLeaf( replacement, _.store.freezeInstances ) ) {

frozen = me.freeze( replacement, _.store );
frozen.__.parents = _.parents;
Expand Down Expand Up @@ -630,7 +637,7 @@ var Frozen = {
for (var i = args.length - 1; i >= 2; i--) {
child = args[i];

if( !Utils.isLeaf( child ) )
if( !Utils.isLeaf( child, _.store.freezeInstances ) )
child = this.freeze( child, _.store );

if( child && child.__ )
Expand Down Expand Up @@ -890,7 +897,8 @@ var Freezer = function( initialValue, options ) {
var me = this,
ops = options || {},
store = {
live: ops.live || false
live: ops.live || false,
freezeInstances: ops.freezeInstances || false
}
;

Expand Down Expand Up @@ -978,7 +986,6 @@ var Freezer = function( initialValue, options ) {
return frozen;
},
set: function( node ){
console.log('setting');
frozen.reset( node );
},
getEventHub: function(){
Expand Down
4 changes: 2 additions & 2 deletions build/freezer.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "freezer-js",
"version": "0.10.0",
"version": "0.11.0",
"description": "A tree data structure that is always updated from the root, making easier to think in a reactive way.",
"main": "freezer.js",
"homepage": "https://github.com/arqex/freezer",
Expand Down
4 changes: 2 additions & 2 deletions src/freezer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ var Freezer = function( initialValue, options ) {
var me = this,
ops = options || {},
store = {
live: ops.live || false
live: ops.live || false,
freezeInstances: ops.freezeInstances || false
}
;

Expand Down Expand Up @@ -98,7 +99,6 @@ var Freezer = function( initialValue, options ) {
return frozen;
},
set: function( node ){
console.log('setting');
frozen.reset( node );
},
getEventHub: function(){
Expand Down
10 changes: 5 additions & 5 deletions src/frozen.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var Frozen = {

// Freeze children
Utils.each( node, function( child, key ){
if( !Utils.isLeaf( child ) ){
if( !Utils.isLeaf( child, store.freezeInstances ) ){
child = me.freeze( child, store );
}

Expand Down Expand Up @@ -74,7 +74,7 @@ var Frozen = {
return frozen[ key ] = child;
}

if( !Utils.isLeaf( val ) )
if( !Utils.isLeaf( val, store.freezeInstances ) )
val = me.freeze( val, store );

if( val && val.__ )
Expand All @@ -89,7 +89,7 @@ var Frozen = {
for( key in attrs ) {
val = attrs[ key ];

if( !Utils.isLeaf( val ) )
if( !Utils.isLeaf( val, store.freezeInstances ) )
val = me.freeze( val, store );

if( val && val.__ )
Expand All @@ -111,7 +111,7 @@ var Frozen = {
frozen = replacement
;

if( !Utils.isLeaf( replacement ) ) {
if( !Utils.isLeaf( replacement, _.store.freezeInstances ) ) {

frozen = me.freeze( replacement, _.store );
frozen.__.parents = _.parents;
Expand Down Expand Up @@ -202,7 +202,7 @@ var Frozen = {
for (var i = args.length - 1; i >= 2; i--) {
child = args[i];

if( !Utils.isLeaf( child ) )
if( !Utils.isLeaf( child, _.store.freezeInstances ) )
child = this.freeze( child, _.store );

if( child && child.__ )
Expand Down
2 changes: 1 addition & 1 deletion src/nodeCreator.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ var nodeCreator = {
if( cons === Object ){
return Object.create( FrozenObject );
}
// Class instances
else {
console.log('instance');
return Object.create( cons.prototype, objectMethods );
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,12 @@ var Utils = {
return found;
},

isLeaf: function( node ){
var cons = node && node.constructor;
return !cons || cons == String || cons == Number || cons == Boolean;
isLeaf: function( node, freezeInstances ){
var cons;
return !node || !(cons = node.constructor) || (freezeInstances ?
(cons === String || cons === Number || cons === Boolean) :
(cons != Object && cons != Array)
);
}
};
//#build
Expand Down
21 changes: 18 additions & 3 deletions tests/freezer-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,9 @@ describe("Freezer test", function(){
assert.strictEqual(pivotNode.a.b.c.test, 2);
});

it('Preserve instance methods', function(){
it('freezeInstances: Preserve instance methods', function(){
var MyClass = function(){ console.log('oh my') },
freezer = new Freezer({})
freezer = new Freezer({}, {freezeInstances: true})
;

MyClass.prototype.sayHello = function() { return 'Hello' };
Expand All @@ -405,6 +405,21 @@ describe("Freezer test", function(){
freezer.get().instance.set({a:2});
assert.equal(freezer.get().instance.a, 2);
assert.equal(freezer.get().instance.sayHello(), 'Hello');
})
});

it('Class instances are leaves', function(){
var MyClass = function(){ this.attr = 2; };
MyClass.prototype.sayHello = function() { return 'Hello' };
var instance = new MyClass();


freezer.get().set({instance: instance});
assert.equal( freezer.get().instance, instance );
instance.attr = 4;
assert.equal( freezer.get().instance.attr, 4);
freezer.get().set({a: {attr: 1}});
assert.equal( freezer.get().a.attr, 1 );
assert.equal( freezer.get().instance, instance );
});

});

0 comments on commit 356394c

Please sign in to comment.