Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Commit

Permalink
Add regex filter, tests, clean up code more. Fixes #66
Browse files Browse the repository at this point in the history
  • Loading branch information
tmcw committed May 8, 2012
1 parent 9960cd2 commit 262ef7e
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 49 deletions.
7 changes: 3 additions & 4 deletions lib/carto/parser.js
Expand Up @@ -438,16 +438,15 @@ carto.Parser = function Parser(env) {
// "milky way" 'he\'s the one!'
//
quoted: function() {
var str;
if (input.charAt(i) !== '"' && input.charAt(i) !== "'") return;

if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
var str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/);
if (str) {
return new tree.Quoted(str[0], str[1] || str[2]);
}
},

comparison: function() {
var str = $(/^=|!=|<=|>=|<|>/);
var str = $(/^=~|=|!=|<=|>=|<|>/);
if (str) {
return str;
}
Expand Down
12 changes: 9 additions & 3 deletions lib/carto/tree/directive.js
Expand Up @@ -25,9 +25,15 @@ tree.Directive.prototype = {
env.frames.shift();
return this;
},
variable: function(name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
find: function() { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
rulesets: function() { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
variable: function(name) {
return tree.Ruleset.prototype.variable.call(this.ruleset, name);
},
find: function() {
return tree.Ruleset.prototype.find.apply(this.ruleset, arguments);
},
rulesets: function() {
return tree.Ruleset.prototype.rulesets.apply(this.ruleset);
}
};

})(require('../tree'));
4 changes: 3 additions & 1 deletion lib/carto/tree/expression.js
@@ -1,6 +1,8 @@
(function(tree) {

tree.Expression = function Expression(value) { this.value = value };
tree.Expression = function Expression(value) {
this.value = value;
};
tree.Expression.prototype = {
eval: function(env) {
if (this.value.length > 1) {
Expand Down
23 changes: 12 additions & 11 deletions lib/carto/tree/filter.js
Expand Up @@ -19,26 +19,27 @@ tree.Filter = function Filter(key, op, val, index, filename) {
this.val = val;
}

if (this.op !== '=' && this.op !== '!=') {
if (ops[this.op][1]) {
this.val = 1 * this.val;
}

this.id = this.key + this.op + this.val;
};


// XML-safe versions of comparators
var opXML = {
'<': '&lt;',
'>': '&gt;',
'=': '=',
'!=': '!=',
'<=': '&lt;=',
'>=': '&gt;='
// xmlsafe, numeric, suffix
var ops = {
'<': [' &lt; ', true],
'>': [' &gt; ', true],
'=': [' = ', false],
'!=': [' != ', false],
'<=': [' &lt;= ', true],
'>=': [' &gt;= ', true],
'=~': ['.match(', false, ')']
};

tree.Filter.prototype.toXML = function(env) {
if (this.op !== '=' && this.op !== '!=' && isNaN(this.val)) {
if (ops[this.op][1] && isNaN(this.val)) {
env.error({
message: 'Cannot use operator "' + this.op + '" with value ' + this.val,
index: this.index,
Expand All @@ -50,7 +51,7 @@ tree.Filter.prototype.toXML = function(env) {
if (this._key) var key = this._key.toString(false);
if (this._val) var val = this._val.toString(this._val.is == 'string');

return '[' + (key || this.key) + '] ' + opXML[this.op] + ' ' + (val || this.val);
return '[' + (key || this.key) + ']' + ops[this.op][0] + '' + (val || this.val) + (ops[this.op][2] || '');
};

tree.Filter.prototype.toString = function() {
Expand Down
45 changes: 31 additions & 14 deletions lib/carto/tree/filterset.js
Expand Up @@ -66,12 +66,14 @@ Object.defineProperty(tree.Filterset.prototype, 'cloneWith', {

// We can add the rules that are already present without going through the
// add function as a Filterset is always in it's simplest canonical form.
for (var id in this)
for (var id in this) {
clone[id] = this[id];
}

// Only add new filters that actually change the filter.
while (id = additions.shift())
while (id = additions.shift()) {
clone.add(id);
}

return clone;
}
Expand All @@ -98,12 +100,10 @@ Object.defineProperty(tree.Filterset.prototype, 'addable', {
case '!=':
if (key + '=' in this) return (this[key + '='].val == value) ? false : null;
if (key + '!=' + value in this) return null;

if (key + '>' in this && this[key + '>'].val >= value) return null;
if (key + '<' in this && this[key + '<'].val <= value) return null;
if (key + '>=' in this && this[key + '>='].val > value) return null;
if (key + '<=' in this && this[key + '<='].val < value) return null;

return true;

case '>':
Expand Down Expand Up @@ -151,27 +151,40 @@ Object.defineProperty(tree.Filterset.prototype, 'add', {

switch (filter.op) {
case '=':
for (var id in this)
if (this[id].key == key)
for (var id in this) {
if (this[id].key == key) {
delete this[id];
}
}
this[key + '='] = filter;
break;

case '!=':
this[key + '!=' + filter.val] = filter;
break;

case '=~':
this[key + '=~' + filter.val] = filter;
break;

case '>':
for (var id in this)
if (this[id].key == key && this[id].val <= filter.val)
// If there are other filters that are also >
// but are less than this one, they don't matter, so
// remove them.
for (var id in this) {
if (this[id].key == key && this[id].val <= filter.val) {
delete this[id];
}
}
this[key + '>'] = filter;
break;

case '>=':
for (var id in this)
if (this[id].key == key && this[id].val < filter.val)
for (var id in this) {
if (this[id].key == key && this[id].val < filter.val) {
delete this[id];
}
}
if (key + '!=' + filter.val in this) {
delete this[key + '!=' + filter.val];
filter.op = '>';
Expand All @@ -183,16 +196,20 @@ Object.defineProperty(tree.Filterset.prototype, 'add', {
break;

case '<':
for (var id in this)
if (this[id].key == key && this[id].val >= filter.val)
for (var id in this) {
if (this[id].key == key && this[id].val >= filter.val) {
delete this[id];
}
}
this[key + '<'] = filter;
break;

case '<=':
for (var id in this)
if (this[id].key == key && this[id].val > filter.val)
for (var id in this) {
if (this[id].key == key && this[id].val > filter.val) {
delete this[id];
}
}
if (key + '!=' + filter.val in this) {
delete this[key + '!=' + filter.val];
filter.op = '<';
Expand Down
12 changes: 6 additions & 6 deletions lib/carto/tree/fontset.js
Expand Up @@ -26,13 +26,13 @@ tree.FontSet = function FontSet(env, fonts) {
};

tree.FontSet.prototype.toXML = function(env) {
return '<FontSet name="'
+ this.name
+ '">\n'
+ this.fonts.map(function(f) {
return '<FontSet name="' +
this.name +
'">\n' +
this.fonts.map(function(f) {
return ' <Font face-name="' + f +'"/>';
}).join('\n')
+ '\n</FontSet>'
}).join('\n') +
'\n</FontSet>';
};

})(require('../tree'));
4 changes: 2 additions & 2 deletions lib/carto/tree/keyword.js
Expand Up @@ -10,8 +10,8 @@ tree.Keyword = function Keyword(value) {
this.is = special[value] ? special[value] : 'keyword';
};
tree.Keyword.prototype = {
eval: function() { return this },
toString: function() { return this.value }
eval: function() { return this; },
toString: function() { return this.value; }
};

})(require('../tree'));
16 changes: 8 additions & 8 deletions lib/carto/tree/zoom.js
Expand Up @@ -4,11 +4,11 @@ var tree = require('../tree');
// and stores them as bit-sequences so that they can be combined,
// inverted, and compared quickly.
tree.Zoom = function(op, value, index) {
value = parseInt(value);
value = parseInt(value, 10);
if (value > tree.Zoom.maxZoom || value < 0) {
throw {
message: 'Only zoom levels between 0 and '
+ tree.Zoom.maxZoom + ' supported.',
message: 'Only zoom levels between 0 and ' +
tree.Zoom.maxZoom + ' supported.',
index: index
};
}
Expand Down Expand Up @@ -81,14 +81,14 @@ tree.Zoom.toXML = function(zoom) {
var start = null, end = null;
for (var i = 0; i <= tree.Zoom.maxZoom; i++) {
if (zoom & (1 << i)) {
if (start == null) start = i;
if (start === null) start = i;
end = i;
}
}
if (start > 0) conditions.push(' <MaxScaleDenominator>'
+ tree.Zoom.ranges[start] + '</MaxScaleDenominator>\n');
if (end < 22) conditions.push(' <MinScaleDenominator>'
+ tree.Zoom.ranges[end + 1] + '</MinScaleDenominator>\n');
if (start > 0) conditions.push(' <MaxScaleDenominator>' +
tree.Zoom.ranges[start] + '</MaxScaleDenominator>\n');
if (end < 22) conditions.push(' <MinScaleDenominator>' +
tree.Zoom.ranges[end + 1] + '</MinScaleDenominator>\n');
}
return conditions;
};
Expand Down
14 changes: 14 additions & 0 deletions test/rendering/regex.mml
@@ -0,0 +1,14 @@
{
"srs": "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over",
"Stylesheet": [
"regex.mss"
],
"Layer": [{
"name": "world",
"srs": "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over",
"Datasource": {
"file": "http://tilemill-data.s3.amazonaws.com/test_data/shape_demo.zip",
"type": "shape"
}
}]
}
5 changes: 5 additions & 0 deletions test/rendering/regex.mss
@@ -0,0 +1,5 @@
#world[ISO =~ "U*"] {
polygon-fill: #FFF;
line-color:#F00;
line-width: 0.5;
}
22 changes: 22 additions & 0 deletions test/rendering/regex.result
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Map[]>
<Map srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over" maximum-extent="-20037508.34,-20037508.34,20037508.34,20037508.34">


<Style name="world" filter-mode="first">
<Rule>
<Filter>([ISO].match('U*'))</Filter>
<PolygonSymbolizer fill="#ffffff" />
<LineSymbolizer stroke="#ff0000" stroke-width="0.5" />
</Rule>
</Style>
<Layer name="world"
srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over">
<StyleName>world</StyleName>
<Datasource>
<Parameter name="file"><![CDATA[[absolute path]]]></Parameter>
<Parameter name="type"><![CDATA[shape]]></Parameter>
</Datasource>
</Layer>

</Map>

0 comments on commit 262ef7e

Please sign in to comment.