Type handling - DarthJDG/Mangler.js GitHub Wiki
By default Mangler.js can only recognise primitive JavaScript object types. While it is enough to handle object literals and JSON data, it's quite limiting when it comes to typed objects. By registering handler functions for other object types, you can teach Mangler.js what to do when it encounters certain object instances.
If you're only using JSON data, simple arrays, object literals, mangler objects and Date objects, you don't need to do anything as Mangler.js has built-in support for them.
If you're using other native object types or typed arrays, see the Mangler-natives module for support.
This section explains how you can teach Mangler.js what to do when it encounters other object types.
The Matrix object
Let's create a simple Matrix object. The constructor takes a rows and cols parameter, an initialises an array of arrays to zeroes. You can access the matrix instance's values by matrix[row][column].
function Matrix(rows, cols) {
this.length = rows;
this.rows = rows;
this.cols = cols;
for(var r = 0; r < rows; r++) {
this[r] = [];
for(var c = 0; c < cols; c++) {
this[r][c] = 0;
}
}
}
By default Mangler.js doesn't recognise this object. When you clone an object containing a Matrix object, it doesn't know what to do with it, and passes the original object on without cloning it. Similarly, calling Mangler.each() or Mangler.get() on the Matrix object will have no effect, as it doesn't know how to "look inside" the object.
To teach Mangler.js how to do all these, you can register your object with Mangler.registerType():
Mangler.registerType(Matrix, {
clone: function(m) {
m2 = new Matrix(m.rows, m.cols);
for(var r = 0; r < m.rows; r++) {
m2[r] = Mangler.clone(m2[r]);
}
return m2;
},
get: function(m, key) {
if(key === 'size') {
return m.rows * m.cols;
} else {
return m[key];
}
},
each: function(m, callback) {
for(var r = 0; r < m.rows; r++) {
if(callback(r, m[r]) === false) return;
}
}
});
The clone function takes a Matrix object as parameter and returns an identical clone. It creates a new instance and copies all values. As Mangler.js knows how to clone arrays, it uses Mangler.clone() on the matrix rows to save iterating over the arrays inside the arrays.
The get function takes a Matrix object and a key as parameter. The function adds a size calculated property which returns the total size of the matrix. For any other key it reads it directly from the matrix object. With this function registered, Mangler.js can directly access all matrix properties, including its rows. Because the rows themselves are simple arrays, you can also access all matrix values using .getPath() or any test expression.
object = {
matrix: new Matrix(3, 4)
};
object.matrix[0][1] = 10;
object.matrix[0][2] = 20;
Mangler.get(object.matrix, 0); // Returns [0, 10, 20, 0]
Mangler.getPath(object, 'matrix[0][1]'); // Returns 10
Mangler.test(object, { matrix { size: 12 } }); // Returns true
array = [
new Matrix(3, 3),
new Matrix(2, 4),
new Matrix(3, 4)
];
// Find all matrix objects with the total size less than 10
Mangler.find(array, { size: { $lt: 10 } }); // Returns the first 2 Matrix objects
The each function takes a Matrix object and a callback function as parameter. By specifying it, Mangler.js can iterate through Matrix objects using any method that takes an iterable parameter, for example .each(), .explore() and .extract(). When writing an iterator function, you need to call the callback function with a key and a value parameter, and stop the iteration if it returns false. Apart from the previous rule, it's up to you what values and keys you're iterating over. This matrix example simply iterates through the rows by index.
m = new Matrix(2, 3);
m[0][1] = 10;
m[0][2] = 20;
m[1][0] = 30;
sum = 0;
// Sum up all values in the matrix
Mangler.each(m, function(r, row) {
Mangler.each(row, function(c, value) {
sum += value;
});
});
// Look for all values greater than 10
Mangler.extract(m, '*', { test: { $type: 1, $gt: 10 }}); // Returns [20, 30]
Array-like objects
You may have noticed that we set the length property to the number of rows in the Matrix object's constructor. In Mangler.js, an array-like object is any object that has a length property and its items can be accessed by numeric keys directly, i.e. object[index]. In this case, you don't have to write each and get handlers, and the registration can be simplified:
Mangler.registerType(Matrix, {
clone: function(m) {
m2 = new Matrix(m.rows, m.cols);
for(var r = 0; r < m.rows; r++) {
m2[r] = Mangler.clone(m2[r]);
}
return m2;
},
get: 'array',
each: 'array'
});
If you want to use calculated properties like size in the original example, you always need to write your own get function.
For more information on other type handling options, see Mangler.registerType().