Saturday 29 August 2009

Code Writing Demo ;

Code Writing Demo



What is the deal?

The whole specification is defined in one line of code. set- and get- functions are created automatically based on the spec.

If a new field is added to the specification we only need to update in one line of code. No editing of setters and getters.

If hairColorId is removed from the specification, we only need to change in one line. And we will spot deprecated code because customer.setHairColorId will now be an error. But if we had direct access as customer.hairColorId = 'blue' this would not cause an error. It would be a bug more difficult to detect.

The risk of typing errors in your setters and getters decrease. The file size decrease. Finally it shows something Javascript can do but most languages can't.



I also have a longer post about this.

Henrik Hjelte / Semicolon report


Click button to try demo:










var makeSetterGetter = function (definitionArray) {

function each (array,fn) {
var len = array.length;
for (var i = 0; i < len; i=i+1) {
var el = array[i];
fn(el);
}
};

function capitalize (str) {
return str.charAt(0).toUpperCase()+str.substring(1);
}

function fireEventName (propertyName) {
return "fire" + capitalize(propertyName) + "Change";
}

var self = {
// You can override these functions for tweaking
_internalPropertyName : function (propertyName) {
return propertyName;
},

_setParam : function (paramName, value) {
this[this._internalPropertyName(paramName)] = value;
var fireFn = this[fireEventName(paramName)];
fireFn(value);
return value;
},

_getParam : function (paramName) {
return this[this._internalPropertyName(paramName)];
},

getDefinitionArray : function () {
return definitionArray;
}
};

function makeSetterAndGetterMethod (propertyName) {
var getterName = "get" + capitalize(propertyName);
var setterName = "set" + capitalize(propertyName);
self[getterName] = function () {
return this._getParam(propertyName);
};
self[setterName] = function (value) {
return this._setParam(propertyName,value);
};
}

function makeEventFunction(propertyName) {
// subscribers is a closure that will be unique for each call to
// makeEventFunction.
var subscribers = [];

var registerSubscriberFn = function (fn) {
subscribers.push(fn);
};
var fireEventFn = function (value) {
// subscribers is an array of callback functions,
// call each of them with value and self (optional parameters)
each(subscribers,function (fn) {
fn(value,self);
});
};
var eventSubscribe = "on" + capitalize(propertyName) + "Change";
var fireEventFnName = fireEventName(propertyName);
// Add the methods to self.
// if eventSubscibe is onHairColorIdChange then
// it will be callable with self.onHairColorIdChange
self[eventSubscribe] = registerSubscriberFn;
self[fireEventFnName] = fireEventFn;
}

each(definitionArray, makeSetterAndGetterMethod);
each(definitionArray, makeEventFunction);

return self;
// Put the result of calling makeSetterGetter in a variable x
// You can now call x.setHairColorId which through _setParam
// calls x.fireHairColorIdChange which is one of the fireEventFn
// added that has access to the subscribers array and
// can call the callback functions you might have added with
// onhairColorIdChange(function (value,obj) {doStuff();});
};

function demo() {
function map (array,fn) {
var result = [];
var len = array.length;
for (var i = 0; i < len; i=i+1) {
var el = array[i];
result.push(fn(el));
}
return result;
};

var specification = ['customerId','hairColorId'];
var customer = makeSetterGetter(specification);

customer.onHairColorIdChange(function (value,object) {
alert("3.Customer id "+ object.getCustomerId() +
" has new haircolor " + value);
});

customer.onCustomerIdChange(function () {
// This is ugly, but you can also access properties
// directly. This way I know no events will be triggered.
customer.hairColorId='DONT KNOW';
});
alert("1.Customer starts with undefined color: " + customer.getHairColorId());
customer.setCustomerId(10);
alert("2.Secretly it has been set to don't know: " + customer.getHairColorId());
customer.setHairColorId('blue');

customer.commaSeparated = function () {
var self = this;
return map(this.getDefinitionArray(), function(paramName) {
return self._getParam(paramName);
}).join(',');
};

alert("4.Send this to the server:" + customer.commaSeparated());
};






No comments:

Post a Comment