/*
+ nconf.js
nconf.js /*
* nconf.js: Top-level include for the nconf module
*
* (C) 2011, Charlie Robbins
@@ -9,19 +9,12 @@
async = require ( 'async' ),
common = require ( './nconf/common' ),
Provider = require ( './nconf/provider' ). Provider ,
- nconf = module . exports = Object . create ( Provider . prototype ); Use the memory engine by default.
Expose the version from the package.json using pkginfo
.
require ( 'pkginfo' )( module , 'version' ); function path (key)
-
-@key {string} The ':' delimited key to split
-
-Returns a fully-qualified path to a nested nconf key.
nconf . path = function ( key ) {
- return key . split ( ':' );
-}; function key (arguments)
-
-Returns a :
joined string from the arguments
.
nconf . key = function () {
- return Array . prototype . slice . call ( arguments ). join ( ':' );
-}; Expose the various components included with nconf
nconf . loadFiles = common . loadFiles ;
-nconf . formats = require ( './nconf/formats' );
-nconf . stores = require ( './nconf/stores' );
-nconf . Provider = Provider ;
+ nconf = module . exports = new Provider (); Expose the version from the package.json using pkginfo
.
require ( 'pkginfo' )( module , 'version' ); Expose the various components included with nconf
nconf . key = common . key ;
+nconf . path = common . path ;
+nconf . loadFiles = common . loadFiles ;
+nconf . loadFilesSync = common . loadFilesSync ;
+nconf . formats = require ( './nconf/formats' );
+nconf . stores = require ( './nconf/stores' );
+nconf . Provider = Provider ;
\ No newline at end of file
diff --git a/docs/nconf/common.html b/docs/nconf/common.html
index 899ba70..5c359ce 100644
--- a/docs/nconf/common.html
+++ b/docs/nconf/common.html
@@ -1,4 +1,4 @@
- common.js
common.js /*
+ common.js
common.js /*
* utils.js: Utility functions for the nconf module.
*
* (C) 2011, Charlie Robbins
@@ -8,9 +8,19 @@
var fs = require ( 'fs' ),
async = require ( 'async' ),
formats = require ( './formats' ),
- stores = require ( './stores' );
+ Memory = require ( './stores/Memory' ). Memory ;
-var common = exports ; function loadFiles (files)
+var common = exports ; function path (key)
+
+@key {string} The ':' delimited key to split
+
+Returns a fully-qualified path to a nested nconf key.
common . path = function ( key ) {
+ return key . split ( ':' );
+}; function key (arguments)
+
+Returns a :
joined string from the arguments
.
common . key = function () {
+ return Array . prototype . slice . call ( arguments ). join ( ':' );
+}; function loadFiles (files, callback)
@files {Object|Array} List of files (or settings object) to load.
@@ -21,28 +31,55 @@
return callback ( null , {});
}
- var options = Array . isArray ( files ) ? { files : files } : files ,
- store = new stores . Memory (); Set the default JSON format if not already
+ var options = Array . isArray ( files ) ? { files : files } : files ;
Set the default JSON format if not already
specified
options . format = options . format || formats . json ;
- function loadFile ( file , next ) {
+ function parseFile ( file , next ) {
fs . readFile ( file , function ( err , data ) {
- if ( err ) {
- return next ( err );
- }
-
- data = options . format . parse ( data . toString ());
- Object . keys ( data ). forEach ( function ( key ) {
- store . merge ( key , data [ key ]);
- });
-
- next ();
+ return ! err
+ ? next ( null , options . format . parse ( data . toString ()))
+ : next ( err );
});
}
- async . forEach ( files , loadFile , function ( err ) {
- return err ? callback ( err ) : callback ( null , store . store );
+ async . map ( files , parseFile , function ( err , objs ) {
+ return err ? callback ( err ) : callback ( null , common . merge ( objs ));
});
+}; function loadFilesSync (files)
+
+@files {Object|Array} List of files (or settings object) to load.
+
+Loads all the data in the specified files
synchronously.
common . loadFilesSync = function ( files ) {
+ if ( ! files ) {
+ return ;
+ } Set the default JSON format if not already
+specified
var options = Array . isArray ( files ) ? { files : files } : files ;
+ options . format = options . format || formats . json ;
+
+ return common . merge ( files . map ( function ( file ) {
+ return options . format . parse ( fs . readFileSync ( file , 'utf8' ));
+ }));
+}; function merge (objs)
+
+@objs {Array} Array of object literals to merge
+
+Merges the specified objs
using a temporary instance
+of stores.Memory
.
common . merge = function ( objs ) {
+ var store = new Memory ();
+
+ objs . forEach ( function ( obj ) {
+ Object . keys ( obj ). forEach ( function ( key ) {
+ store . merge ( key , obj [ key ]);
+ });
+ });
+
+ return store . store ;
+}; function capitalize (str)
+
+@str {string} String to capitalize
+
+Capitalizes the specified str
.
common . capitalize = function ( str ) {
+ return str && str [ 0 ]. toUpperCase () + str . slice ( 1 );
};
\ No newline at end of file
diff --git a/docs/nconf/formats.html b/docs/nconf/formats.html
index 0766925..a2ab2f5 100644
--- a/docs/nconf/formats.html
+++ b/docs/nconf/formats.html
@@ -1,4 +1,4 @@
- formats.js
formats.js /*
+ formats.js
formats.js /*
* formats.js: Default formats supported by nconf
*
* (C) 2011, Charlie Robbins
diff --git a/docs/nconf/provider.html b/docs/nconf/provider.html
index 1b50174..66c6718 100644
--- a/docs/nconf/provider.html
+++ b/docs/nconf/provider.html
@@ -1,4 +1,4 @@
- provider.js
provider.js /*
+ provider.js
provider.js /*
* provider.js: Abstraction providing an interface into pluggable configuration storage.
*
* (C) 2011, Charlie Robbins
@@ -6,7 +6,6 @@
*/
var async = require ( 'async' ),
- optimist = require ( 'optimist' ),
common = require ( './common' ),
stores = require ( './stores' ); function Provider (options)
@@ -14,51 +13,161 @@
Constructor function for the Provider object responsible
for exposing the pluggable storage features of nconf
.
var Provider = exports . Provider = function ( options ) {
- options = options || {};
- this . overrides = options . overrides || null
- this . useArgv = options . useArgv || false ;
-
- this . store = stores . create ( options . type || 'memory' , options );
-}; function use (type, options)
+ var self = this ;
+ Setup default options for working with stores
,
+overrides
, process.env
and process.argv
.
options = options || {};
+ this . _overrides = options . overrides || null ;
+ this . _argv = options . argv || false ;
+ this . _env = options . env || false ;
+ this . _reserved = Object . keys ( Provider . prototype );
+ this . _stores = [];
+ Add the default system
store for working with
+overrides
, process.env
, process.argv
and
+a simple in-memory objects.
this . add ( 'system' , options );
+
+ if ( options . type ) {
+ this . add ( options . type , options );
+ }
+ else if ( options . store ) {
+ this . add ( options . store . name || options . store . type , options . store );
+ }
+ else if ( options . stores ) {
+ Object . keys ( options . stores ). forEach ( function ( store ) {
+ self . add ( store . name || store . type , store );
+ });
+ }
+}; function use (name, options)
@type {string} Type of the nconf store to use.
@options {Object} Options for the store instance.
-Sets the active this.store
to a new instance of the
-specified type
.
Provider . prototype . use = function ( type , options ) {
- var self = this ;
- options = options || {};
+Adds (or replaces) a new store with the specified name
+and options
. If options.type
is not set, then name
+will be used instead:
- function sameOptions () {
+provider.use('file');
+ provider.use('file', { type: 'file', filename: '/path/to/userconf' })
Provider . prototype . use = function ( name , options ) {
+ if ( name === 'system' ) {
+ return ;
+ }
+ else if ( this . _reserved . indexOf ( name ) !== - 1 ) {
+ throw new Error ( 'Cannot use reserved name: ' + name );
+ }
+
+ options = options || {};
+ var type = options . type || name ;
+
+ function sameOptions ( store ) {
return Object . keys ( options ). every ( function ( key ) {
- return options [ key ] === self . store [ key ];
+ return options [ key ] === store [ key ];
});
}
- if ( ! this . store || type . toLowerCase () !== this . store . type
- || ! sameOptions ()) {
- this . store = stores . create ( type , options );
+ var store = this [ name ],
+ update = store && ! sameOptions ( store );
+
+ if ( ! store || update ) {
+ if ( update ) {
+ this . remove ( name );
+ }
+
+ this . add ( name , options );
}
return this ;
-}; function get (key, callback)
+}; function add (name, options)
+
+@name {string} Name of the store to add to this instance
+
+@options {Object} Options for the store to create
+
+Adds a new store with the specified name
and options
. If options.type
+is not set, then name
will be used instead:
+
+provider.add('memory');
+ provider.add('userconf', { type: 'file', filename: '/path/to/userconf' })
Provider . prototype . add = function ( name , options ) {
+ if ( this . _reserved . indexOf ( name ) !== - 1 ) {
+ throw new Error ( 'Cannot use reserved name: ' + name );
+ }
+
+ options = options || {};
+ var type = options . type || name ;
+
+ if ( Object . keys ( stores ). indexOf ( common . capitalize ( type )) === - 1 ) {
+ throw new Error ( 'Cannot add store with unknown type: ' + type );
+ }
+
+ this [ name ] = this . create ( type , options );
+ this . _stores . push ( name );
+
+ if ( this [ name ]. loadSync ) {
+ this [ name ]. loadSync ();
+ }
+}; function remove (name)
+
+@name {string} Name of the store to remove from this instance
+
+Removes a store with the specified name
from this instance. Users
+are allowed to pass in a type argument (e.g. memory
) as name if
+this was used in the call to .add()
.
Provider . prototype . remove = function ( name ) {
+ if ( this . _reserved . indexOf ( name ) !== - 1 ) {
+ throw new Error ( 'Cannot use reserved name: ' + name );
+ }
+ else if ( ! this [ name ]) {
+ throw new Error ( 'Cannot remove store that does not exist: ' + name );
+ }
+
+ delete this [ name ];
+ this . _stores . splice ( this . _stores . indexOf ( name ), 1 );
+}; function create (type, options)
+
+@type {string} Type of the nconf store to use.
+
+@options {Object} Options for the store instance.
+
+Creates a store of the specified type
using the
+specified options
.
Provider . prototype . create = function ( type , options ) {
+ return new stores [ common . capitalize ( type . toLowerCase ())]( options );
+}; function get (key, callback)
@key {string} Key to retrieve for this instance.
@callback {function} Optional Continuation to respond to when complete.
-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 ]);
+Retrieves the value for the specified key (if any).
Provider . prototype . get = function ( key , callback ) { If there is no callback we can short-circuit into the default
+logic for traversing stores.
if ( ! callback ) {
+ return this . _execute ( 'get' , 1 , key , callback );
+ }
+ Otherwise the asynchronous, hierarchical get
is
+slightly more complicated because we do not need to traverse
+the entire set of stores, but up until there is a defined value.
var current = 0 ,
+ self = this ,
+ response ;
+
+ async . whilst ( function () {
+ return typeof response === 'undefined' && current < self . _stores . length ;
+ }, function ( next ) {
+ var store = self [ self . _stores [ current ]];
+ current ++ ;
+
+ if ( store . get . length >= 2 ) {
+ return store . get ( key , function ( err , value ) {
+ if ( err ) {
+ return next ( err );
+ }
+
+ response = value ;
+ next ();
+ });
}
- return this . overrides [ key ];
- }
-
- return this . _execute ( 'get' , 1 , key , callback );
-}; function set (key, value, callback)
+ response = store . get ( key );
+ next ();
+ }, function ( err ) {
+ return err ? callback ( err ) : callback ( null , response );
+ });
+}; function set (key, value, callback)
@key {string} Key to set in this instance
@@ -68,7 +177,21 @@ specified type
.
Sets the value
for the specified key
in this instance.
Provider . prototype . set = function ( key , value , callback ) {
return this . _execute ( 'set' , 2 , key , value , callback );
-}; function merge ([key,] value [, callback])
+}; function reset (callback)
+
+@callback {function} Optional Continuation to respond to when complete.
+
+Clears all keys associated with this instance.
Provider . prototype . reset = function ( callback ) {
+ return this . _execute ( 'reset' , 0 , callback );
+}; function clear (key, callback)
+
+@key {string} Key to remove from this instance
+
+@callback {function} Optional Continuation to respond to when complete.
+
+Removes the value for the specified key
from this instance.
Provider . prototype . clear = function ( key , callback ) {
+ return this . _execute ( 'clear' , 1 , key , callback );
+}; function merge ([key,] value [, callback])
@key {string} Key to merge the value into
@@ -101,43 +224,44 @@ specified type
.
}
return this . _execute ( 'merge' , 2 , key , value , callback );
-}; function mergeFiles (files, callback)
-
-@files {Object|Array} List of files (or settings object) to load.
+}; function load (callback)
@callback {function} Continuation to respond to when complete.
-Merges all key:value
pairs in the files
supplied into the
-store that is managed by this provider instance.
Provider . prototype . mergeFiles = function ( files , callback ) {
+Responds with an Object representing all keys associated in this instance.
Provider . prototype . load = function ( callback ) {
var self = this ;
- common . loadFiles ( files , function ( err , merged ) {
- return ! err
- ? self . merge ( merged , callback )
- : onError ( err );
- });
-}; function clear (key, callback)
-
-@key {string} Key to remove from this instance
-
-@callback {function} Optional Continuation to respond to when complete.
-
-Removes the value for the specified key
from this instance.
Provider . prototype . clear = function ( key , callback ) {
- return this . _execute ( 'clear' , 1 , key , callback );
-}; function load (callback)
-
-@callback {function} Continuation to respond to when complete.
-
-Responds with an Object representing all keys associated in this instance.
Provider . prototype . load = function ( callback ) { If we don't have a callback and the current
-store is capable of loading synchronously
-then do so.
if ( ! callback && this . store . loadSync ) {
- return this . store . loadSync ();
+ function loadStoreSync ( name ) {
+ var store = self [ name ];
+
+ if ( ! store . loadSync ) {
+ throw new Error ( 'nconf store ' + store . type + ' has no loadSync() method' );
+ }
+
+ return store . loadSync ();
}
- return ! this . store . load
- ? onError ( new Error ( 'nconf store ' + this . store . type + ' has no load() method' ), callback )
- : this . store . load ( callback );
-}; function save (value, callback)
+ function loadStore ( name , next ) {
+ var store = self [ name ];
+
+ if ( ! store . load && ! store . loadSync ) {
+ return next ( new Error ( 'nconf store ' + store . type + ' has no load() method' ));
+ }
+
+ return store . loadSync
+ ? next ( null , store . loadSync ())
+ : store . load ( next );
+ }
+ If we don't have a callback and the current
+store is capable of loading synchronously
+then do so.
if ( ! callback ) {
+ return common . merge ( this . _stores . map ( loadStoreSync ));
+ }
+
+ async . map ( this . _stores , loadStore , function ( err , objs ) {
+ return err ? callback ( err ) : callback ( null , common . merge ( objs ));
+ });
+}; function save (value, callback)
@value {Object} Optional Config object to set for this instance
@@ -145,26 +269,44 @@ then do so. Removes any existing configuration settings that may exist in this
instance and then adds all key-value pairs in value
. Provider . prototype . save = function ( value , callback ) {
- if ( ! callback ) {
+ if ( ! callback && typeof value === 'function' ) {
callback = value ;
value = null ;
- If we still don't have a callback and the
-current store is capable of saving synchronously
-then do so.
if ( ! callback && this . store . saveSync ) {
- return this . store . saveSync ();
- }
}
- return ! this . store . save
- ? onError ( new Error ( 'nconf store ' + this . store . type + ' has no save() method' ), callback )
- : this . store . save ( value , callback );
-}; function reset (callback)
-
-@callback {function} Optional Continuation to respond to when complete.
-
-Clears all keys associated with this instance.
Provider . prototype . reset = function ( callback ) {
- return this . _execute ( 'reset' , 0 , callback );
-}; @private function _execute (action, syncLength, [arguments])
+ var self = this ;
+
+ function saveStoreSync ( name ) {
+ var store = self [ name ];
+
+ if ( ! store . saveSync ) {
+ throw new Error ( 'nconf store ' + store . type + ' has no saveSync() method' );
+ }
+
+ return store . saveSync ();
+ }
+
+ function saveStore ( name , next ) {
+ var store = self [ name ];
+
+ if ( ! store . save && ! store . saveSync ) {
+ return next ( new Error ( 'nconf store ' + store . type + ' has no save() method' ));
+ }
+
+ return store . saveSync
+ ? next ( null , store . saveSync ())
+ : store . save ( next );
+ }
+ If we don't have a callback and the current
+store is capable of saving synchronously
+then do so.
if ( ! callback ) {
+ return common . merge ( this . _stores . map ( saveStoreSync ));
+ }
+
+ async . map ( this . _stores , saveStore , function ( err , objs ) {
+ return err ? callback ( err ) : callback ();
+ });
+}; @private function _execute (action, syncLength, [arguments])
@action {string} Action to execute on this.store
.
@@ -172,41 +314,65 @@ then do so. @arguments {Array} Arguments array to apply to the action
-Executes the specified action
on this.store
, ensuring a callback supplied
+
Executes the specified action
on all stores for this instance, ensuring a callback supplied
to a synchronous store function is still invoked.
Provider . prototype . _execute = function ( action , syncLength /* [arguments] */ ) {
var args = Array . prototype . slice . call ( arguments , 2 ),
- callback ,
+ callback = typeof args [ args . length - 1 ] === 'function' && args . pop (),
+ self = this ,
response ;
-
- if ( this . store [ action ]. length > syncLength ) {
- return this . store [ action ]. apply ( this . store , args );
- }
- callback = typeof args [ args . length - 1 ] === 'function' && args . pop ();
- response = this . store [ action ]. apply ( this . store , args );
+ function runAction ( name , next ) {
+ var store = self [ name ]
+
+ return store [ action ]. length > syncLength
+ ? store [ action ]. apply ( store , args . concat ( next ))
+ : next ( null , store [ action ]. apply ( store , args ));
+ }
if ( callback ) {
- callback ( null , response );
+ return async . forEach ( self . _stores , runAction , function ( err ) {
+ return err ? callback ( err ) : callback ();
+ });
}
-
+
+ this . _stores . forEach ( function ( name ) {
+ var store = self [ name ];
+ response = store [ action ]. apply ( store , args );
+ });
+
return response ;
-} getter @useArgv {boolean}
+} @argv {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}
+Gets or sets a property representing overrides which supercede all
+other values for this instance.
Provider . prototype . __defineSetter__ ( 'overrides' , function ( val ) { updateSystem . call ( this , 'overrides' , val ) });
+Provider . prototype . __defineGetter__ ( 'overrides' , function () { return this . _argv }); @argv {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 ;
-}); Throw the err
if a callback is not supplied
function onError ( err , callback ) {
+Gets or sets a property indicating if we should wrap calls to .get
+by checking optimist.argv
. Can be a boolean or the pass-thru
+options for optimist
.
Provider . prototype . __defineSetter__ ( 'argv' , function ( val ) { updateSystem . call ( this , 'argv' , val ) });
+Provider . prototype . __defineGetter__ ( 'argv' , function () { return this . _argv }); @env {boolean}
+
+Gets or sets a property indicating if we should wrap calls to .get
+by checking process.env
. Can be a boolean or an Array of
+environment variables to extract.
Provider . prototype . __defineSetter__ ( 'env' , function ( val ) { updateSystem . call ( this , 'env' , val ) });
+Provider . prototype . __defineGetter__ ( 'env' , function () { return this . _env }); Throw the err
if a callback is not supplied
function onError ( err , callback ) {
if ( callback ) {
return callback ( err );
}
throw err ;
+} Helper function for working with the
+default system
store for providers.
function updateSystem ( prop , value ) {
+ var system = this [ 'system' ];
+
+ if ( system [ prop ] === value ) {
+ return ;
+ }
+
+ value = value || false ;
+ this [ '_' + prop ] = value ;
+ system [ prop ] = value ;
+ system . loadSync ();
}
\ No newline at end of file
diff --git a/docs/nconf/stores.html b/docs/nconf/stores.html
index 34eb214..d799966 100644
--- a/docs/nconf/stores.html
+++ b/docs/nconf/stores.html
@@ -1,4 +1,4 @@
- stores.js
stores.js /*
+ stores.js
stores.js /*
* stores.js: Top-level include for all nconf stores
*
* (C) 2011, Charlie Robbins
@@ -6,26 +6,14 @@
*/
var fs = require ( 'fs' ),
- stores = exports ;
-
-function capitalize ( str ) {
- return str && str [ 0 ]. toUpperCase () + str . slice ( 1 );
-}; Setup all stores as lazy-loaded getters.
fs . readdirSync ( __dirname + '/stores' ). forEach ( function ( file ) {
+ common = require ( './common' ),
+ stores = exports ; Setup all stores as lazy-loaded getters.
fs . readdirSync ( __dirname + '/stores' ). forEach ( function ( file ) {
var store = file . replace ( '.js' , '' ),
- name = capitalize ( store );
+ name = common . capitalize ( store );
stores . __defineGetter__ ( name , function () {
return require ( './stores/' + store )[ name ];
});
-}); function create (type, options)
-
-@type {string} Type of the nconf store to use.
-
-@options {Object} Options for the store instance.
-
-Creates a store of the specified type
using the
-specified options
.
stores . create = function ( type , options ) {
- return new stores [ capitalize ( type . toLowerCase ())]( options );
-};
+});
\ No newline at end of file
diff --git a/docs/nconf/stores/file.html b/docs/nconf/stores/file.html
index 5c38659..7a00765 100644
--- a/docs/nconf/stores/file.html
+++ b/docs/nconf/stores/file.html
@@ -1,4 +1,4 @@
- file.js
file.js /*
+ file.js
file.js /*
* file.js: Simple file storage engine for nconf files
*
* (C) 2011, Charlie Robbins
@@ -16,9 +16,9 @@
Constructor function for the File nconf store, a simple abstraction
around the Memory store that can persist configuration to disk.
var File = exports . File = function ( options ) {
- if ( ! options . file ) {
+ if ( ! options || ! options . file ) {
throw new Error ( 'Missing required option `files`' );
- }
+ }
Memory . call ( this , options );
@@ -97,8 +97,8 @@ using the format specified by this.format
synchronously.
data = {};
}
else { Else, the path exists, read it from disk
try {
- data = fs . readFileSync ( this . file , 'utf8' );
- this . store = this . format . parse ( data );
+ data = this . format . parse ( fs . readFileSync ( this . file , 'utf8' ));
+ this . store = data ;
}
catch ( ex ) {
throw new Error ( "Error parsing your JSON configuration file." )
diff --git a/docs/nconf/stores/memory.html b/docs/nconf/stores/memory.html
index 8994c70..8867394 100644
--- a/docs/nconf/stores/memory.html
+++ b/docs/nconf/stores/memory.html
@@ -1,11 +1,11 @@
- memory.js
memory.js /*
+ memory.js
memory.js /*
* memory.js: Simple memory storage engine for nconf configuration(s)
*
* (C) 2011, Charlie Robbins
*
*/
-var nconf = require ( '../../nconf' ); function Memory (options)
+var common = require ( '../common' ); function Memory (options)
@options {Object} Options for this instance
@@ -13,17 +13,23 @@
a nested json structure based on key delimiters :
.
e.g. my:nested:key
==> { my: { nested: { key: } } }
var Memory = exports . Memory = function ( options ) {
- options = options || {};
- this . type = 'memory' ;
- this . store = {};
- this . mtimes = {};
+ options = options || {};
+ this . type = 'memory' ;
+ this . store = {};
+ this . mtimes = {};
+ this . readOnly = false ;
+ this . loadFrom = options . loadFrom || null ;
+
+ if ( this . loadFrom ) {
+ this . store = common . loadFilesSync ( this . loadFrom );
+ }
}; function get (key)
@key {string} Key to retrieve for this instance.
Retrieves the value for the specified key (if any).
Memory . prototype . get = function ( key ) {
var target = this . store ,
- path = nconf . path ( key ); Scope into the object to get the appropriate nested context
while ( path . length > 0 ) {
+ path = common . path ( key ); Scope into the object to get the appropriate nested context
while ( path . length > 0 ) {
key = path . shift ();
if ( ! ( target && key in target )) {
return ;
@@ -41,8 +47,12 @@ a nested json structure based on key delimiters :
.
@value {literal|Object} Value for the specified key
Sets the value
for the specified key
in this instance.
Memory . prototype . set = function ( key , value ) {
+ if ( this . readOnly ) {
+ return false ;
+ }
+
var target = this . store ,
- path = nconf . path ( key );
+ path = common . path ( key );
Update the mtime
(modified time) of the key
this . mtimes [ key ] = Date . now ();
Scope into the object to get the appropriate nested context
while ( path . length > 1 ) {
key = path . shift ();
@@ -60,8 +70,12 @@ a nested json structure based on key delimiters :
.
@key {string} Key to remove from this instance
Removes the value for the specified key
from this instance.
Memory . prototype . clear = function ( key ) {
+ if ( this . readOnly ) {
+ return false ;
+ }
+
var target = this . store ,
- path = nconf . path ( key );
+ path = common . path ( key );
Remove the key from the set of mtimes
(modified times)
Scope into the object to get the appropriate nested context
while ( path . length > 1 ) {
key = path . shift ();
@@ -82,14 +96,18 @@ a nested json structure based on key delimiters :
.
Merges the properties in value
into the existing object value
at key
. If the existing value key
is not an Object, it will be
-completely overwritten.
Memory . prototype . merge = function ( key , value ) { If the key is not an Object
or is an Array
,
+completely overwritten.
Memory . prototype . merge = function ( key , value ) {
+ if ( this . readOnly ) {
+ return false ;
+ }
+ If the key is not an Object
or is an Array
,
then simply set it. Merging is for Objects.
if ( typeof value !== 'object' || Array . isArray ( value )) {
return this . set ( key , value );
}
var self = this ,
target = this . store ,
- path = nconf . path ( key ),
+ path = common . path ( key ),
fullKey = key ;
Update the mtime
(modified time) of the key
this . mtimes [ key ] = Date . now ();
Scope into the object to get the appropriate nested context
while ( path . length > 1 ) {
@@ -113,6 +131,10 @@ is an Object.
}; function reset (callback)
Clears all keys associated with this instance.
Memory . prototype . reset = function () {
+ if ( this . readOnly ) {
+ return false ;
+ }
+
this . mtimes = {};
this . store = {};
return true ;
diff --git a/docs/nconf/stores/redis.html b/docs/nconf/stores/redis.html
deleted file mode 100644
index b86fdbb..0000000
--- a/docs/nconf/stores/redis.html
+++ /dev/null
@@ -1,308 +0,0 @@
- redis.js
redis.js /*
- * redis.js: Redis storage engine for nconf configuration(s)
- *
- * (C) 2011, Charlie Robbins
- *
- */
-
-var async = require ( 'async' ),
- redis = require ( 'redis' ),
- nconf = require ( '../../nconf' ),
- Memory = require ( './memory' ). Memory ; function Redis (options)
-
-@options {Object} Options for this instance
-
-Constructor function for the Redis nconf store which maintains
-a nested Redis key structure based on key delimiters :
.
-
-e.g.
- my:nested:key, 'value'
- namespace:keys ==> ['my']
- namespace:nested:keys ==> ['key']
- namespace:nested:key ==> 'value'
var Redis = exports . Redis = function ( options ) {
- options = options || {};
- this . type = 'redis' ;
- this . namespace = options . namespace || 'nconf' ;
- this . host = options . host || 'localhost' ;
- this . port = options . port || 6379 ;
- this . ttl = options . ttl || 60 * 60 * 1000 ;
- this . cache = new Memory ();
- this . redis = redis . createClient ( options . port , options . host );
-
- if ( options . auth ) {
- this . redis . auth ( options . auth );
- }
- Suppress errors from the Redis client
this . redis . on ( 'error' , function ( err ) {
- console . dir ( err );
- });
-}; function get (key, callback)
-
-@key {string} Key to retrieve for this instance.
-
-@callback {function} Continuation to respond to when complete.
-
-Retrieves the value for the specified key (if any).
Redis . prototype . get = function ( key , callback ) {
- var self = this ,
- result = {},
- now = Date . now (),
- mtime = this . cache . mtimes [ key ],
- fullKey = nconf . key ( this . namespace , key );
- Set the callback if not provided for "fire and forget"
callback = callback || function () { };
- If the key exists in the cache and the ttl is less than
-the value set for this instance, return from the cache.
if ( mtime && now - mtime < this . ttl ) {
- return callback ( null , this . cache . get ( key ));
- }
- Get the set of all children keys for the key
supplied. If the value
-to be returned is an Object, this list will not be empty.
this . redis . smembers ( nconf . key ( fullKey , 'keys' ), function ( err , keys ) {
- function addValue ( source , next ) {
- self . get ( nconf . key ( key , source ), function ( err , value ) {
- if ( err ) {
- return next ( err );
- }
-
- result [ source ] = value ;
- next ();
- });
- }
-
- if ( keys && keys . length > 0 ) { If the value to be retrieved is an Object, recursively attempt
-to get the value from redis. Here we use a recursive call to this.get
-to support nested Object keys.
async . forEach ( keys , addValue , function ( err ) {
- if ( err ) {
- return callback ( err );
- }
-
- self . cache . set ( key , result );
- callback ( null , result );
- })
- }
- else { If there are no keys, then the value to be retrieved is a literal
-and we can simply return the value from redis directly.
self . redis . get ( fullKey , function ( err , value ) {
- if ( err ) {
- return callback ( err );
- }
-
- result = JSON . parse ( value );
- if ( result ) {
- self . cache . set ( key , result );
- }
-
- callback ( null , result );
- });
- }
- });
-}; function set (key, value, callback)
-
-@key {string} Key to set in this instance
-
-@value {literal|Object} Value for the specified key
-
-@callback {function} Continuation to respond to when complete.
-
-Sets the value
for the specified key
in this instance.
Redis . prototype . set = function ( key , value , callback ) {
- var self = this ,
- path = nconf . path ( key );
- Set the callback if not provided for "fire and forget"
callback = callback || function () { };
-
- this . _addKeys ( key , function ( err ) {
- if ( err ) {
- return callback ( err );
- }
-
- var fullKey = nconf . key ( self . namespace , key );
-
- if ( ! Array . isArray ( value ) && value !== null && typeof value === 'object' ) { If the value is an Object
(and not an Array
) then
-nest into the value and set the child keys appropriately.
-This is done for efficient lookup when setting Object keys.
-(i.e. If you set and Object then wish to later retrieve only a
-member of that Object, the entire Object need not be retrieved).
self . cache . set ( key , value );
- self . _setObject ( fullKey , value , callback );
- }
- else { If the value is a simple literal (or an Array
) then JSON
-stringify it and put it into Redis.
self . cache . set ( key , value );
- value = JSON . stringify ( value );
- self . redis . set ( fullKey , value , callback );
- }
- });
-}; function merge (key, value, callback)
-
-@key {string} Key to merge the value into
-
-@value {literal|Object} Value to merge into the key
-
-2callback {function} Continuation to respond to when complete.
-
-Merges the properties in value
into the existing object value
-at key
. If the existing value key
is not an Object, it will be
-completely overwritten.
Redis . prototype . merge = function ( key , value , callback ) { If the key is not an Object
or is an Array
,
-then simply set it. Merging is for Objects.
if ( typeof value !== 'object' || Array . isArray ( value )) {
- return this . set ( key , value , callback );
- }
-
- var self = this ,
- path = nconf . path ( key ),
- fullKey = nconf . key ( this . namespace , key );
- Set the callback if not provided for "fire and forget"
callback = callback || function () { };
- Get the set of all children keys for the key
supplied. If the value
-to be returned is an Object, this list will not be empty.
this . _addKeys ( key , function ( err ) {
- self . redis . smembers ( nconf . key ( fullKey , 'keys' ), function ( err , keys ) {
- function nextMerge ( nested , next ) {
- var keyPath = nconf . key . apply ( null , path . concat ([ nested ]));
- self . merge ( keyPath , value [ nested ], next );
- }
-
- if ( keys && keys . length > 0 ) { If there are existing keys then we must do a recursive merge
-of the two Objects.
return async . forEach ( Object . keys ( value ), nextMerge , callback );
- } Otherwise, we can simply invoke set
to override the current
-literal or Array value with our new Object value
self . set ( key , value , callback );
- });
- });
-}; function clear (key, callback)
-
-@key {string} Key to remove from this instance
-
-@callback {function} Continuation to respond to when complete.
-
-Removes the value for the specified key
from this instance.
Redis . prototype . clear = function ( key , callback ) {
- var self = this ,
- result = {},
- path = [ this . namespace ]. concat ( nconf . path ( key )),
- last = path . pop (),
- fullKey = nconf . key ( this . namespace , key ); Set the callback if not provided for "fire and forget"
callback = callback || function () { }; Clear the key from the cache for this instance
Remove the key
from the parent set of keys.
this . redis . srem ( nconf . key . apply ( null , path . concat ([ 'keys' ])), last , function ( err ) { Remove the value from redis by iterating over the set of keys (if any)
-and deleting each value. If no keys, then just delete the simple literal.
self . redis . smembers ( nconf . key ( fullKey , 'keys' ), function ( err , keys ) {
- function removeValue ( child , next ) { Recursively call self.clear
here to ensure we remove any
-nested Objects completely from this instance.
self . clear ( nconf . key ( key , child ), next );
- }
-
- if ( keys && keys . length > 0 ) { If there are child keys then iterate over them,
-removing each child along the way.
async . forEach ( keys , removeValue , callback );
- }
- else { Otherwise if this is just a simple literal, then
-simply remove it from Redis directly.
self . redis . del ( fullKey , callback );
- }
- });
- });
-}; function save (value, callback)
-
-@value {Object} Config object to set for this instance
-
-@callback {function} Continuation to respond to when complete.
-
-Removes any existing configuration settings that may exist in this
-instance and then adds all key-value pairs in value
.
Redis . prototype . save = function ( value , callback ) {
- if ( Array . isArray ( value ) || typeof value !== 'object' ) {
- return callback ( new Error ( '`value` to be saved must be an object.' ));
- }
-
- var self = this ,
- keys = Object . keys ( value );
- Set the callback if not provided for "fire and forget"
callback = callback || function () { }; Clear all existing keys associated with this instance.
this . reset ( function ( err ) {
- if ( err ) {
- return callback ( err );
- }
- Iterate over the keys in the new value, setting each of them.
async . forEach ( keys , function ( key , next ) {
- self . set ( key , value [ key ], next );
- }, callback );
- });
-}; function load (callback)
-
-@callback {function} Continuation to respond to when complete.
-
-Responds with an Object representing all keys associated in this instance.
Redis . prototype . load = function ( callback ) {
- var self = this ,
- result = {};
- Set the callback if not provided for "fire and forget"
callback = callback || function () { };
-
- this . redis . smembers ( nconf . key ( this . namespace , 'keys' ), function ( err , keys ) {
- if ( err ) {
- return callback ( err );
- }
-
- function addValue ( key , next ) {
- self . get ( key , function ( err , value ) {
- if ( err ) {
- return next ( err );
- }
-
- result [ key ] = value ;
- next ();
- });
- }
-
- keys = keys || [];
- async . forEach ( keys , addValue , function ( err ) {
- return err ? callback ( err ) : callback ( null , result );
- });
- });
-}; function reset (callback)
-
-@callback {function} Continuation to respond to when complete.
-
-Clears all keys associated with this instance.
Redis . prototype . reset = function ( callback ) {
- var self = this ;
- Set the callback if not provided for "fire and forget"
callback = callback || function () { };
- Get the list of of top-level keys, then clear each of them
this . redis . smembers ( nconf . key ( this . namespace , 'keys' ), function ( err , existing ) {
- if ( err ) {
- return callback ( err );
- }
-
- existing = existing || [];
- async . forEach ( existing , function ( key , next ) {
- self . clear ( key , next );
- }, callback );
- });
-}; @private function _addKeys (key, callback)
-
-@key {string} Key to add parent keys for
-
-@callback {function} Continuation to respond to when complete.
-
-Adds the full key
path to Redis via sadd
.
Redis . prototype . _addKeys = function ( key , callback ) {
- var self = this ,
- path = nconf . path ( key );
-
- function addKey ( partial , next ) {
- var index = path . indexOf ( partial ),
- base = [ self . namespace ]. concat ( path . slice ( 0 , index )),
- parent = nconf . key . apply ( null , base . concat ([ 'keys' ]));
-
- self . redis . sadd ( parent , partial , next );
- }; Iterate over the entire key path and add each key to the
-parent key-set if it doesn't exist already.
async . forEach ( path , addKey , callback );
-}; @private function _setObject (key, value, callback)
-
-@key {string} Key to set in this instance
-
-@value {Object} Value for the specified key
-
-@callback {function} Continuation to respond to when complete.
-
-Internal helper function for setting all keys of a nested object.
Redis . prototype . _setObject = function ( key , value , callback ) {
- var self = this ,
- keys = Object . keys ( value );
-
- function addValue ( child , next ) { Add the child key to the parent key-set, then set the value.
-Recursively call _setObject
in the event of nested Object(s).
self . redis . sadd ( nconf . key ( key , 'keys' ), child , function ( err ) {
- if ( err ) {
- return next ( err );
- }
-
- var fullKey = nconf . key ( key , child ),
- childValue = value [ child ];
-
- if ( ! Array . isArray ( childValue ) && typeof childValue === 'object' ) {
- self . _setObject ( fullKey , childValue , next );
- }
- else {
- childValue = JSON . stringify ( childValue );
- self . redis . set ( fullKey , childValue , next );
- }
- });
- }
- Iterate over the keys of the Object and set the appropriate values.
async . forEach ( keys , addValue , function ( err ) {
- return err ? callback ( err ) : callback ();
- });
-};
-
-
\ No newline at end of file
diff --git a/docs/nconf/stores/system.html b/docs/nconf/stores/system.html
new file mode 100644
index 0000000..9e89544
--- /dev/null
+++ b/docs/nconf/stores/system.html
@@ -0,0 +1,98 @@
+ system.js
system.js /*
+ * system.js: Simple memory-based store for process environment variables and
+ * command-line arguments.
+ *
+ * (C) 2011, Charlie Robbins
+ *
+ */
+
+var util = require ( 'util' ),
+ Memory = require ( './memory' ). Memory ;
+ function System (options)
+
+@options {Object} Options for this instance.
+
+Constructor function for the System nconf store, a simple abstraction
+around the Memory store that can read process environment variables
+and command-line arguments.
var System = exports . System = function ( options ) {
+ options = options || {};
+ Memory . call ( this , options );
+
+ this . type = 'system' ;
+ this . overrides = options . overrides || null ;
+ this . env = options . env || false ;
+ this . argv = options . argv || false ;
+}; Inherit from the Memory store
util . inherits ( System , Memory ); function loadSync ()
+
+Loads the data passed in from process.env
into this instance.
System . prototype . loadSync = function () {
+ if ( this . env ) {
+ this . loadEnv ();
+ }
+
+ if ( this . argv ) {
+ this . loadArgv ();
+ }
+
+ if ( this . overrides ) {
+ this . loadOverrides ();
+ }
+
+ return this . store ;
+}; function loadOverrides ()
+
+Loads any overrides set on this instance into
+the underlying managed Memory
store.
System . prototype . loadOverrides = function () {
+ if ( ! this . overrides ) {
+ return ;
+ }
+
+ var self = this ,
+ keys = Object . keys ( this . overrides );
+
+ keys . forEach ( function ( key ) {
+ self . set ( key , self . overrides [ key ]);
+ });
+
+ return this . store ;
+}; function loadArgv ()
+
+Loads the data passed in from the command-line arguments
+into this instance.
System . prototype . loadArgv = function () {
+ var self = this ,
+ argv ;
+
+ if ( typeof this . argv === 'object' ) {
+ argv = require ( 'optimist' ). options ( this . argv ). argv ;
+ }
+ else if ( this . argv ) {
+ argv = require ( 'optimist' ). argv ;
+ }
+
+ if ( ! argv ) {
+ return ;
+ }
+
+ Object . keys ( argv ). forEach ( function ( key ) {
+ self . set ( key , argv [ key ]);
+ });
+
+ return this . store ;
+}; function loadEnv ()
+
+Loads the data passed in from process.env
into this instance.
System . prototype . loadEnv = function () {
+ var self = this ;
+
+ if ( ! this . env ) {
+ return ;
+ }
+
+ Object . keys ( process . env ). filter ( function ( key ) {
+ return ! self . env . length || self . env . indexOf ( key ) !== - 1 ;
+ }). forEach ( function ( key ) {
+ self . set ( key , process . env [ key ]);
+ });
+
+ return this . store ;
+};
+
+
\ No newline at end of file