Am I being over-complicated for a parser? - javascript

This is more a design question that a technical question, but since there is a tag called design-patterns I think it makes sense.
My scenario is as follows: I have a CSV file, that I want to use to populate an object and then use that object for making an API call. So far so good.
The tricky part is that the CSV data could require some conversions before populating the object, and once the object is created and populated I want to edit some of those object properties.
The view and controller operations are going to be provided by angular and I have focused on the template stuff.
How is the object composed? Well, my idea is as follows:
The result will be a hasmap of objects, where each object has a collection of fields which are also objects. This object represents a row, and each field a column.
Each field will have a value property, this way angular can do it's two way data binding magic. It will have also a set of methods for querying and interacting with the object, like asking for the object class (ng-dirty if it is required and empty), adding another element if it is a collection instead of a single value, and that kind of things.
To build this object I will proceed this way:
First build a set of rules for parsing each column/field data.
Each rule has a parser method that parses the data, and a constructor method, which returns the "field" object I mentioned above.
The constructor calls the parser, which will parse the data and return a valid representation of that data. The constructor will then return an object field with the parser result as value and a set of method for interacting with that object.
Rules are created using the ruleFactory function. This function receives the "type" of the field, if it is required (mandatory) or not, the constructor to use and an object for additional options such the parser to use and returns a rule.
Some constructors are built on top of other constructors. For example, the basic constructor is used by the arrayConstructor, that extends the object the basic constructor returns and then returns it. The arrayConstructor is used by the limitedValuesConstructor and so on. If you did not noticed, some constructors falls back to a default parser if it is not defined.
My idea wish is that this is extensible, so if in the future if the format of the data changes, I just add another parser, or I update an existing parser. Same stuff for the constructors.
But, I feel that I'm going to complicated for this task, and I want your opinion about it. Another thing that scares me a lot is that I feel that this does not fit under any valid design pattern that I know. It is not prototypical, not classical, not a module pattern (closure) and I'm not familiar with composition, but I feel that this is not valid composition neither.
Below you can find the basic code inside a closure.
(function () {
function ruleFactory (type,required,constructor,options) {
constructor = constructor || basicConstructor;
var column = {
'type': type,
'required': required || false,
'parser': options && options.parser ,
'constructor': function (data) { return constructor.apply(column,[data,required,options])}
};
return column
}
function strParser (data){
if( typeof data === "string" ){
return data
} else if( data && data.toString){
return data.toString();
}
return ''
}
function arrParser (data){
if(!data){
return []
}
if( angular.isArray(data) ){
return data
}
return strParser(data).split(' ');
}
function basicConstructor (data,required) {
var parser = this.parser || strParser; //fallback to the most basic parser
var column = {};
column.value = parser(data);
column.getClass = function (){
if( required && ! this.value ){
return 'ng-dirty'
}
return ''
};
return column
}
function arrConstructor (data,required) {
this.parser = this.parser || arrParser; // default parser for this constructor
var column = basicConstructor.apply(this,arguments);
column.addValue = function (value) {
column.value.push(value);
}
column.getClass = function ( ) {
if ( column.value.length <= 0 && required ) {
return 'ng-dirty'
}
return ''
}
return column
}
})()
The "rules" object (or array or whatever you want) is built like this:
var rules = {
"someColName": ruleFactory('number',true), // true means required. Defaults to false
"someList" : ruleFactory('array',false,arrConstructor), //No parser defined, so fallbacks to default parser for arrConstructor
"otherList" : ruleFactory('array',false,arrConstructor, {parser:arrParser}) }
Any opinion / constructive criticism is very welcome.
Regards

Related

Maybe monad in JavaScript

In the examples for monads.maybe on npm we have:
function find(collection, predicate) {
for (var i = 0; i < collection.length; ++i) {
var item = collection[i]
if (predicate(item)) return Maybe.Just(item)
}
return Maybe.Nothing()
}
Can someone explain what Maybe.Just(item); and Maybe.Nothing() are actually doing?
Put another way; are monads essentially objects used as return values that implement specific interfaces that enable the definition of a sequence of function invocations?
Maybe is used to represent an operation that might fail.
In the case of this function, you return Just(the element) if an element fulfills the predicate, else, you return Nothing to show that it had "failed" (in this case, none of the elements fulfill the predicate).
It's preferred to just returning a null because the return type explicitly shows that it can fail, and the answer can be pattern matched against.
Monads are abstract containers with an API to operate on the data contained within. In the instance of the Option monad I think of it as a giftbox that either has a gift or is empty. Wrapping your data in a Maybe.Just() signifies that this container does infact contain data, while at the same time it maintains the returned value as a Maybe. The caller of your find() method can then do this:
var userPredicate = function(user) { return user.name === 'billy bob'; };
var users = collections.getUsersCollection();
var maybeData = find(users, userPredicate);
if(maybeData.isJust()) {
// there was data...do something with it
} else {
// no data...do something else
}
On the other hand, Maybe.Nothing() indicates the absence of data (the else part in the example above). Ideally, you would wrap your data within like so: var maybeData = Maybe(data) and then operate on this, pass it around etc. This is a signal to anyone receiving this object that they need to handle the case of missing data consciously.
Disclosure: I'm working on a similar library called Giftbox that has a richer API. Take a look at the readme there for some more explanations to help you understand what the Option monad is and how to use it effectively.
Here's an article describing Monads, Applicatives and Functors that might be useful to you.

javascript build filter function at runtime

While I go into my use-case in (hopefully not too much) detail below, keep in mind that the fundamental question is "How do I create a customized function at runtime in javascript?"
I have (potentially large) arrays of objects, and the user can build custom searches on those objects. The search function is passed an array of filters of the form
[{field:'name', predicate:'contains', modifier:'Joe'},
{field:'type', predicate:'is', modifier:'Boss'}]
which in this example would return all bosses named Joe.
Toward that end, I created a filtering function that applies the filters to the master list, which looks something like:
var matches = everythingOfThatType;
whereClause.forEach(function(filter) {
switch(filter.predicate) {
case '=':
case 'is':
matches = matches.filter(function(record) { return record[filter.field] == filter.modifier; });
console.log(filter, matches);
break;
case '!=':
case 'is not':
matches = matches.filter(function(record) { return record[filter.field] != filter.modifier; });
console.log(filter, matches);
break;
...
and so on.
It's working all right, but now I'm getting some gnarly complexity (special rules for filter combinations, recursive filtering on array properties, etc.), and for performance it would be better to only iterate through the list of all candidates once anyway.
my ideal solution would look something like
var filterFunc = magicallyCreateFilterFunc(filters);
var matches = everythingOfThatType.filter(filterFunc);
where magicallyCreateFilterFunc() would have something like the original switch statement, but instead of applying the filter, would add a line to the function that would eventually be applied to all the objects. Then I can add all the other complexity and recursion and whatnot in a tight, efficient manner.
It seems to me that JavaScript is well-suited for this sort of task (as an aside, the deeper I get into JavaScript the more I appreciate its depth), but I'm a little stuck on step 1: dynamically define a function based on data at run-time. I would really appreciate a nudge in the right direction.
It turns out there is a simple, clean way to do this. What I didn't know when I asked this question oh, so long ago is that closures and filters are best pals.
Rather than apply the filters in the switch statement, I can add the filter functions to an array, then use a closure to execute all the functions on each member of the array.
So my switch statement above looks more like
var buildFilterList = function(whereClause) {
var filterFunctions = [];
whereClause.forEach(function(filter) {
switch(filter.predicate) {
case '=':
case 'is':
filterFunctions.push((function(field) { return function(record) { return record[filter.field] == filter.modifier; })})(field));
break;
...
Which gives me a list of functions to apply to each element, each in a closure that contains the field it should be applied to. More complex filter functions could have more parameters. Now, how to efficiently take that list of filters and apply them? Closures again.
var filterApplicator = function(filters) {
return function(item) {
var passed = true, i = 0, filterCount = filters.length;
for (i = 0; passed && i < filterCount; i++) {
passed = filters[i](item);
}
return passed;
}
}
var filterFunctions = buildFilterList(whereClause);
matches = everythingOfThatType.filter(filterApplicator(filterFunctions));
filterApplicator() returns a function that will be applied to each element in the original array. That function is in a closure that includes the array of filter functions, so all it has to do is loop through those functions and apply them on the element until one fails.
(It should be noted that I have not tested this exact syntax, but the basic concept is what I wanted to pass on here.)

Form handling and validation in pure JavaScript

My intention is to get your thoughts and criticism about the script below, as regards the algorithm's design, performance and cross-browser compatibility.
I have just started getting into JavaScript having missed out on its awesomeness for quite a while. My background and experience is in developing C/C++/PHP based RESTful backends.
In order to understand the language and the right way of using it, I decided to do something which I am sure has been done many times before. But learning to use a new language and paradigm often entails pain anyway.
This is my attempt to create a normal form processing and validation script/ function.
In order to reduce complexity and keep code simple/clean, I decided to use HTML5 Custom Data Attributes (data-*) to assign metadata for each element in the form:
Data-Required: True or False. If set to true, this parameter makes the form-field required and so it cannot be empty. A value set to false indicates that the field is optional. Default is false.>
Data-Type: Type of validation to be performed. Examples include 'email', 'password', 'numbers' or any other 'regexp'.
A fairy simple example of such a form would be:
<form action="postlistings" id="postlistings" enctype='multipart/form-data' method="post" class="postlistings">
<ul class="login-li">
<li>
<input class="title" name="title" type="title" id="title" data-required="true" data-type="title"></a>
</li>
<li>
<textarea name="body" id="elm1" class="elm1" name="elm1" data-type="body" data-required="true" >
</textarea>
</li>
<li>
<span class="nav-btn-question">Add Listing</span>
</li>
</ul>
</form>
Reminder: This is my first piece of JavaScript code.
The idea is to call Form while passing the form name to retrieve and validate all the field values in one loop for performance. The validation involves two steps as can be guessed from the Data-* attributes described above:
i. Check for required form fields.
In case the values fail to meet step 1 requirement, an error message from configuration is pulled for the specific form value. Thus, for all values that fail to meet this requirement, an array of error messages are collected and passed on to the View.
ii. Perform respective validations.
Validations are only performed if all the values passed step 1. Otherwise, they follow the same steps as indicated in 1 above.
function Form(){
var args = Array.prototype.slice.call(arguments),
formName = args[0],
callback = args.pop(),
userError = [{type: {}, param: {}}],
requiredDataParam = 'required',
typeDataParam = 'type',
form = document.forms[formName],
formLength = form.length || null,
formElement = {id: {}, name: {}, value: {}, required: {}, type: {}};
function getFormElements(){
var num = 0;
var emptyContent = false;
for (var i = 0; i < formLength; i += 1) {
var formField = form[i];
formElement.id[i] = inArray('id', formField) ? formField.id : null;
formElement.name[i] = inArray('name', formField) ? formField.name : null;
formElement.value[i] = inArray('value', formField) ? formField.value : null;
formElement.required[i] = getDataAttribute(formField, requiredDataParam);
formElement.type[i] = getDataAttribute(formField, typeDataParam);
if (formElement.required[i] === true){
if(!formElement.type[i]) {
error('Validation rule not defined!');
}
else if (!formElement.value[i]) {
userError[num++] = {'type': 'required', 'param': form[i]};
emptyContent = true;
}
}
if (emptyContent === false) {
// Perform validations only if no empty but required form values were found.
// This is so that we can collect all the empty
// inputs and their corresponding error messages.
}
}
if (userError) {
// Return empty form errors and their corresponding error messages.
}
return formElement;
};
// Removed the getFormParam function that was not used at all.
return {
getFormElements: getFormElements
}
};
Two outside functions that are used in the JS script above (from JQuery source):
var inArray = function(elem, array){
if (array.indexOf){
return array.indexOf(elem);
}
for (var i = 0, length = array.length; i < length; i++){
if (array[i] === elem){
return i;
}
}
return -1;
}
// This is a cross-platform way to retrieve HTML5 custom attributes.
// Source: JQuery
var getDataAttribute = function(elem, key, data) {
if (data === undefined && elem.nodeType === 1) {
data = elem.getAttribute("data-" + key);
if (typeof data === "string") {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
!CheckType.isNaN ? parseFloat(data) :
CheckType.rbrace.test(data) ? parseJSON(data) :
data;
}
else {
data = undefined;
}
}
return data;
}
An example of Config Error messages can be set as follows:
var errorMsgs = {
ERROR_email: "Please enter a valid email address.",
ERROR_password: "Your password must be at least 6 characters long. Please try another",
ERROR_user_exists: "The requested email address already exists. Please try again."
};
As I post this for your review, please ignore any styling conventions that I might not have followed. My intention is to get your expert reviews on anything I should be doing different or could do better concerning the code itself, and the algorithm.
Besides the styling conventions, all criticism and questions are welcome.
First I'd like to clear up a common misconception. Forgive me if you already understand this clearly; maybe it will be helpful for someone else.
Learning and using jQuery or a similar library does not preclude or conflict with learning the JavaScript language. jQuery is simply a DOM manipulation library which takes away many of the pain points of using the DOM. There's plenty of room to learn and use JavaScript, the language, even if you use a library to abstract away some of the DOM details.
In fact, I would argue that using the DOM directly is likely to teach bad JavaScript coding habits, because the DOM is very much not a "JavaScript-ish" API. It was designed to work identically in JavaScript and Java and potentially other languages, and so it completely fails to make good use of the features of the JavaScript language.
Of course as you said, you're using this as a learning exercise; I just don't want you to fall into the trap that I've seen many people fall into of thinking, "I don't want to learn jQuery, because I want to learn JavaScript instead!" That's a false dichotomy: you have to learn JavaScript in either case, and using jQuery for the DOM doesn't interfere with that at all.
Now some details...
While it's OK to quote property names in an object literal and when you reference the properties, it's customary - and more readable - not to quote them when they are valid JavaScript names. e.g. in your formElement object
formElement = { id: {}, name: {}, value: {}, required: {}, type: {} };
(there was a missing semicolon at the end there too)
and where you use the names you can do:
formElement.id[i] = ...
formElement.name[i] = ...
etc.
Don't run your loops backwards unless the program logic requires it. It doesn't make the code faster except possibly in the case of an extremely tight loop, and it makes it unclear whether you're just prematurely optimizing or actually need the backwards loop.
Speaking of optimization, that loop has several inArray() calls. Since each of those loops through an array, that could be more of a performance impact than the outer loop. I imagine these arrays are probably pretty short? So performance wouldn't matter at all anyway, but this is something to think about in cases where you have longer arrays and objects. In some cases you can use an object with property names and values for a faster lookup - but I didn't look closely enough at what you're doing to suggest anything.
In any case, you're using inArray() wrong! But not your fault, that is a ridiculously named function in jQuery. The name clearly suggests a boolean return value, but the function returns the zero-based array index or -1 if the value is not found. I strongly recommend renaming this function as indexOf() to match the native Array method, or arrayIndex(), or some such.
That same loop has form[i] repeated numerous times. You could do this at the top of the loop:
var field = form[i];
and then use field throughout, e.g. field.id instead of form[i].id. This is generally faster, if it matters (which it probably doesn't here), but more importantly it's easier to read.
Do not use strict boolean comparisons like if( foo === true ) and if( bar === false) unless you really need to - and those cases are rare. The code sends a signal to the reader that there is something going on that's different from the usual boolean test. The only time these particular tests should be used is when you have a variable that may contain a boolean value or may contain some other type of value, and you need to distinguish which is which.
A good example of a case where you should use tests like these is an optional parameter that defaults to true:
// Do stuff unless 'really' is explicitly set to false, e.g.
// stuff(1) will do stuff with 1, but stuff(1,false) won't.
function stuff( value, really ) {
if( really === false ) {
// don't do stuff
}
else {
// do stuff
}
}
That specific example doesn't make a lot of sense, but it should give you the idea.
Similarly, an === true test could be used in a case where need to distinguish an actual boolean true value from some other "truthy" value. Indeed, it looks like this line is a valid case for that:
if (formElement['required'][i] === true){
given that if (formElement['required'][i] comes from the getDataAttribute() function which may return a boolean or other type.
If you are just testing for truthiness, though - and this should be most of the time - simply use if( foo ) or if( ! foo ). Or similarly in a conditional expression: foo ? x : y or !foo ? x : y.
The above was a long-winded way of saying that you should change this:
if (empty_content === false) {
to:
if (!empty_content) {
Your getFormParam() function goes to some work to convert an undefined result to null. There is usually no reason to do this. I don't see any place where that function is called, so I can't advise specifically, but in general you'd be testing for truthiness on something like this, so null and undefined would both be treated as false. Or in cases where you do need to distinguish null/undefined from other values (say, an explicit false), you can easily do it with != null or == null. This is one case where the "looser" comparison performed by == and != is very useful: both null and undefined evaluate the same with these operators.
You asked to ignore coding style, but one little suggestion here: You have a mix of camelCaseNames and names_with_underscores. In JavaScript, camelCaseNames are more idiomatic for function and variable names, with PascalCaseNames for constructor functions. Of course feel free to use underscores where they make more sense, for example if you're writing code that works with database columns in that format you may want your variable names to match the column names.
Hope that helps! Keep up the good work.
Update for your new code
I'm having a bit of trouble following the logic in the code, and I think I know part of the reason. It's a combination of naming conventions and inside-out objects.
First, the name formElement is really confusing. When I see element in JavaScript, I think of either a DOM element (HTMLElement) or an array element. I'm not sure if this formElement represents one or the other or neither.
So I look at the code to figure out what it's doing, and I see it has id:{}, name:{}, ... properties, but the code later treats each of those as an Array and not an Object:
formElement.id[i] = ...
formElement.name[i] = ...
formElement.value[i] = ...
formElement.required[i] = ...
formElement.type[i] = ...
(where i is an integer index)
If that code is right, those should be arrays instead: id:[], name:[], ....
But this is a red flag. When you see yourself creating parallel arrays in JavaScript, you're probably doing it wrong. In most cases you're better off replacing the parallel arrays with a single array of objects. Each of the objects in that array represents a single slice through all your parallel arrays, with a property for each of the previous arrays.
So, this object (where I've made the correction from {} to [] to match its current use):
formElement = { id: [], name: [], value: [], required: [], type: [] };
should be:
formInfo = [];
and then where you have the code that goes:
formElement.id[i] = ...;
formElement.name[i] = ...;
formElement.value[i] = ...;
formElement.required[i] = ...;
formElement.type[i] = ...;
It should be:
var info = {
id: ...,
name: ...,
value: ...,
required: ...,
type: ...
};
formInfo.push( info );
and adjust the rest of the code to suit. For example:
formElement.required[i]
would be:
formInfo[i].required
or even simpler since it's in the same function:
info.required
And note: I'm not saying info and formInfo are great names :-) they are just placeholders so you can think of a better name. The main idea is to create an array of objects instead of a set of parallel arrays.
One last thing and then I'm out of time for now.
That getDataAttribute() function is a complicated little piece of work. You don't need it! It would be simpler would just call the underlying function directly where you need it:
var info = {
...
required: formField.getAttribute('data-required') === 'true',
type: formField.getAttribute('data-type')
};
This also gives you full control of how the attributes are interpreted - as in the === 'true' test above. (This gives you a proper boolean value, so when you test the value later you don't have to use === true on it.)
On a stylistic note, yes, I did hard code the two 'data-xxxx' names right there, and I think that's a better and more clear way to do it.. Don't let your C experience throw you off here. There's no advantage to defining a string "constant" in this particular case, unless it's something that you want to make configurable, which this isn't.
Also, even if you do make a string constant, there's a minor advantage to having the complete 'data-whatever' string instead of just 'whatever'. The reason is that when somebody reads your HTML code, they may see a string in it and search the JS code for that string. But when they search for data-whatever they won't find it if the data- prefix is automagically prepended in the JS code.
Oh, I forgot one last thing. This code:
function Form(){
var args = Array.prototype.slice.call(arguments),
formName = args[0],
callback = args.pop(),
is working way too hard! Just do this instead:
function Form( formName, callback ) {
(and keep the var for the remaining variable declarations of course)
I cannot add comments yet so here is a little tip. I would separate the getFormElements() into smaller private functions. And I would add the errorMsgs to the Form function.
But for a first script in JavaScript, it is very impressive. This is actually the real reason I respond. I think it deserves more upvotes, and I would be very interested in a JS ninja responding to this question.
Good luck!

Jquery in 30 days inquiry

I am currently watching a tutorial video "30 days to learn jQuery".
I have a question about why the tutor in the video returned a variable from a function.
Here's the code:
This is in the HTML file which just binds an event handler to buttons, calls functions, etc.
(function() {
slider.nav.find('button').on('click', function() {
slider.setCurrent( $(this).data('dir') );
slider.transition();
});
})();
and this is the one function I'm interested in (in the js file):
Slider.prototype.setCurrent = function( dir ) {
var pos = this.current;
pos += ( ~~( dir === 'next' ) || -1 );
this.current = ( pos < 0 ) ? this.imgsLen - 1 : pos % this.imgsLen;
return pos; // <== HERE
};
The only thing I want to figure out is why return pos? I tried removing it and the code still worked.
Was it a mistake or is there sound logic to this?
In a nutshell, setCurrent function is called and setCurrent returns a value. But why?
I can't speculate as to why your tutor did that, but a common practice, especially in jQuery, is to overload a function by having the same function be both a setter and getter based on what parameters are passed. An example is below:
function (dir)
{
//If dir was passed as a parameter
if (typeof dir !== "undefined")
{
//Setter code
value = dir;
}
//Getter (always returns value)
return value;
}
There are tons of functions in jQuery that use this, e.g .val, .height, .css('propertyName', [optionallySetValue]), etc.
Let me know if this makes sense, or if you have any questions :)
It's hard to know without seeing the rest of your code, but often functions that set a value on object will return something, even though that is counterintuitive, since their purpose is to set a value, not to get something.
The most common pattern you'll see is to return the object itself. The allows you to chain together multiple setter calls at once:
object.setColor("red").setSize("large");
This is not specifically going on in your case, but the author may have had a similar use in mind, in the sense that he wanted to do 2 things at once: set a value, and get some information about how that value was set.

Variable Dependency with knockoutJS

I'm building an application with KnockoutJS with a component that essentially acts as a sequential spreadsheet. On different lines users may define variables or use them to represent a value.
So for example
x =2
x //2
x = 4
x //4
I have this working in the straightforward case of continuing adding new lines. The output function for each line checks and iterates backwards to see if the variable was ever defined previously. If it was it uses the first example it finds and sets that as the value. This works when initially defining the lines, and also works when you edit a line after a previous line has changed.
However, I would like variables to update if a previous definition of that variable has changed, been removed, or been added. That behavior does not exist right now. I have tried adding my own custom dependency handling code using a map to track the variables, but it badly impacted performance. I would like to tap into Knockouts dependency management to solve this, but I'm not sure of the best way to do so. Here is a brief summary of my code structure, I would be happy to add more detail if needed.
calcFramework is the view-model object I bind to the map. It consists of an observable list of Lines, a varMap, and other unrelated properties and functions
Line is a custom object. The relevant code is below
var Line = function (linenum,currline) {
var self = this;
self.varMap = {};
self.input = ko.observable("");
self.linenum = ko.observable(linenum);
self.lnOutput = ko.computed({
read:function(){
return outputFunction(self,self.input());
},
write:function(){},
owner:self
});
};
function outputFunction(self,input) {
try{
var out = EQParser.parse(input,10,self);
return out.toString();
}
catch(ex){
//error handling
}
}
Line.prototype.getVar = function (varName, notCurrentLine) {
if(typeof varName === "undefined"){
return null;
}
//Actually don't want ones set in the current varMap, only past lines
if(varName in this.varMap && notCurrentLine){
return this.varMap[varName];
}
if (this.linenum() > 0) {
var nextLine = calcFramework.lines()[this.linenum() - 1];
return nextLine.getVar(varName,true);
} else {
//eventually go to global
return calcFramework.varMap[varName];
}
};
Line.prototype.setVar = function(varName,value){
this.varMap[varName] = value;
};
SetVar and getVar are passed to eqParser, which gets the value of the expression, calling those functions as needed if a variable is referenced. So the variable value is not explicitly passed to the function and thus knockout does not view it as a dependency. But I'm not sure how I would pass the variable as a parameter without traversing the list every time.
So my question is, given this setup, what is the best way to track changes to a variable assignment (and/or new assignments) and update the lines that reference that variable, while maintaining good performance.
I recognize my question is lengthy and I have attempted to trim out all unnecessary detail. Thanks for your patience in reading.
I would be tempted to use a publish/subscribe model, using something like Peter Higgins' PubSub jquery plugin
Your overall app would subscribe/listen out for lines publishing an event that they have a variable definition. This would store any variable names in a standard javascript hashtable, along with the value. When a variable found event is published by a line, the app would check through all the known variables, and if it finds that it is a change to an existing variable value, it would publish a variable changed event. All the lines would subscribe to that event. They can then check whether they have a variable matching that name, and update the value accordingly.
Here's some untested code to give you an idea of what I mean:
var app = function()
{
var self = this;
self.variables = {};
$.subscribe('/variableAssigned', function (key, value)
{
// I think that this is the best way of checking that there is a variable
// in the object
if(self.variables.hasOwnProperty(key))
{
if(self.variables[key] !== value)
{
$.publish('/variableChanged', [ key, value ]);
}
}
});
}
In your Line object:
$.subscribe('/variableChanged', function (key, value)
{
// loop through varMap and see if any of them need updating.
});

Categories

Resources