Alright everyone, I have finished the xJSON object suite, or at least a decent first pass. This was a bigger project than I expected and I apologize for dragging it out over the past couple weeks. It seemed like every time I was about to finish, I would uncover a corner case that would break an entire second of the project. Anyway, I was away over the passed weekend and had to do a lot work in the evening last week, and missed your Tuesday post as well. I hope to be better about getting two articles written a week. I am also open to guest posts, if you are interest just leave a comment on any article.
Anyway, I have written the following objects: JsonObject, JsonArray, XJsonObject, and XJsonArray. Here they are:
/**
* The JsonObject class manages a JSON object by creating getter and setters
* @namespace Core.Model
* @class JsonObject
* @dependencies library
*/
Core.Model.JsonObject = function(json) {
this.update(json);
};
Core.extend(Core.Model.JsonObject, Core.Model.Model, {
/**
* The number of values in the json object
* @property length
* @type int
*/
length: 0,
/**
* Updates the object to use the passed data set
* @method update
* @param json {array} jsonobject object
* @public
*/
update: function(json) {
// validation
if (! isType(json, 'object')) {throw('JsonObject - Invalid data passed into Update');}
this.parent.update.call(this, json);
// private variables
var data = {},
that = this,
n = 0;
var fx = function(key, o) {
var ckey = capitalize(key);
data[key] = Core.Model.XJson(o);
that[(isType(o, 'boolean') && -1 !== key.indexOf('is'))? key: 'get' + ckey] = function() {return data[key];};
that['set' + ckey] = function(o) {
if ($type(o) !== $type(data[key])) {throw('JSONObject - invalid object passed into setter for: ' + key);}
data[key] = o;
};
};
// iterate through the JSON object keys
for (var key in json) {
fx(key, json[key]);
n += 1;
};
// update public variables
this.length = n;
}
});
/**
* The JsonArray class manages ...
* @namespace Core.Model
* @class JsonArray
* @dependencies library
*/
Core.Model.JsonArray = function(json) {
this.update(json);
};
Core.extend(Core.Model.JsonArray, Core.Model.Model, {
/**
* Boolean used to inform the 'get' method to clean the cache
* @property clean
* @type boolean
*/
clean: false,
/**
* The number of values in the json array
* @property length
* @type int
*/
length: 0,
/**
* Execute function 'fn' on all elements in collection
* @method batch
* @param fn {function} the function to execute
* @public
*/
batch: function(fn) {
Core.batch(this.data, function(o, i, scope) {
fn(scope.get(i), i);
}, this);
},
/**
* Retrieve the element at 'i' from the collection; lazy definition to allow for converting objects on demand
* @method get
* @param i {int} index in the data
* @public
*/
get: function(i) {
var that = this,
data = [];
this.get = function(i) {
// commented because this is very strict and don't always want to use, sometimes returning undefined is ok
//if (! that.data[i]) {throw('JsonArray - Invalid index passed into Get: ' + i);}
// purges cached data on an update
if (that.clean) {
data = [];
that.clean = false;
}
if (! data[i] && that.data[i]) {
data[i] = Core.Model.XJson(that.data[i]);
}
return data[i];
};
return this.get(i);
},
/**
* Inserts another value into the data structure
* @method push
* @param o {array} new row of data
* @public
*/
push: function(o) {
if (! o) {throw('JsonArray - Invalid Object passed into Push');}
this.data.push(o);
this.length = this.data.length;
},
/**
* Updates the object to use the passed data set
* @method update
* @param json {array} jsonarray object
* @public
*/
update: function(json) {
// validation
if (! isType(json, 'array')) {throw('JSONArray - Invalid JSON Array Object passed into Update');}
this.parent.update.call(this, json);
this.clean = true;
// update public variables
this.length = json.length;
}
});
/**
* The XJsonObject class manages ...
* @namespace Core.Model
* @class XJsonObject
* @dependencies library
*/
Core.Model.XJsonObject = function(scheme, json) {
if (! isType(scheme, 'array')) {throw('XJsonObject - Invalid scheme passed into Constructor');}
this.scheme = scheme;
this.update(json);
};
Core.extend(Core.Model.XJsonObject, Core.Model.Model, {
/**
* The number of values in the xjson object
* @property length
* @type int
*/
length: 0,
/**
* The object schema
* @property scheme
* @type array
*/
scheme: [],
/**
* Updates the object to use the passed data set
* @method update
* @param json {object} XJsonObject object
* @public
*/
update: function(json) {
// validation
if (! isType(json, 'array')) {throw('XJsonObject - Invalid data passed into Update');}
if (json.length !== this.scheme.length) {throw('XJsonObject - Invalid data (does not match scheme) passed into Update');}
this.parent.update.call(this, json);
// private variables
var data = this.data,
that = this;
// update public variables
this.length = data.length;
Core.batch(this.scheme, function(key, i, json) {
var o = json[i],
ckey = capitalize(key);
data[i] = Core.Model.XJson(o);
that[(isType(o, 'boolean') && -1 !== key.indexOf('is'))? key: 'get' + ckey] = function() {return data[i];};
that['set' + ckey] = function(o) {
if ($type(o) !== $type(data[key])) {throw('XJSONObject - invalid object passed into setter for: ' + key);}
data[i] = o;
};
}, data);
}
});
/**
* The XJsonArray class manages ...
* @namespace Core.Model
* @class XJsonArray
* @dependencies library
*/
Core.Model.XJsonArray = function(json) {
this.update(json);
};
Core.extend(Core.Model.XJsonArray, Core.Model.Model, {
/**
* Boolean used to inform the 'get' method to clean the cache
* @property clean
* @type boolean
*/
clean: false,
/**
* The number of values in the xjson array
* @property length
* @type int
*/
length: 0,
/**
* The object schema
* @property scheme
* @type array
*/
scheme: [],
/**
* Execute function 'fn' on all elements in collection
* @method batch
* @param fn {function} the function to execute
* @public
*/
batch: function(fn) {
Core.batch(this.data, function(o, i, scope) {
fn(scope.get(i), i);
}, this);
},
/**
* Retrieve the element at 'i' from the collection; lazy definition to allow for converting objects on demand
* @method get
* @param i {int} index in the data
* @public
*/
get: function(i) {
var that = this,
data = [];
// internally redeclaring to scope the data structure, which will contain already converted objects
this.get = function(i) {
// commented because this is very strict and don't always want to use, sometimes returning undefined is ok
//if (! that.data[i]) {throw('XJsonArray - Invalid index passed into Get: ' + i);}
// purges cached data on an update
if (that.clean) {
data = [];
that.clean = false;
}
if (! data[i]) {
var o = that.data[i];
// if array, then it is an XJsonObject
if (isType(o, 'array')) {
data[i] = new Core.Model.XJsonObject(that.scheme, o);
}
// otherwise, use generic method
else {
data[i] = Core.Model.XJson(o);
}
}
return data[i];
};
return this.get(i);
},
/**
* Inserts another value into the data structure
* @method push
* @param o {array} new row of data
* @public
*/
push: function(o) {
if (! (isType(o, 'array') && o.length === this.scheme.length)) {throw('XJsonArray - Invalid data passed into Push');}
this.data.push(o);
this.length = this.data.length;
},
/**
* Updates the object to use the passed data set
* @method update
* @param json {object} xjsonarray object
* @public
*/
update: function(json) {
// validation
if (! (json && isType(json, 'object') && isType(json.scheme, 'array') && isType(json.set, 'array'))) {throw('XJsonArray - Invalid data passed into Update');}
this.parent.update.call(this, json.set);
this.clean = true;
// update public variables
this.length = json.length;
this.scheme = json.scheme;
}
});
/**
* The XJson class manages ...
* @namespace Core.Model
* @class XJson
* @dependencies library
*/
Core.Model.XJson = function(o) {
if (! o) {
return null;
}
else if (isType(o, 'array') && (isType(o[0], 'array') || ! o.length)) {
return new Core.Model.JsonArray(o);
}
else if (isType(o, 'object') && ! isType(o, 'array')) {
return (o.scheme)? new Core.Model.XJsonArray(o): new Core.Model.JsonObject(o);
}
else {
return o;
}
};
This is a lot of code to discuss, which I do not have time for today (Tuesday's article will have a detailed explanation). I have introduced a String manipulation method 'capitalize', which converts strings like 'mattsnider' to 'Mattsnider'. This way all getter and setter methods have the appropriate capitalization. This method is from a small package of string functions, which we will discuss after these JSON objects. For now, let me know your thoughts about these objects and take a look at the test page.