Skip to content

Commit

Permalink
Fix #3 - adding $merge
Browse files Browse the repository at this point in the history
  • Loading branch information
Yomguithereal committed Feb 2, 2015
1 parent bdc54e5 commit 3e38b5a
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 27 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ cursor.apply(function(currentData) {
});
```

*Merging objects*

```js
cursor.merge({hello: 'world'});
```

#### Events

Whenever an update is committed, events are fired to notify relevant parts of the tree that data was changed so that bound elements, React components, for instance, can update.
Expand Down Expand Up @@ -549,6 +555,7 @@ The available commands are the following and are basically the same as the curso
* `$chain`
* `$push`
* `$unshift`
* `$merge`

*Example*

Expand Down
2 changes: 1 addition & 1 deletion build/baobab.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/baobab.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function Baobab(initialData, opts) {
EventEmitter.call(this);

// Merging defaults
this.options = merge(opts, defaults);
this.options = helpers.shallowMerge(defaults, opts);
this._cloner = this.options.cloningFunction || helpers.deepClone;

// Privates
Expand Down
10 changes: 10 additions & 0 deletions src/cursor.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,16 @@ Cursor.prototype.unshift = function(value) {
return this.update({$unshift: value});
};

Cursor.prototype.merge = function(o) {
if (!types.check(o, 'object'))
throw Error('baobab.Cursor.merge: trying to merge a non-object.');

if (!types.check(this.reference(), 'object'))
throw Error('baobab.Cursor.merge: trying to merge into a non-object.');

this.update({$merge: o});
};

Cursor.prototype.update = function(spec) {
return this._stack(spec);
};
Expand Down
12 changes: 12 additions & 0 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ function arrayOf(o) {
return Array.prototype.slice.call(o);
}

// Shallow merge
function shallowMerge(o1, o2) {
var o = {},
k;

for (k in o1) o[k] = o1[k];
for (k in o2) o[k] = o2[k];

return o;
}

// Shallow clone
function shallowClone(item) {
if (!item || !(item instanceof Object))
Expand Down Expand Up @@ -228,6 +239,7 @@ module.exports = {
arrayOf: arrayOf,
deepClone: deepClone,
shallowClone: shallowClone,
shallowMerge: shallowMerge,
compose: compose,
getIn: getIn,
inherits: inherits,
Expand Down
54 changes: 31 additions & 23 deletions src/merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,30 +40,38 @@ function merge() {

for (i = l - 1; i >= 0; i--) {

// Upper $set/$apply and conflicts
// TODO: Boooo! Ugly...
if (hasOneOf(arguments[i], ['$set', '$apply', '$chain'])) {
if (res.$set && (arguments[i].$apply || arguments[i].$chain)) {
delete res.$set;
res.$apply = arguments[i].$apply || arguments[i].$chain;
}
else if (res.$apply && arguments[i].$set) {
delete res.$apply;
res.$set = arguments[i].$set;
}
else if (arguments[i].$set) {
res.$set = arguments[i].$set;
}
else if (arguments[i].$apply) {
res.$apply = arguments[i].$apply;
}
else if (arguments[i].$chain) {
if (res.$apply)
res.$apply = helpers.compose(res.$apply, arguments[i].$chain);
else
res.$apply = arguments[i].$chain;
}
// Upper $set/$apply... and conflicts
// When solving conflicts, here is the priority to apply:
// -- 1) $set
// -- 2) $merge
// -- 3) $apply
// -- 4) $chain
if (arguments[i].$set) {
delete res.$apply;
delete res.$merge;
res.$set = arguments[i].$set;
continue;
}
else if (arguments[i].$merge) {
delete res.$set;
delete res.$apply;
res.$merge = arguments[i].$merge;
continue;
}
else if (arguments[i].$apply){
delete res.$set;
delete res.$merge;
res.$apply = arguments[i].$apply;
continue;
}
else if (arguments[i].$chain) {
delete res.$set;
delete res.$merge;

if (res.$apply)
res.$apply = helpers.compose(res.$apply, arguments[i].$chain);
else
res.$apply = arguments[i].$chain;
continue;
}

Expand Down
16 changes: 14 additions & 2 deletions src/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
* A handy method to mutate an atom according to the given specification.
* Mostly inspired by http://facebook.github.io/react/docs/update.html
*/
var types = require('./typology.js');
var types = require('./typology.js'),
helpers = require('./helpers.js');

var COMMANDS = {};
[
'$set',
'$push',
'$unshift',
'$apply'
'$apply',
'$merge'
].forEach(function(c) {
COMMANDS[c] = true;
});
Expand Down Expand Up @@ -92,6 +94,16 @@ function update(target, spec, opts) {
log[h] = true;
o[k] = fn.call(null, o[k]);
}
else if ('$merge' in (spec[k] || {})) {
v = spec[k].$merge;

if (!types.check(o[k], 'object'))
throw makeError(path.concat(k), 'using command $merge on a non-object');

// Logging update
log[h] = true;
o[k] = helpers.shallowMerge(o[k], v);
}
else if (opts.shiftReferences &&
('$push' in (spec[k] || {}) ||
'$unshift' in (spec[k] || {}))) {
Expand Down
16 changes: 16 additions & 0 deletions test/suites/cursor.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,5 +366,21 @@ describe('Cursor API', function() {
done();
});
});

it('should be possible to shallow merge two objects.', function(done) {
var baobab = new Baobab({o: {hello: 'world'}, string: 'test'});

assert.throws(function() {
baobab.select('test').merge({hello: 'moto'});
}, /merge/);

var cursor = baobab.select('o');
cursor.merge({hello: 'jarl'});

baobab.on('update', function() {
assert.deepEqual(baobab.get('o'), {hello: 'jarl'});
done();
});
});
});
});
10 changes: 10 additions & 0 deletions test/suites/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ describe('Helpers', function() {
});
});

describe('Shallow merge', function() {

it('should be possible to merge objects shallowly.', function() {
assert.deepEqual(
helpers.shallowMerge({hello: 'world', other: 'mate'}, {hello: 'Jack', one: 'two'}),
{hello: 'Jack', one: 'two', other: 'mate'}
);
});
});

describe('Update API', function() {

it('should be possible to set nested values.', function() {
Expand Down

0 comments on commit 3e38b5a

Please sign in to comment.