Vitaly Puzrin
10 years ago
6 changed files with 216 additions and 119 deletions
@ -0,0 +1,160 @@ |
|||
// Ruler is helper class to build responsibility chains from parse rules.
|
|||
// It allows:
|
|||
//
|
|||
// - easy stack rules chains
|
|||
// - getting main chain and named chains content (as arrays of functions)
|
|||
|
|||
'use strict'; |
|||
|
|||
|
|||
////////////////////////////////////////////////////////////////////////////////
|
|||
// helpers
|
|||
|
|||
function _class(obj) { return Object.prototype.toString.call(obj); } |
|||
function isFunction(obj) { return _class(obj) === '[object Function]'; } |
|||
|
|||
function functionName(fn) { |
|||
var ret = fn.toString(); |
|||
ret = ret.substr('function '.length); |
|||
ret = ret.substr(0, ret.indexOf('(')); |
|||
return ret; |
|||
} |
|||
|
|||
|
|||
////////////////////////////////////////////////////////////////////////////////
|
|||
|
|||
function Ruler(compileFn) { |
|||
this.compile = compileFn; // callback to call after each change
|
|||
|
|||
// List of added rules. Each element is:
|
|||
//
|
|||
// {
|
|||
// name: XXX,
|
|||
// fn: Function(),
|
|||
// alt: [ name2, name3 ]
|
|||
// }
|
|||
//
|
|||
this.rules = []; |
|||
} |
|||
|
|||
|
|||
// Find rule index by name
|
|||
//
|
|||
Ruler.prototype.find = function (name) { |
|||
for (var i = 0; i < this.rules.length; i++) { |
|||
if (this.rules[i].name === name) { |
|||
return i; |
|||
} |
|||
} |
|||
return -1; |
|||
}; |
|||
|
|||
|
|||
// Replace/delete parser function
|
|||
//
|
|||
Ruler.prototype.at = function (name, fn, altNames) { |
|||
var index = this.find(name); |
|||
|
|||
if (index === -1) { |
|||
throw new Error('Parser rule not found: ' + name); |
|||
} |
|||
|
|||
if (isFunction(fn)) { |
|||
this.rules[index].fn = fn; |
|||
if (altNames) { |
|||
this.rules[index].alt = altNames; |
|||
} |
|||
} else { |
|||
this.rules = this.rules.slice(0, index).concat(this.rules.slice(index + 1)); |
|||
} |
|||
|
|||
this.compile(); |
|||
}; |
|||
|
|||
|
|||
// Add function to parser chain before one with given name.
|
|||
// Or add to start, if name not defined
|
|||
//
|
|||
Ruler.prototype.before = function (name, fn, altNames) { |
|||
var index; |
|||
|
|||
if (isFunction(name)) { |
|||
altNames = fn; |
|||
fn = name; |
|||
name = ''; |
|||
} |
|||
|
|||
if (!name) { |
|||
this.rules.unshift({ |
|||
name: functionName(fn), |
|||
fn: fn, |
|||
alt: altNames || [] |
|||
}); |
|||
|
|||
} else { |
|||
|
|||
index = this.find(name); |
|||
if (index === -1) { |
|||
throw new Error('Parser rule not found: ' + name); |
|||
} |
|||
this.rules.splice(index, 0, fn); |
|||
} |
|||
|
|||
this.compile(); |
|||
}; |
|||
|
|||
|
|||
// Add function to parser chain after one with given name.
|
|||
// Or add to end, if name not defined
|
|||
//
|
|||
Ruler.prototype.after = function (name, fn, altNames) { |
|||
var index; |
|||
|
|||
if (isFunction(name)) { |
|||
altNames = fn; |
|||
fn = name; |
|||
name = ''; |
|||
} |
|||
|
|||
if (!name) { |
|||
this.rules.push({ |
|||
name: functionName(fn), |
|||
fn: fn, |
|||
alt: altNames || [] |
|||
}); |
|||
|
|||
} else { |
|||
|
|||
index = this.find(name); |
|||
if (index === -1) { |
|||
throw new Error('Parser rule not found: ' + name); |
|||
} |
|||
this.rules.splice(index + 1, 0, fn); |
|||
} |
|||
|
|||
this.compile(); |
|||
}; |
|||
|
|||
|
|||
// Get rules list as array of functions. By default returns main chain
|
|||
//
|
|||
Ruler.prototype.getRules = function (chainName) { |
|||
var result = []; |
|||
|
|||
if (!chainName) { |
|||
this.rules.forEach(function (rule) { |
|||
result.push(rule.fn); |
|||
}); |
|||
return result; |
|||
} |
|||
|
|||
this.rules.forEach(function (rule) { |
|||
if (rule.alt.indexOf(chainName) >= 0) { |
|||
result.push(rule.fn); |
|||
} |
|||
}); |
|||
return result; |
|||
}; |
|||
|
|||
|
|||
module.exports = Ruler; |
Loading…
Reference in new issue