Socket
Socket
Sign inDemoInstall

gestalt

Package Overview
Dependencies
4
Maintainers
1
Versions
2577
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.7 to 0.0.8

examples/state.js

5

examples/cluster.js

@@ -14,3 +14,3 @@ var gestalt = require('../lib/gestalt');

},
original: new gestalt.ConfigEnv()
config: new gestalt.ConfigEnv()
});

@@ -25,3 +25,3 @@

},
original: new gestalt.ConfigArgs( {
config: new gestalt.ConfigArgs( {
optimist_usage: "Usage: $0 options\nStart a test cluster talking to zookeeper to coordinate naming and leader election.",

@@ -112,3 +112,2 @@ optimist_options: {

//console.log( require.resolve( config.get('config:file')));
var file = new gestalt.ConfigFile( { source: require.resolve( config.get( 'config:file' ) ),

@@ -115,0 +114,0 @@ watch: true,

4

examples/complicated-example.js

@@ -29,4 +29,4 @@ var gestalt = require('../lib/gestalt');

var f = new ConfigFile({ source: yaml_file, format: 'yaml'});
var re = new RemapConfig( { mapper: env_mapper, original: e } );
var ra = new RemapConfig( { mapper: args_mapper, original: a } );
var re = new RemapConfig( { mapper: env_mapper, config: e } );
var ra = new RemapConfig( { mapper: args_mapper, config: a } );

@@ -33,0 +33,0 @@ var config = new ConfigContainer({ source: "config" });

@@ -23,3 +23,3 @@ var gestalt = require('../lib/gestalt'),

var r = new RemapConfig( { mapper: mapper, original: c } );
var r = new RemapConfig( { mapper: mapper, config: c } );

@@ -26,0 +26,0 @@ console.log( r.get('new:foo:0') );

@@ -26,7 +26,6 @@ var EventEmitter = require('events').EventEmitter,

this._pattern_listeners_ = [];
this._state_ = 'not ready';
var self = this;
this.on('change', function(change) { this._on_change_(change) });
process.nextTick( function() {self.state( self._options_.initial_state_ ) } );
self.state( self._options_.initial_state );
}

@@ -38,2 +37,19 @@

function worse_state( a , b ) {
if( a == 'invalid' || b == 'invalid' ) {
return 'invalid';
} else if ( a == 'ready' ) {
return b;
} else {
return a
}
}
p._dependency_states_ = function() {
return _.chain( this._values_ )
.filter( function(value) { return value instanceof Configuration } )
.map( function(value) {return value.state() } )
.value();
}
p.state = function(state, data) {

@@ -44,4 +60,13 @@ if( ! state ) {

var worst = _.reduce( this._dependency_states_(), worse_state, state );
if( state != worst ) {
// unable to change states because there
// is a dependency blocking us with a
// higher priority state.
state = worst;
}
if( this._state_ != state || state == 'invalid' ) {
var so = { state: state, old_state: this._state, data: data };
var so = { state: state, old_state: this._state_, data: data };
this._state_ = state;

@@ -86,3 +111,3 @@ this.emit('state', so);

p.getPath = function(name) {
p._get_path_ = function(name) {
var path;

@@ -107,2 +132,3 @@ if( typeof(name)== 'string' ) {

});
self.emit('state', { state: this._state_, old_state: this._state_ } );
};

@@ -141,3 +167,3 @@

p.get = function(name) {
var path = this.getPath(name);
var path = this._get_path_(name);
if( _.isUndefined(path)) {

@@ -160,3 +186,3 @@ return undefined;

p.getValSource = function(name) {
var path = this.getPath(name);
var path = this._get_path_(name);
if( _.isUndefined(path)) {

@@ -183,3 +209,3 @@ return undefined;

var self = this;
var path = this.getPath(name);
var path = this._get_path_(name);
if( _.isUndefined(path)) {

@@ -240,5 +266,5 @@ return;

if( state_change.state == 'invalid' ) {
this.state( 'invalid', state_change.data );
self.state( 'invalid', state_change.data );
} else if (state_change.state == 'ready' ) {
if( _.chain( this._values_)
if( _.chain( self._values_)
.values()

@@ -249,6 +275,6 @@ .filter( function(x) { return x instanceof Configuration ;} )

) {
this.state('ready', state_change.data );
self.state('ready', state_change.data );
}
} else {
this.state( 'not ready', data );
self.state( 'not ready', state_change.data );
}

@@ -301,3 +327,3 @@ }

var path = this.getPath(name);
var path = this._get_path_(name);

@@ -324,3 +350,3 @@ // do nothing if the path is not valid

// remove values that are not present in the new value
_.each( this._values_[n].flat_keys, function(key) {
_.each( this._values_[n]._child_keys_(), function(key) {
if( !_.has(value, key) ) {

@@ -358,3 +384,3 @@ self.remove([n,key]);

} else {
this._change_value_( n, new Configuration( this._options_ ) );
this._change_value_( n, new Configuration( _.extend({},this._options_,{initial_state: 'ready'} ) ) );
this._sources_[n] = source;

@@ -368,3 +394,3 @@ this._values_[n].set(path,value,source);

var self = this;
var path = this.getPath(name);
var path = this._get_path_(name);
var n = path.shift();

@@ -394,3 +420,5 @@ if( path.length === 0 ) {

p.flat_keys = function() {
// Return the keys of direct descendents of this config
// object.
p._child_keys_ = function() {
var keys = [];

@@ -408,11 +436,11 @@ return _.keys( this._values_ );

p.isArrayLike = function() {
var arrayLike = true;
this.flat_keys().map( function(x) { return(Number(x)); })
.sort()
.forEach( function(element,index) {
arrayLike = arrayLike && (element===index);
});
return arrayLike;
};
// p.isArrayLike = function() {
// var arrayLike = true;
// this.flat_keys().map( function(x) { return(Number(x)); })
// .sort()
// .forEach( function(element,index) {
// arrayLike = arrayLike && (element===index);
// });
// return arrayLike;
// };

@@ -447,3 +475,3 @@ //p.toObject = function() {

_.each( this.keys().sort(), function(key) {
var path = self.getPath(key);
var path = self._get_path_(key);
var indent = "";

@@ -503,3 +531,3 @@ for(var i=0; i<keys.length && i <path.length && keys[i] == path[i]; ++i) {

_.each( this.keys().sort() , function(key) {
var path = self.getPath(key);
var path = self._get_path_(key);
var val = self.get(key);

@@ -506,0 +534,0 @@ if( val instanceof Configuration ) {

module.exports.Configuration = require('./config').Configuration;
module.exports.ConfigContainer = require('./config-container').ConfigContainer;
module.exports.ConfigContainer = require('./container').ConfigContainer;
module.exports.ConfigFile = require('./file').ConfigFile;

@@ -4,0 +4,0 @@ module.exports.ConfigArgs = require('./args').ConfigArgs;

@@ -20,3 +20,3 @@ var parsers = require('./format').parsers,

var org = this._org_ = this._options_.original;
var org = this._org_ = this._options_.config;
this._cache_ = {forward: {}, reverse: {}};

@@ -104,2 +104,7 @@

p.update = function(name,value,source) {
// remapped objects are read only
// this._org_.set( this.map_new_name(name), value, source);
};
p.set = function(name,value,source) {

@@ -106,0 +111,0 @@ // remapped objects are read only

{
"name": "gestalt",
"version": "0.0.7",
"version": "0.0.8",
"author": "Chris Howe <chris@howeville.com>",

@@ -5,0 +5,0 @@ "description": "Event driven configuration management.",

@@ -6,23 +6,24 @@ # gestalt

underlying configuration for an application may change while the
application is still running. Gestalt gives you a framework detecting
application is still running. Gestalt provides a framework detecting
and reacting to these changes without having to completely restart
your application.
There are a couple of motivations for gestalt. Configuration of a
There are a couple of motivations for gestalt: Configuration of a
large software system is often complicated - there are of course many
tools out there for gathering configuration information from a bunch
of different sources. nconf for node is a good one, and gestalt is to
some extent based upon it, ( but also influenced by configliere for
ruby and the configuration node structure of chef). There are a couple
of things that many of these tools do not do. First, configuration
files (and other sources) can change, and it would be nice to be able
to react to these changes on-the-fly. Second, when you have a
some extent based upon it. Gestalt is also influenced by configliere
for ruby and the configuration node structure of chef. However, there
are a couple of things that many of these tools do not do well. First,
configuration files (and other sources) can change, and it would be
nice to be able to react to these changes on-the-fly. Second, for a
sufficiently complicated system of default and override configuration
sources, it can become difficult to figure out exactly where a
particular setting came from. Gestalt solves both of these
problems. It has a per-value event change tracking system so that you
can track changes to individual settings to your configuration. It
also rigorously keeps track of where the values for particular
settings came from.
particular setting came from.
Gestalt solves both of these problems. It has a per-value event change
tracking system so that you can track changes to individual settings
to your configuration. It also rigorously keeps track of where the
values for particular settings came from.
## Basics

@@ -62,3 +63,3 @@

Values can be primative values (numbers, strings, booleans,
etc.). Assignments of structured objects get destructured into nested
etc.). By default, assignments of structured objects get destructured into nested
Configuration objects.

@@ -73,8 +74,9 @@

In many cases (not quite all...this is not yet supported for
RemapConfig objects...) it is possible to turn a configuration object
back into a regular object. In fact, if a configuration object looks
like an array (all integer keys...) toObject will in fact return an
array.
( The default destructuring of assignments can be disabled. See
the destructure_assignments and destructure_arrays options, below. )
It is possible to turn a configuration object back into a regular
object. Also, if a configuration object looks like an array (all
integer keys...) toObject will in fact return an array.
## Events

@@ -98,5 +100,5 @@

You can also listen to events on the nested configuration objects. Note
that configuration names in the events are reported relative to the configuration
object you are listening to.
The nested configuration objects are also event emitters. Note that
the configuration names in the events are reported relative to the
configuration object being listening to.

@@ -134,3 +136,4 @@ Configuration objects also have a ready/invalid/other state. When

configuration data. You can read data from it, and set up
listeners.
listeners. Note that a configuration can only be in a ready
state if all of its dependencies are also ready.

@@ -143,3 +146,4 @@ - 'invalid' Something has gone wrong. We may not be able to get in

stop consuming configuration data from the object and seek a way to remedy
the invalid state.
the invalid state. If any of an objects depencencies is in an invalid
state, the object will also be invalid.

@@ -256,3 +260,3 @@ - 'not ready', (and others). The configuration object is not ready for reads.

### Configuration
### Configuration

@@ -305,5 +309,7 @@ A Configuration object is a container of name value pairs. The names

#### Methods
- get(name)
Returns the value assigned to `name`, or undefined if not
Returns the value assigned to 'name', or undefined if not
present. Namespaces are separated by colons. If name is an array, it

@@ -352,5 +358,5 @@ is treated the same as if it were a single string joined together by

- report()
- report( )
Generates a detailed report of all of the names.
Generates a detailed report (on console.log) of all of the names.

@@ -363,3 +369,4 @@ - toObject()

are sequential numbers starting with 0, it will be converted into an
array instead of a regular object.
array instead of a regular object. The resultant object will not
generate any events and will not have source attribution.

@@ -376,7 +383,8 @@ - options( options )

Calls the callback whenever there is a change to the configuration that
matches the pattern. Pattern could be a string, or a regex, in which cases
match means that the name of the changed value either equals the string
or matches the regex respectively. Pattern could also be a function which
return a truthy value if the change matches its criteria.
Calls the callback whenever there is a change to the configuration
that matches the pattern. Pattern could be a string, or a regex, in
which cases match means that the name of the changed value either
equals the string or matches the regex respectively. Pattern could
also be a function which return a truthy value if the change matches
its criteria.

@@ -400,5 +408,5 @@ - removePatternListener( callback )

Change events are emitted whenever the Configuration object detects that something
has changed in the data. The handlers to these events are passed an object describing
the change:
Change events are emitted whenever the Configuration object detects
that something has changed in the data. The handlers to these events
are passed an object describing the change:

@@ -414,5 +422,190 @@ ```javascript

When the object's state changes between 'invalid', 'ready' and 'not ready', it will
emit 'change' events.
When the object's state changes between 'invalid', 'ready' and 'not
ready', it will emit 'state' events of the form:
```javascript
state = { state: 'ready', // new state value
old_state: 'invalid', // state we are transitioning to
data: 'good now' // data passed in by the config.state() method.
};
```
### ConfigContainer
gestalt's mechanism to deal with the notion of default and override
behavior is implemented in the ConfigContainer object. ConfigContainers
contain a list or priority ordered configuration objects. Calling 'get(name)'
on the ConfigContainer will return the value assigned to the highest priority
configuration that has a value set for that name.
- constructor ConfigContainer( options )
Takes the same options as a Configuration object, but will also accept
-config
A configuration object to act as the 'normal' object. See 'set' and
'update' below. If no config option is given, a new object will be
created as the 'normal' object;
#### Methods
All of the public methods of the Configuration object should work on a
ConfigContainer, however the semantics of a few of them are a little
different.
- get(name)
Returns the value associated with the name of the highest priority object
containing a defined value for the name.
- set(name, value, source)
Calls 'set' on the 'normal' priority configuration object.
- update(name, value, source)
Calls 'update' on the highest prior configuration that has a value
already set for 'name'. If none have defined 'name', then call 'update'
on the 'normal' priority object.
- keys()
Returns the union of all of the keys in all of the contained configuration
objects.
- has(name)
Returns true if the name is in the result of calling keys()
- each()
Works the same as Configuration's each method, but the values are as
determined by the highest priority configuration object that has a
value for the given key.
- addOverride( config )
Adds a configuration object to the priority list of configurations
as the highest priority object.
- addDefault( config )
Adds a configuration object to the priority list as the lowest
priority config object.
### RemapConfig
The RemapConfig object provides a way to change the names of a
configuration without changing the values. This useful for changing
the names that come from environment variables or command line
variables into names that match up with the configuration hierarchy
established in a configuraiton file - making it possible to use
the override and default behaviors from a ConfigContainer object.
- constructor RemapConfig( options )
Takes the same options as a Configuration object, but will also accept
-config (mandatory)
The configuration object to remap.
-mapper (mandatory)
Specifies how to remap configuration names. This can either be a
function of the form:
```javascript
remap = function(old_value) {
var new_value = "a:b:c:" + old_value;
return new_value;
}
```
or it can be a flat javascript object with old names as keys and new
names as values.
Names that get mapped to 'undefined' by a remap function, or that are
not present in the remap object, will simply not be included in the
resultant object.
### Methods
All of the Configuration public methods are supported, with the following
additions and modifications:
- original()
Returns a reference to the unmapped configuration object.
- set()
Does nothing - remap objects are read only at this time.
- update()
Does nothing - remap objects are read only at this time.
- remove()
Does nothing - remap objects are read only at this time.
### ConfigArgs
This is a standard Configuration object that pulls its name and value
pairs from parsing the command line arguments with the optimist
library. In addition to the standard configuration options, it will also
accept the following:
- argv
Use the array instead of the arguments in process.argv
- optimist_usage
String to pass on to optimist as a usage string. ( Uses optimist's
"usage" method. )
- optimist_options
Object to pass on to optimist as a configuration options. ( Uses
optimist's "usage" method. )
### ConfigEnv
This is a standard Configuration object that pulls its name and value
pairs from parsing the environmental variables. In addition to the
standard configuration options, it will also accept the following:
- env
Use this set of name value pairs instead of process.env.
### ConfigFile
This is a standard Configuration object that draws its names and values
from a configuration file. In addition to the standard options, ConfigFiles
accept the following:
- format
Tells what format the file is in. Current options are 'json', 'yaml'
and 'ini'.
- source
Tells what file to read - gets passed to fs.readFile.
- watch
Boolean. If set to true, the constructed ConfigFile object will set up
a watch for changes to the underlying file. If it changes on disk,
ConfigFile will reload the file and update any changed values.

@@ -342,2 +342,24 @@ var vows = require('vows'),

}
},
"State Change": {
topic: function() {
var states = [];
var config = new Configuration({source: "X"})
.on('state', function(state) { states.push(state); } );
config.set("a:b:c:d",1);
config.set("a:b:d:e",1);
config.get("a:b:c").state('invalid', 'test1');
config.get("a:b:d").state('invalid', 'test2');
config.get("a:b").state('unknown', 'test3');
config.get("a:b:c").state('ready', 'doesnt propagate');
config.get("a:b:d").state('ready', 'test4');
return states;
},
"4 state changes": function(states) {
assert.equal( states.length, 4 );
assert.deepEqual( _.pluck(states,'state'),
['invalid','invalid','invalid', 'ready'] );
assert.deepEqual( _.pluck(states,'data'),
['test1','test2','test3','test4' ] );
}
}

@@ -344,0 +366,0 @@ }).export(module);

@@ -37,12 +37,2 @@ var vows = require('vows'),

},
'should break apart colon separated paths':
function(config) {
var path = config.getPath("a:b:c:d");
assert.isArray( path );
assert.equal(path.length, 4);
assert.equal(path[0], "a");
assert.equal(path[1], "b");
assert.equal(path[2], "c");
assert.equal(path[3], "d");
},
'should populate new paths when set':

@@ -258,5 +248,62 @@ function(config) {

}
},
"State Change": {
topic: function() {
var states = [];
var orig = new ConfigContainer();
var config = new ConfigContainer({config: orig})
.on('state', function(state) { states.push(state); } );
var def = new Configuration();
var over = new Configuration();
config.addDefault(def);
config.addOverride(over);
def.state('invalid', 'test1');
over.state('invalid', 'test2');
orig.state('unknown', 'test3');
orig.state('ready', 'doesnt propagate');
def.state('ready', 'doesnt propagate');
over.state('ready', 'test4');
return states;
},
"4 state changes": function(states) {
assert.equal( states.length, 4 );
assert.deepEqual( _.pluck(states,'state'),
['invalid','invalid','invalid', 'ready'] );
assert.deepEqual( _.pluck(states,'data'),
['test1','test2','test3','test4' ] );
}
},
"Initial State": {
topic: function() {
var states = [];
var orig = new ConfigContainer();
orig.state('not ready');
var config = new ConfigContainer({config: orig});
states.push( config.state() );
var def = new Configuration();
def.state('invalid')
var over = new Configuration();
over.state('unknown');
config.addDefault(def);
states.push( config.state() );
config.addOverride(over);
states.push( config.state() );
return states;
},
"states": function(states) {
assert.deepEqual( states,
['ready','invalid','invalid'] );
}
}
}).export(module);

@@ -23,3 +23,3 @@ var vows = require('vows'),

};
var remap = new RemapConfig({mapper: mapper, original: config});
var remap = new RemapConfig({mapper: mapper, config: config});
return remap;

@@ -44,3 +44,3 @@ },

};
var remap = new RemapConfig({mapper: mapper, original: config});
var remap = new RemapConfig({mapper: mapper, config: config});
config.set("a", 1);

@@ -73,3 +73,3 @@ config.set("b", 2);

};
var remap = new RemapConfig({mapper: mapper, original: config});
var remap = new RemapConfig({mapper: mapper, config: config});
config.set("a", 1);

@@ -97,3 +97,3 @@ config.set("b", 2);

};
var remap = new RemapConfig({mapper: mapper, original: config});
var remap = new RemapConfig({mapper: mapper, config: config});
var changes = [];

@@ -149,3 +149,3 @@ remap.on('change', function( change ) {

};
var remap = new RemapConfig({mapper: mapper, original: config});
var remap = new RemapConfig({mapper: mapper, config: config});
var changes = [];

@@ -185,3 +185,3 @@ remap.on('change', function( change ) {

};
var remap = new RemapConfig({mapper: mapper, original: config});
var remap = new RemapConfig({mapper: mapper, config: config});
var changes = [];

@@ -204,3 +204,28 @@ remap.on('change', function( change ) {

}
},
"State Change": {
topic: function() {
var states = [];
var config = new Configuration({source: "basic config object"});
var mapper = function(old_name) {
return {a:'e:f', b:'e:g', c:'d'}[old_name];
};
var remap = new RemapConfig({mapper: mapper, config: config});
remap.on('state', function(state) {states.push(state);} );
config.state('invalid', 'test1');
config.state('invalid', 'test2');
config.state('weird', 'test3');
config.state('weird', 'doesnt propagate');
config.state('ready', 'test4');
return states;
},
"4 state changes": function(states) {
assert.equal( states.length, 4 );
assert.deepEqual( _.pluck(states,'state'),
['invalid','invalid','weird','ready'] );
assert.deepEqual( _.pluck(states,'data'),
['test1','test2','test3','test4' ] );
}
}
}).export(module);

@@ -207,0 +232,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc