A library for managing javascript objects and offering common getter, setter, merge support.
Works great for managing config objects and libraries that have options.
As of 0.8.x the API was completely reimagined so that ObjectManage would only extend the object. Allowing it to be passed and used like any other object but with extended functionality.
This breaks all implementations of the 0.7.x branch which has been split to be maintained separately.
The main change is that the ObjectManage.data
storage object has been moved to the root and all the
extension methods are now prefixed with $
eg: var obj = new ObjectManage(); obj.$get('foo');
$ npm install object-manage
This helper is generally meant to be implemented into higher level API's. As such usage is simple.
ObjectManage is also an event emitter that allows the internal data object to be watched and augmented manually.
var ObjectManage = require('object-manage')
//construct
var obj = new ObjectManage({box: 'square'})
//watch data
var mydata = {}
obj.$on('load',function(data){
mydata = data
})
//load in data
obj.$load({foo: 'bar'})
//set a path
obj.$set('bas.boo','foo1')
//get a path
obj.$get('bas') //{boo: 'foo1'}
obj.$get('bas.boo') //'foo1'
//access data directly
console.log(obj.bas.boo) //'foo1'
//check if a path exists
obj.$exists('bas') //true
obj.$exists('badkey') //false
//remove a path
obj.$remove('bas')
obj.$exists('bas') //false
//reset
obj.$reset()
//path as an array
obj.$set(['foo','test'],'yes')
obj.$get('foo.test') //yes
//see paths currently in object
obj.$getPaths() // ['foo','foo.test']
//clone the object
var clone = ObjectManage.$clone(obj)
//create a new object
var obj2 = {foo: 'test'}
//extend that object
obj2 = ObjectManage.$extend(obj2)
//remove extension
obj2 = obj2.$strip()
It is also useful to use ObjectManage as a super constructor for libraries with options.
Here is a quick example
var ObjectManage = require('object-manage')
, util = require('util')
var myObj = function(data){
ObjectManage.call(this,data)
}
util.inherits(myObj,ObjectManage)
myObj.prototype.$foo = function(){
console.log(this.data) //this.data managed by ObjectManage
}
Paths can be passed in many different formats to allow for more programatic usage of object-manage.
The most common path format is a dot separated set of paths separated by a period. This is also the internal format that all others normalize to.
Example
var path = 'level1.level2.level3'
obj.$get(path)
An array of path parts can also be passed
Example
var path = ['level1','level2','level3']
obj.$get(path)
A function may be passed that returns a string
Example
var path = function(){
return 'level1.level2.level3'
}
obj.$get(path)
The function can also return an array of parts
Example
var path = function(){
return ['level1','level2','level3']
}
obj.$get(path)
An object that has a toString
method can also be used.
Example
var path = {
toString: function(){
return 'level1.level2.level3'
}
}
obj.$get(path)
By default object-manage uses an internal memory storage. However this can easily be changed to use a storage driver to persist the instance.
var handle = 'uuid'
var obj = new ObjectManage()
obj.$storage({
driver: 'redis',
options: {
host: '127.0.0.1',
port: 6379,
secret: 'xyz'
}
})
obj.$restore(handle)
obj.$set('foo',1)
obj.$save(function(err,handle){
if(err) throw err
console.log(handle)
})
To set the storage driver and options use the setStorage method. This method will automatically save the current object to the newly set options so data can still be passed to the constructor. If a string is passed it will be treated as the driver name and will not pass any options to the driver which assumes default.
var obj = new ObjectManage()
obj.$storage('redis') // redis with default options
obj.$storage('memory') // revert back to the default
obj.$storage({
driver: 'redis',
options: {
host: '127.0.0.1',
port: 6379,
secret: 'xyz'
},
ready: function(err){
if(err) throw err
console.log('redis is ready')
}
})
Storage setup also returns the instance so it can be chained on to the constructor.
var obj = new ObjectManage().storage('redis')
obj.$set('foo','yes')
obj.$save(function(err){
if(err) throw err
process.exit()
})
Saves the state of the object into the storage driver.
If no handle is set using the setHandle()
method then a handle
will be automatically generated as a UUID. This handle is made available
to the callback of the save function and will be available through the
getHandle()
method once the save has been initiated.
var obj = new ObjectManage()
obj.$storage('redis')
obj.foo = 1
obj.$save(function(err,handle,data){
if(err) throw err
console.log(handle) //prints the instance id
console.log(data.foo) //1
})
To get the handle used to identify the instance use the getHandle method. The handle is automatically generated when a new instance is saved and no handle has been set.
var obj = new ObjectManage()
console.log(obj.$getHandle()) //prints the instance handle
To set a custom handle used to identify the instance use the setHandle method.
var obj = new ObjectManage()
obj.$storage('redis')
obj.$setHandle('foo')
obj.$set('bar','baz')
obj.$save(function(err,handle,data){
if(err) throw err
console.log(handle) //foo
console.log(data.bar) //baz
})
To retrieve a saved instance of an object use the restore method.
var handle = 'uuid'
var obj = new ObjectManage().$storage('redis')
obj.$restore(handle,function(err,data){
if(err) throw err
console.log(data)
})
Implementing user space drivers is simple as well.
Create a driver.
var myStorageDriver = ObjectManage.StorageDriver.create('myStorageDriver')
var store = {}
myStorageDriver.prototype.setup = function(options){
//connect here
}
myStorageDriver.prototype.save = function(handle,data,next){
//save here
store[handle] = data
next()
}
myStorageDriver.prototype.restore = function(handle,next){
//restore here
next(null,store[handle])
}
myStorageDriver.prototype.flush = function(handle,next){
//flush here
delete store[handle]
next()
}
Using the driver
var obj = new ObjectManage().$storage(new myStorageDriver())
In order to make object-manage more performance friendly in smaller environments the merger can easily be switched between object-merge for merge-recursive. merge-recursive will only merge pointers and thus when the object-manage instance is modified the original objects will be as well. We choose object-merge as the default because it will decouple from the objects being merged in. This comes with a performance and memory cost.
To use merge-recursive
var ObjectManage = require('object-manage')
ObjectManage.prototype.$merge = ObjectManage.prototype.$mergeRecursive
It is also possible to implement one's own merging function.
var ObjectManage = require('object-manage')
ObjectManage.prototype.$merge = function(obj1,obj2){
var mergedObject = obj2
return mergedObject
}
NOTICE Be careful when changing this as it can have unexpected results on other packages that may depend on ObjectManage. It would be best to only override the merge value of the specific instance rather than the prototype.
In order for object-manage to be useful in more hostile environments. It allows for validation functions to be defined per instance.
Quick example of a validation function for setting values
var obj = new ObjectManage()
obj.$validateSet = function(path,value){
//your validation code here that calls one of the below functions
//erroneous method that still processes the action
this.warn('should have passed a boolean',value)
//erroneous methods that will halt processing of the action
this.drop('value must be boolean')
this.reject('value must be boolean')
//will throw an exception that must be caught in user space
this.error('something bad happened')
//non erroneous return methods
this.ok(value)
//or
return value
}
The following callbacks are available.
ObjectManage.$validateGet
-- Validate get directivesObjectManage.$validateSet
-- Validate set directivesObjectManage.$validateExists
-- Validate exists directivesObjectManage.$validateRemove
-- Validate remove directivesObjectManage.$validateLoad
-- Validate load directivesThere are 5 verbs used to handle exceptions
The constructor sets up the object to be managed and accepts
the a arbitrary numbers of arguments that get passed to ObjectManage.load()
var data = {foo: 'foo'}
var inst = new ObjectManage(data)
NOTE If watching data via the load
event is desired data
should not be passed to the construct as it will be impossible to
listen for the load
event.
Load is used to merge an argument object into the main object.
var inst = new ObjectManage()
inst.$load({mykey: 'mydata'})
inst.$load({mykey2: 'mydata2'})
Load will also accept an arbitrary numbers of objects that will be merged on top of each other in order.
var data1 = {test1: 'val1', test2: 'val2'}
, data2 = {test3: 'val3', test4: 'val4'}
, data3 = {test5: {test6: 'val6'}}
var inst = new ObjectManage()
inst.$load(data1,data2,data3)
Set will recursively set a path given by a string using dot notation.
var isnt = new ObjectManage()
inst.$set('mykey','mydata') //{mykey: 'mydata'}
inst.$set('mykey2.data','mydata') //{mykey: 'mydata', mykey2: {data: 'mydata'}}
Get will recursively set a path given by a string using dot notation.
var isnt = new ObjectManage({mykey: 'mydata', mykey2: {data: 'mydata'}})
inst.$get('mykey') //'mydata'
inst.$get('mykey2.data') //'mydata
Check if a path exists
NOTE This uses hasOwnProperty()
method of the object so is safe
to return an accurate value even when a path is set to undefined
var inst = new ObjectManage({mykey: 'myvalue'})
inst.$exists('mykey') //true
inst.$exists('mykey2') //false
Remove a path and all its children
This uses delete object[property]
and does not just set the property
to undefined
var inst = new ObjectManage({mykey: {mykey2: 'myvalue'}})
inst.$exists('mykey.mykey2') //true
inst.$remove('mykey') //true
inst.$exists('mykey.mykey') //false
This will take a userspace object and count the depth of the object.
var inst = new ObjectManage()
var obj = {foo: {foo: {foo: 'baz'}}}
inst.$countDepth(obj) //3
It may be useful to be able to iterate the paths that are contained within the managed object.
In order to do this use the ObjectManage.getPaths()
method.
Example
var obj = new ObjectManage()
obj.$load({foo: {bar: 'baz'}})
obj.$getPaths() // ['foo','foo.bar']
Strip returns only the data from an instance of ObjectManage
Extract returns only the internals from an instance of ObjectManage
Extend returns a new instance of ObjectManage populated with obj
Counts the depth of the object up to maxDepth
and returns that number.
If maxDepth
is omitted it will be set to 50
Fired when a set is processed on the managed object
var obj = new require('object-manage')()
obj.$on('set',function(path,value,valid){
valid = valid ? 'valid' : 'invalid'
console.log('a ' + valid + ' value of (' + value + ') set to (' + path + ')')
})
obj.$set('foo','bar')
Fired when a get is processed on the managed object
var obj = new require('object-manage')()
obj.$on('get',function(path,value){
console.log(value + ' was retrieved from ' + path)
})
obj.$get('foo')
Fired when an exists operation is performed
var obj = new require('object-manage')()
obj.$on('exists',function(path,exists){
var does = exists ? 'does' : 'does not'
console.log('checked if ' + path + ' exists and it ' + does)
})
obj.$exists('foo')
Fired when an remove operation is performed
var obj = new require('object-manage')()
obj.$on('exists',function(path,removed){
var successfully = removed ? 'successfully' : 'unsuccessfully'
console.log(successfully + ' removed path (' + path + ')')
})
obj.$remove('foo')
Fired when a load and merge is performed on the managed object
var obj = new require('object-manage')()
obj.$on('load',function(data){
console.log('a merge was performed and the resulting data: ' + data)
})
obj.$load({foo: 'bar'})
Fired when a handle is generated for the instance
var obj = new require('object-manage')()
obj.$on('generateHandle',function(handle){
console.log('a handle was generated: ' + handle)
})
obj.$generateHandle()
Fired when a save to the storage driver is called
var obj = new require('object-manage')()
obj.$on('save',function(err,handle,data){
if(err) throw err
console.log(handle) //foo
console.log(data.foo) //yes
})
obj.$set('foo','yes')
obj.$setHandle('foo')
obj.$save()
Fired when a restore to the storage driver is called
var obj = new require('object-manage')()
obj.$on('restore',function(err,data){
if(err) throw err
console.log(data.foo) //yes
})
obj.$restore('foo')
Fired when a flush to the storage driver is called
var obj = new require('object-manage')()
obj.$on('flush',function(err){
if(err) throw err
console.log('flushed instance')
})
obj.$restore('foo')
obj.$flush()
Fired when there is a validation drop
var obj = new require('object-manage')()
obj.$on('drop',function(verb,message,path,value){
console.log('object-manage drop [' + verb + ':' + path + ']: ' + message)
})
obj.$validateSet = function(path,value){
this.drop('not accepting anything')
}
obj.$set('foo','will drop') //returns true
Fired when there is a validation reject
var obj = new require('object-manage')()
obj.$on('reject',function(verb,message,path,value){
console.log('object-manage reject [' + verb + ':' + path + ']: ' + message)
})
obj.$validateSet = function(path,value){
this.reject('not accepting anything')
}
obj.$set('foo','will drop') //returns false
Fired when there is a set/get/merge warning.
var obj = new require('object-manage')()
obj.$on('warn',function(verb,message,path,value){
console.log('object-manage warning [' + verb + ']: ' + message)
})
obj.$load(overlyDeepObject)
Fired when there is a set/get/merge error.
var obj = new require('object-manage')()
obj.$on('error',function(verb,message,path,value){
console.log('object-manage error [' + verb + ']: ' + message)
})
obj.$load(overlyDeepObject)
$
eg obj.get -> obj.$get
ObjectManage.getPaths()
reset
methodMaximum call stack exceeded
Maximum call stack exceeded
errorObjectMan
Language | javascript |
Version | 0.8.0 |
Git URL | https://github.com/nullivex/object-manage |
License | MIT |
Description | |
Keywords |