From 26d81e8dca7dc872c521e309a14a70a3f84742df Mon Sep 17 00:00:00 2001 From: Michael Hart Date: Wed, 13 Jun 2012 17:14:56 +1000 Subject: [PATCH] Merge objects if necessary when traversing stores on get() --- lib/nconf/provider.js | 33 +++++++++++++++-- test/complete-test.js | 2 +- test/fixtures/merge/file1.json | 8 +++-- .../scripts/nconf-hierarchical-load-merge.js | 18 ++++++++++ test/hierarchy-test.js | 35 ++++++++++++++++++- 5 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/scripts/nconf-hierarchical-load-merge.js diff --git a/lib/nconf/provider.js b/lib/nconf/provider.js index c228894..5bb9823 100644 --- a/lib/nconf/provider.js +++ b/lib/nconf/provider.js @@ -218,7 +218,8 @@ Provider.prototype.get = function (key, callback) { var current = 0, names = Object.keys(this.stores), self = this, - response; + response, + mergeObjs = []; async.whilst(function () { return typeof response === 'undefined' && current < names.length; @@ -233,13 +234,30 @@ Provider.prototype.get = function (key, callback) { } response = value; + + // Merge objects if necessary + if (typeof response === 'object' && !Array.isArray(response)) { + mergeObjs.push(response); + response = undefined; + } + next(); }); } response = store.get(key); + + // Merge objects if necessary + if (typeof response === 'object' && !Array.isArray(response)) { + mergeObjs.push(response); + response = undefined; + } + next(); }, function (err) { + if (!err && mergeObjs.length) { + response = common.merge(mergeObjs.reverse()); + } return err ? callback(err) : callback(null, response); }); }; @@ -475,7 +493,8 @@ Provider.prototype._execute = function (action, syncLength /* [arguments] */) { callback = typeof args[args.length - 1] === 'function' && args.pop(), destructive = ['set', 'clear', 'merge'].indexOf(action) !== -1, self = this, - response; + response, + mergeObjs = []; function runAction (name, next) { var store = self.stores[name]; @@ -505,9 +524,19 @@ Provider.prototype._execute = function (action, syncLength /* [arguments] */) { } response = store[action].apply(store, args); + + // Merge objects if necessary + if (action === 'get' && typeof response === 'object' && !Array.isArray(response)) { + mergeObjs.push(response); + response = undefined; + } } }); + if (mergeObjs.length) { + response = common.merge(mergeObjs.reverse()); + } + return response; } diff --git a/test/complete-test.js b/test/complete-test.js index e547c15..4efeedd 100644 --- a/test/complete-test.js +++ b/test/complete-test.js @@ -50,7 +50,7 @@ vows.describe('nconf').addBatch({ "literal vars": { "are present": function () { Object.keys(data).forEach(function (key) { - assert.equal(nconf.get(key), data[key]); + assert.deepEqual(nconf.get(key), data[key]); }); } }, diff --git a/test/fixtures/merge/file1.json b/test/fixtures/merge/file1.json index 8005a30..b48f5c0 100644 --- a/test/fixtures/merge/file1.json +++ b/test/fixtures/merge/file1.json @@ -7,6 +7,10 @@ "candy": { "something": "file1", "something1": true, - "something2": true + "something2": true, + "something5": { + "first": 1, + "second": 2 + } } -} \ No newline at end of file +} diff --git a/test/fixtures/scripts/nconf-hierarchical-load-merge.js b/test/fixtures/scripts/nconf-hierarchical-load-merge.js new file mode 100644 index 0000000..4945cfd --- /dev/null +++ b/test/fixtures/scripts/nconf-hierarchical-load-merge.js @@ -0,0 +1,18 @@ +/* + * nconf-hierarchical-load-merge.js: Test fixture for loading and merging nested objects across stores. + * + * (C) 2012, Nodejitsu Inc. + * (C) 2012, Michael Hart + * + */ + +var path = require('path'), + nconf = require('../../../lib/nconf'); + +nconf.argv() + .file(path.join(__dirname, '..', 'merge', 'file1.json')); + +process.stdout.write(JSON.stringify({ + apples: nconf.get('apples'), + candy: nconf.get('candy') +})); diff --git a/test/hierarchy-test.js b/test/hierarchy-test.js index e286974..80e11e9 100644 --- a/test/hierarchy-test.js +++ b/test/hierarchy-test.js @@ -75,6 +75,39 @@ vows.describe('nconf/hierarchy').addBatch({ } }); } + }, + "configured with .argv(), .file() and invoked with nested command line options": { + topic: function () { + var script = path.join(__dirname, 'fixtures', 'scripts', 'nconf-hierarchical-load-merge.js'), + argv = ['--candy:something', 'foo', '--candy:something5:second', 'bar'], + that = this, + data = '', + child; + + child = spawn('node', [script].concat(argv)); + + child.stdout.on('data', function (d) { + data += d; + }); + + child.on('exit', function() { + that.callback(null, data); + }); + }, + "should merge nested objects ": function (err, data) { + assert.deepEqual(JSON.parse(data), { + apples: true, + candy: { + something: 'foo', + something1: true, + something2: true, + something5: { + first: 1, + second: 'bar' + } + } + }); + } } } -}).export(module); \ No newline at end of file +}).export(module);