[dist api test] Finished integrating features from reconf and updating associated tests

master
indexzero 2011-08-23 06:38:51 -04:00
parent add8922c04
commit a6533aa7bf
7 changed files with 151 additions and 27 deletions

View File

@ -5,7 +5,8 @@
*
*/
var stores = require('./stores');
var optimist = require('optimist'),
stores = require('./stores');
//
// ### function Provider (options)
@ -14,7 +15,10 @@ var stores = require('./stores');
// for exposing the pluggable storage features of `nconf`.
//
var Provider = exports.Provider = function (options) {
options = options || {};
options = options || {};
this.overrides = options.overrides || null
this.useArgv = options.useArgv || false;
this.store = stores.create(options.type || 'memory', options);
};
@ -50,6 +54,14 @@ Provider.prototype.use = function (type, options) {
// Retrieves the value for the specified key (if any).
//
Provider.prototype.get = function (key, callback) {
if (this.overrides && Object.prototype.hasOwnProperty.call(this.overrides, key)) {
if (callback) {
callback(null, this.overrides[key]);
}
return this.overrides[key];
}
return this.store.get(key, callback);
};
@ -154,4 +166,23 @@ Provider.prototype.save = function (value, callback) {
//
Provider.prototype.reset = function (callback) {
return this.store.reset(callback);
};
};
//
// ### getter @useArgv {boolean}
// Gets a property indicating if we should wrap calls to `.get`
// by checking `optimist.argv`.
//
Provider.prototype.__defineGetter__('useArgv', function () {
return this._useArgv;
});
//
// ### setter @useArgv {boolean}
// Sets a property indicating if we should wrap calls to `.get`
// by checking `optimist.argv`.
//
Provider.prototype.__defineSetter__('useArgv', function (val) {
this._useArgv = val || false;
this.overrides = this.overrides || optimist.argv;
});

View File

@ -25,7 +25,7 @@ var File = exports.File = function (options) {
this.type = 'file';
this.file = options.file;
this.search = options.search || false;
this.dir = options.dir || process.cwd();
this.format = options.format || {
stringify: function (obj) {
return JSON.stringify(obj, null, 2)
@ -144,21 +144,26 @@ File.prototype.loadSync = function () {
};
//
// ### function resolve (base)
// ### function search (base)
// #### @base {string} Base directory (or file) to begin searching for the target file.
// Attempts to find `this.file` by iteratively searching up the
// directory structure
//
File.prototype.resolve = function (base) {
var looking = this.search,
File.prototype.search = function (base) {
var looking = true,
fullpath,
previous,
stats;
base = base || process.cwd();
if (this.file[0] === '/') {
//
// If filename for this instance is a fully qualified path
// (i.e. it starts with a `'/'`) then check if it exists
//
try {
stats = fs.statSync(fs.realpathSync(fullpath));
stats = fs.statSync(fs.realpathSync(this.file));
if (stats.isFile()) {
fullpath = this.file;
looking = false;
@ -186,26 +191,32 @@ File.prototype.resolve = function (base) {
}
while (looking) {
//
// Iteratively look up the directory structure from `base`
//
try {
stats = fs.statSync(fs.realpathSync(fullpath = path.join(base, this.file)));
looking = stats.isDirectory();
}
catch (ex) {
var olddir = dir;
dir = path.dirname(dir);
previous = base;
base = path.dirname(base);
if (olddir === dir) {
if (previous === base) {
//
// If we've reached the top of the directory structure then simply use
// the default file path.
//
try {
var stat = fs.statSync(fs.realpathSync(configPath = path.join(process.env.HOME, filename)));
if(stat.isDirectory()) {
configPath = undefined;
stats = fs.statSync(fs.realpathSync(fullpath = path.join(this.dir, this.file)));
if (stats.isDirectory()) {
fullpath = undefined;
}
}
catch (ex) {
//
// Ignore errors
//
configPath = undefined;
}
looking = false;
@ -213,5 +224,12 @@ File.prototype.resolve = function (base) {
}
}
//
// Set the file for this instance to the fullpath
// that we have found during the search. In the event that
// the search was unsuccessful use the original value for `this.file`.
//
this.file = fullpath || this.file;
return fullpath;
};

View File

@ -10,6 +10,7 @@
"keywords": ["configuration", "key value store", "plugabble"],
"dependencies": {
"async": "0.1.x",
"optimist": "0.2.x",
"pkginfo": "0.2.x"
},
"devDependencies": {

View File

@ -101,4 +101,36 @@ vows.describe('nconf/stores/file').addBatch({
}
}
}
}).addBatch({
"When using the nconf file store": {
"the search() method": {
"when the target file exists higher in the directory tree": {
topic: function () {
var filePath = this.filePath = path.join(process.env.HOME, '.nconf');
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
return new (nconf.stores.File)({
file: '.nconf'
})
},
"should update the file appropriately": function (store) {
store.search();
assert.equal(store.file, this.filePath);
fs.unlinkSync(this.filePath);
}
},
"when the target file doesn't exist higher in the directory tree": {
topic: function () {
var filePath = this.filePath = path.join(__dirname, 'fixtures', 'search-store.json');
return new (nconf.stores.File)({
dir: path.dirname(filePath),
file: 'search-store.json'
})
},
"should update the file appropriately": function (store) {
store.search();
assert.equal(store.file, this.filePath);
}
}
}
}
}).export(module);

View File

@ -0,0 +1,11 @@
/*
* nconf-override.js: Test fixture for using optimist defaults with nconf.
*
* (C) 2011, Charlie Robbins
*
*/
var nconf = require('../../../lib/nconf');
nconf.useArgv = true;
process.stdout.write(nconf.get('something'));

12
test/fixtures/scripts/nconf-override.js vendored Normal file
View File

@ -0,0 +1,12 @@
/*
* nconf-override.js: Test fixture for using optimist defaults with nconf.
*
* (C) 2011, Charlie Robbins
*
*/
var nconf = require('../../../lib/nconf');
var provider = new (nconf.Provider)({ useArgv: true });
process.stdout.write(provider.get('something'));

View File

@ -5,28 +5,47 @@
*
*/
var fs = require('fs'),
var assert = require('assert'),
fs = require('fs'),
path = require('path'),
spawn = require('child_process').spawn,
vows = require('vows'),
assert = require('assert'),
nconf = require('../lib/nconf')
var first = '/path/to/file1',
second = '/path/to/file2';
function assertDefaults (script) {
return {
topic: function () {
spawn('node', [script, '--something', 'foobar'])
.stdout.once('data', this.callback.bind(this, null));
},
"should respond with the value passed into the script": function (_, data) {
assert.equal(data.toString(), 'foobar');
}
}
}
vows.describe('nconf/provider').addBatch({
"When using an instance of nconf.Provier": {
"calling the use() method with the same store type and different options": {
topic: new nconf.Provider().use('file', { file: first }),
"should use a new instance of the store type": function (provider) {
var old = provider.store;
"When using nconf": {
"an instance of 'nconf.Provider'": {
"calling the use() method with the same store type and different options": {
topic: new nconf.Provider().use('file', { file: first }),
"should use a new instance of the store type": function (provider) {
var old = provider.store;
assert.equal(provider.store.file, first);
provider.use('file', { file: second });
assert.equal(provider.store.file, first);
provider.use('file', { file: second });
assert.notStrictEqual(old, provider.store);
assert.equal(provider.store.file, second);
}
assert.notStrictEqual(old, provider.store);
assert.equal(provider.store.file, second);
}
},
"when 'useArgv' is true": assertDefaults(path.join(__dirname, 'fixtures', 'scripts', 'nconf-override.js'))
},
"the default nconf provider": {
"when 'useArgv' is true": assertDefaults(path.join(__dirname, 'fixtures', 'scripts', 'default-override.js'))
}
}
}).export(module);