Skip to content

Commit 4e1dbeb

Browse files
committed
Refactored expression matching into Expression
1 parent 7a29e01 commit 4e1dbeb

File tree

4 files changed

+107
-96
lines changed

4 files changed

+107
-96
lines changed

lib/environment.js

Lines changed: 3 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
var Expression = require('./expression');
2+
13
var cache = {};
24

35
var Environment = module.exports = function(jsonObject, expression, options) {
@@ -114,71 +116,5 @@ Environment.prototype.slice = function(segment, expression, object, path) {
114116
Environment.prototype.match = function(expression, object, _vname) {
115117
if(object === null) return object;
116118

117-
if(/[>=<]/.test(expression))
118-
return this.compareValue(expression, object);
119-
else if(/[-+*\/]/.test(expression))
120-
return this.computeValue(expression, object);
121-
else if(/\./.test(expression))
122-
return this.getProperty(expression, object);
123-
else
124-
throw new SyntaxError("jsonPath: invalid query syntax: " + expression);
125-
};
126-
127-
Environment.prototype.compareValue = function(expression, object) {
128-
return this.operate(object, expression, '>=<');
129-
};
130-
131-
Environment.prototype.getProperty = function(expression, object) {
132-
var parts = expression.match(/\.([^\s]+)/);
133-
var rhs;
134-
try {
135-
rhs = JSON.parse('"' + parts[1] + '"');
136-
}
137-
catch(e) {
138-
throw new SyntaxError("jsonPath: invalid property name: " + parts[1]);
139-
}
140-
return object[rhs];
141-
};
142-
143-
Environment.prototype.getValue = function(expression) {
144-
try {
145-
return JSON.parse(expression);
146-
}
147-
catch(e) {
148-
throw new SyntaxError("jsonPath: invalid right-hand-side value: " + expression);
149-
}
150-
};
151-
152-
Environment.prototype.computeValue = function(expression, object) {
153-
return this.operate(object, expression, '-+*/');
154-
};
155-
156-
Environment.prototype.operate = function(object, expression, operators) {
157-
var regex = new RegExp("([^\(\)" + operators + "]+)([" + operators + "]+)([^\(\)]+)");
158-
var parts = expression.match(regex);
159-
var lhs = this.getProperty(parts[1], object);
160-
var rhs = this.getValue(parts[3]);
161-
162-
switch(parts[2]) {
163-
case '==':
164-
return lhs == rhs;
165-
case '>=':
166-
return lhs >= rhs;
167-
case '<=':
168-
return lhs <= rhs;
169-
case '>':
170-
return lhs > rhs;
171-
case '<':
172-
return lhs < rhs;
173-
case '-':
174-
return lhs - rhs;
175-
case '+':
176-
return lhs + rhs;
177-
case '*':
178-
return lhs * rhs;
179-
case '/':
180-
return lhs / rhs;
181-
default:
182-
throw new SyntaxError("jsonPath: invalid query syntax: " + expression);
183-
}
119+
return Expression.execute(expression, object);
184120
};

lib/expression.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
var Expression = module.exports = {
2+
execute: function(expression, object) {
3+
if(/[>=<]/.test(expression))
4+
return this.operate(object, expression, '>=<');
5+
else if(/[-+*\/]/.test(expression))
6+
return this.operate(object, expression, '-+*/');
7+
else if(/\./.test(expression))
8+
return this.getProperty(expression, object);
9+
else
10+
throw new SyntaxError("jsonPath: invalid query syntax: " + expression);
11+
},
12+
13+
getProperty: function(expression, object) {
14+
var parts = expression.match(/\.([^\s]+)/);
15+
var rhs;
16+
try {
17+
rhs = JSON.parse('"' + parts[1] + '"');
18+
}
19+
catch(e) {
20+
throw new SyntaxError("jsonPath: invalid property name: " + parts[1]);
21+
}
22+
return object[rhs];
23+
},
24+
25+
getValue: function(expression) {
26+
try {
27+
return JSON.parse(expression);
28+
}
29+
catch(e) {
30+
throw new SyntaxError("jsonPath: invalid right-hand-side value: " + expression);
31+
}
32+
},
33+
34+
operate: function(object, expression, operators) {
35+
var regex = new RegExp("([^\(\)" + operators + "]+)([" + operators + "]+)([^\(\)]+)");
36+
var parts = expression.match(regex);
37+
var lhs = this.getProperty(parts[1], object);
38+
var rhs = this.getValue(parts[3]);
39+
40+
switch(parts[2]) {
41+
case '==':
42+
return lhs == rhs;
43+
case '>=':
44+
return lhs >= rhs;
45+
case '<=':
46+
return lhs <= rhs;
47+
case '>':
48+
return lhs > rhs;
49+
case '<':
50+
return lhs < rhs;
51+
case '-':
52+
return lhs - rhs;
53+
case '+':
54+
return lhs + rhs;
55+
case '*':
56+
return lhs * rhs;
57+
case '/':
58+
return lhs / rhs;
59+
default:
60+
throw new SyntaxError("jsonPath: invalid query syntax: " + expression);
61+
}
62+
},
63+
};

test/environment-test.js

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,16 @@ var assert = require('assert'),
22
vows = require('vows'),
33
Environment = require("../lib/environment");
44

5-
vows.describe('JSONPath').addBatch({
5+
vows.describe('Environment').addBatch({
66
'#match': {
77
topic: new Environment({}, '', {}),
88

9-
'matches (@.length-1)': function(env) {
10-
var obj = [1,2,3];
11-
assert.equal(env.match('(@.length-1)', obj), 2);
12-
},
13-
'matches @.isbn': function(env) {
14-
var obj = { isbn: 'abc123' };
15-
assert.equal(env.match('@.isbn', obj), 'abc123');
16-
},
17-
'matches @.price<10 true': function(env) {
18-
var obj = { price: 5 };
19-
assert.isTrue(env.match('@.price<10', obj));
20-
},
21-
'matches @.price<10 false': function(env) {
22-
var obj = { price: 10 };
23-
assert.isFalse(env.match('@.price<10', obj));
24-
},
25-
'matches @.price==10 true': function(env) {
26-
var obj = { price: 10 };
27-
assert.isTrue(env.match('@.price==10', obj));
28-
},
29-
'matches @.price==10 false': function(env) {
30-
var obj = { price: 11 };
31-
assert.isFalse(env.match('@.price==10', obj));
32-
},
339
'returns null if there is nothing to match against': function(env) {
3410
assert.isNull(env.match('something', null));
3511
},
36-
'throws a syntax error for invalid statements': function(env) {
37-
assert.throws(function() {
38-
env.match('oogabooga', {});
39-
});
12+
'matches the expression against the current object': function(env) {
13+
var obj = { isbn: 'abc123' };
14+
assert.equal(env.match('@.isbn', obj), 'abc123');
4015
}
4116
}
4217
}).export(module);

test/expression-test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
var assert = require('assert'),
2+
vows = require('vows'),
3+
Expression = require("../lib/expression");
4+
5+
vows.describe('Expression').addBatch({
6+
'.execute': {
7+
'matches (@.length-1)': function(env) {
8+
var obj = [1,2,3];
9+
assert.equal(Expression.execute('(@.length-1)', obj), 2);
10+
},
11+
'matches @.isbn': function(env) {
12+
var obj = { isbn: 'abc123' };
13+
assert.equal(Expression.execute('@.isbn', obj), 'abc123');
14+
},
15+
'matches @.price<10 true': function(env) {
16+
var obj = { price: 5 };
17+
assert.isTrue(Expression.execute('@.price<10', obj));
18+
},
19+
'matches @.price<10 false': function(env) {
20+
var obj = { price: 10 };
21+
assert.isFalse(Expression.execute('@.price<10', obj));
22+
},
23+
'matches @.price==10 true': function(env) {
24+
var obj = { price: 10 };
25+
assert.isTrue(Expression.execute('@.price==10', obj));
26+
},
27+
'matches @.price==10 false': function(env) {
28+
var obj = { price: 11 };
29+
assert.isFalse(Expression.execute('@.price==10', obj));
30+
},
31+
'throws a syntax error for invalid statements': function(env) {
32+
assert.throws(function() {
33+
Expression.execute('oogabooga', {});
34+
});
35+
}
36+
}
37+
}).export(module);

0 commit comments

Comments
 (0)