mchammer
v1.1.4
Published
Sort-of-immutable objects
Downloads
10
Readme
MC Hammer
This is a really simple library for creating sort-of-immutable data structures in Javascript. It's called "MC Hammer" because you "can't touch this". Why might you want to use it? Mainly because you are interested in referential transparency and want something to remind you about immutability.
This library does not provide deep immutability of built-ins like seamless-immutable or a rich API like Immutable. What it gives you is an easy way to create and (non-destructively) update objects that have read-only properties and methods.
Installation
This library is available through NPM or Bower and it is packaged as a UMD bundle.
npm install mchammer
or
bower install mchammer
and if you are using node/commonjs
var Model = require('mchammer').Model,
Foo = Model()
or AMD
define(['mchammer'], function (mchammer)
{
var Foo = mchammer.Model()
})
or neither
var Foo = mchammer.Model()
Basics
You create a model by defining what properties are allowed and their defaults as well as any methods.
var Model = require('mchammer').Model
var Writer = Model(
{
fields: {
name: 'Unknown',
number_of_books: 0,
something: 'Derp!'
},
methods: {
say_something: function ()
{
return this.something
}
}
})
Then you can create instances of the new model, specifying only the properties that have a value different from the defaults.
var writer = new Writer(
{
name: 'Stephen King',
number_of_books: 54
})
console.log(writer.name) // "Stephen King"
console.log(writer.something) // "Derp!"
writer.say_something() // "Derp!"
You can't change any of the properties.
writer.something = 'Boo!' // TypeError("Cannot assign to read only property 'something' of [object Object]")
But you can easily create a modified copy by specifying the properties you want to change
var the_real_writer = writer.update({ something: 'Boo!' })
the_real_writer.say_something() // 'Boo!'
Fields
To define the fields a Model has, use the fields
options.
var Foo = Model({ fields: { name: 'Steve' } }),
foo = new Foo()
console.log(foo.name) // 'Steve'
Fields can also be functions, in which case they are transformers for whatever value is passed in during instantiation, including undefined
.
var Foo = Model({ fields: { name: function (x) { return (x ? 'Steve '+x : 'Nameless') } } }),
foo1 = new Foo(),
foo2 = new Foo({ name: 'Blobface' })
console.log(foo1.name) // 'Nameless'
console.log(foo2.name) // 'Steve Blobface'
Fields are immutable. Don't bother trying to set them.
foo2.name = 'Andrea Blobface' // TypeError("Cannot assign to read only property 'name' of [object Object]")
Also, if you didn't define a field when you created the model, you can't do it later.
var Foo = Model(),
foo1 = new Foo(),
foo2 = new Foo({ stuff: 'things' }) // Error('Unknown field "stuff"'),
foo3 = foo1.update({ skidoo: 23 }) // Error('Unknown field "skidoo"')
Inheritance
Existing models can be extended.
var Model = require('mchammer').Model
var Instrument = Model(
{
fields: {
sound: '...'
},
methods: {
play: function ()
{
return this.sound
}
}
})
var Guitar = Model.extend(Instrument,
{
fields: {
sound: 'Twang Twang'
}
})
var Martin = Model.extend(Guitar)
var martin_guitar = new Martin()
martin_guitar.play() // 'Twang Twang'
martin_guitar.constructor == Martin // true
Model.is_instance(martin_guitar, Martin) // true
Model.is_instance(martin_guitar, Instrument) // true
Comparisons
You can Deeply compare two Model
instances like so
var SweetMove = Model({
fields: {
name: 'spin',
danger_level: 1
}
}),
spin = new SweetMove(),
twirl = new SweetMove(),
cartwheel = new SweetMove({ name: 'cartwheel', danger_level: 5 })
spin.equals(twirl) // true
spin.equals(cartwheel) // false
You can also compare only based on a subset of properties, like this:
var backbend = new SweetMove({ name: 'backbend', danger_level: 5 })
cartwheel.equals(backbend) // false
cartwheel.equals(backbend, ['danger_level']) // true
Contributing
If you see an open issue you want to tackle, be my guest. If you have a problem or feature suggestion, please create a new issue. Thanks!